chatlab-cli 0.28.0 → 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.
Files changed (71) hide show
  1. package/dist/{chat-command-7WL5NMZ6.mjs → chat-command-ISJ2DC7R.mjs} +5 -5
  2. package/dist/{chunk-VASK54KT.mjs → chunk-3QBVO4J7.mjs} +2 -2
  3. package/dist/chunk-5FGB42EQ.mjs +7 -0
  4. package/dist/{chunk-YQ2FJGBT.mjs → chunk-AB6TAXTQ.mjs} +83 -46
  5. package/dist/chunk-AB6TAXTQ.mjs.map +1 -0
  6. package/dist/{chunk-XNU5X7EV.mjs → chunk-ERAAWLEF.mjs} +3 -3
  7. package/dist/{chunk-GFRG7TZQ.mjs → chunk-GHTGFM6O.mjs} +14 -14
  8. package/dist/{chunk-WGS33EWH.mjs → chunk-NJB2NNB2.mjs} +2 -2
  9. package/dist/{chunk-ZSFVX6FM.mjs → chunk-T7IETWHN.mjs} +6 -22
  10. package/dist/chunk-T7IETWHN.mjs.map +1 -0
  11. package/dist/chunk-YBS3YQB6.mjs +1336 -0
  12. package/dist/chunk-YBS3YQB6.mjs.map +1 -0
  13. package/dist/{chunk-55WR6WKW.mjs → chunk-ZVDOFWL7.mjs} +13327 -4696
  14. package/dist/chunk-ZVDOFWL7.mjs.map +1 -0
  15. package/dist/cli.mjs +4 -4
  16. package/dist/{http-C2FBHNZG.mjs → http-MBILV37U.mjs} +9 -9
  17. package/dist/{import-ED6JCPSJ.mjs → import-EYV3GXHE.mjs} +5 -12
  18. package/dist/index.mjs +9 -9
  19. package/dist/{mcp-5JIBER4M.mjs → mcp-H55AEXU5.mjs} +5 -5
  20. package/dist/semantic-index-worker.mjs +1 -1
  21. package/dist/{src-WBNM42SL.mjs → src-36ZIR65K.mjs} +30 -28
  22. package/dist/{stream-import-37U3SROO.mjs → stream-import-YZMZ56B5.mjs} +4 -4
  23. package/dist/stream-import-YZMZ56B5.mjs.map +1 -0
  24. package/dist/undici-ZSXBT7EA.mjs +18389 -0
  25. package/dist/undici-ZSXBT7EA.mjs.map +1 -0
  26. package/dist/{worker-runtime-6DGYL4TF.mjs → worker-runtime-YDYS2C6T.mjs} +9 -5
  27. package/dist/worker-runtime-YDYS2C6T.mjs.map +1 -0
  28. package/dist-web/assets/{DebugToolsPanel.vue_vue_type_script_setup_true_lang-CCz0Syxo.js → DebugToolsPanel.vue_vue_type_script_setup_true_lang-Do3x4aL3.js} +5 -5
  29. package/dist-web/assets/{MessageExportModal-Dd6R-cX_.js → MessageExportModal-rijqUusq.js} +1 -1
  30. package/dist-web/assets/{electron-DjminAKK.js → electron-DWDCqx_d.js} +1 -1
  31. package/dist-web/assets/{fetch-B_kLRm6-.js → fetch-29ZBtGV0.js} +1 -1
  32. package/dist-web/assets/{fetch-DFCYOQe5.js → fetch-BAxKmbKF.js} +1 -1
  33. package/dist-web/assets/{fetch-srCJzcWc.js → fetch-BYczbT4C.js} +1 -1
  34. package/dist-web/assets/{fetch-DOhCQ5J8.js → fetch-BcxrU2mr.js} +1 -1
  35. package/dist-web/assets/{fetch-DV8A1dGB.js → fetch-Bh1fo3Df.js} +1 -1
  36. package/dist-web/assets/{fetch-Wad5mWVH.js → fetch-C3yhWO2S.js} +1 -1
  37. package/dist-web/assets/{fetch-CURbMNJV.js → fetch-Da_TBxrX.js} +1 -1
  38. package/dist-web/assets/{fetch-uM3erGZm.js → fetch-DyD8wDhb.js} +1 -1
  39. package/dist-web/assets/{fetch-Cle6QKmL.js → fetch-TCeykOkO.js} +1 -1
  40. package/dist-web/assets/{fetch-r83wdzHy.js → fetch-tIIVdXSv.js} +1 -1
  41. package/dist-web/assets/index-BzjLqlW_.js +173 -0
  42. package/dist-web/assets/{index-BpszRZ8V.js → index-C74qEDFh.js} +3 -3
  43. package/dist-web/assets/index-CM6xNPFp.css +1 -0
  44. package/dist-web/assets/index-CgK2LLIF.js +12 -0
  45. package/dist-web/assets/{index-hOsKRsp6.js → index-CjkOvM3N.js} +2 -2
  46. package/dist-web/assets/{index-BIvLzdwg.js → index-Dno7CADA.js} +1 -1
  47. package/dist-web/assets/{index-tkbEq8av.js → index-fbWrQpgH.js} +1 -1
  48. package/dist-web/assets/{web-D27K6zSX.js → web-H3XLx159.js} +1 -1
  49. package/dist-web/index.html +2 -2
  50. package/package.json +1 -1
  51. package/dist/chunk-55WR6WKW.mjs.map +0 -1
  52. package/dist/chunk-GPF34WXV.mjs +0 -9573
  53. package/dist/chunk-GPF34WXV.mjs.map +0 -1
  54. package/dist/chunk-YQ2FJGBT.mjs.map +0 -1
  55. package/dist/chunk-YZDEZ6UI.mjs +0 -389
  56. package/dist/chunk-YZDEZ6UI.mjs.map +0 -1
  57. package/dist/chunk-ZSFVX6FM.mjs.map +0 -1
  58. package/dist/worker-runtime-6DGYL4TF.mjs.map +0 -1
  59. package/dist-web/assets/index-7E5GSvR2.css +0 -1
  60. package/dist-web/assets/index-BCRHSc1k.js +0 -173
  61. package/dist-web/assets/index-D5UgZUpS.js +0 -12
  62. /package/dist/{chat-command-7WL5NMZ6.mjs.map → chat-command-ISJ2DC7R.mjs.map} +0 -0
  63. /package/dist/{chunk-VASK54KT.mjs.map → chunk-3QBVO4J7.mjs.map} +0 -0
  64. /package/dist/{http-C2FBHNZG.mjs.map → chunk-5FGB42EQ.mjs.map} +0 -0
  65. /package/dist/{chunk-XNU5X7EV.mjs.map → chunk-ERAAWLEF.mjs.map} +0 -0
  66. /package/dist/{chunk-GFRG7TZQ.mjs.map → chunk-GHTGFM6O.mjs.map} +0 -0
  67. /package/dist/{chunk-WGS33EWH.mjs.map → chunk-NJB2NNB2.mjs.map} +0 -0
  68. /package/dist/{import-ED6JCPSJ.mjs.map → http-MBILV37U.mjs.map} +0 -0
  69. /package/dist/{src-WBNM42SL.mjs.map → import-EYV3GXHE.mjs.map} +0 -0
  70. /package/dist/{mcp-5JIBER4M.mjs.map → mcp-H55AEXU5.mjs.map} +0 -0
  71. /package/dist/{stream-import-37U3SROO.mjs.map → src-36ZIR65K.mjs.map} +0 -0
@@ -0,0 +1,1336 @@
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
+ import {
8
+ BGE_BASE_PROFILE,
9
+ CHUNKER_VERSION,
10
+ CHUNK_VECTOR_INDEX_INDEXES,
11
+ CHUNK_VECTOR_INDEX_TABLE,
12
+ DEFAULT_CHUNKER_CONFIG,
13
+ DESENSITIZE_RULES_SCHEMA_VERSION,
14
+ EMBEDDING_INDEX_SCHEMA,
15
+ EmbeddingIndexStore,
16
+ LocalEmbeddingProvider,
17
+ MEANINGFUL_POS_TAGS,
18
+ OpenAICompatibleEmbeddingProvider,
19
+ QWEN3_PROFILE,
20
+ SEARCH_MAX_RESULTS_DEFAULT,
21
+ SEARCH_MAX_RESULTS_MAX,
22
+ SEARCH_MAX_RESULTS_MIN,
23
+ SEMANTIC_INDEX_AUTH_PROFILE,
24
+ SEMANTIC_INDEX_CONFIG_FILE,
25
+ SEMANTIC_INDEX_CONFIG_VERSION,
26
+ SEMANTIC_INDEX_DB_FILE,
27
+ SEMANTIC_INDEX_SESSION_TABLE,
28
+ STRATEGY_ID,
29
+ SemanticIndexConfigStore,
30
+ SemanticIndexJobQueue,
31
+ SemanticIndexService,
32
+ SemanticIndexStateStore,
33
+ StaticPathProvider,
34
+ applyQueryInstruction,
35
+ assembleEvidence,
36
+ chunkMessages,
37
+ clampSearchMaxResults,
38
+ clampTextChars,
39
+ composeChunkId,
40
+ computeChunkerConfigHash,
41
+ computeDbPathHash,
42
+ createChatDbFtsSearcher,
43
+ createChatDbMessageRangeReader,
44
+ createChatDbMessageSource,
45
+ createEmbedder,
46
+ createSemanticIndexService,
47
+ defaultSemanticIndexConfig,
48
+ deriveParentId,
49
+ detectConflictsInMessages,
50
+ estimateTokens,
51
+ extractFtsKeywords,
52
+ formatEvidenceMessages,
53
+ generateMessageKey,
54
+ getCache,
55
+ getCollidingPlatformIds,
56
+ getJieba,
57
+ getLocalProfileByModelId,
58
+ getLocalProfilesForLocale,
59
+ hybridSearch,
60
+ isKeylessSemanticIndexApiBaseUrl,
61
+ isSemanticIndexConfigured,
62
+ isSemanticVoid,
63
+ isStopword,
64
+ loadConfig,
65
+ mergeMembers,
66
+ migrateFromElectronIfNeeded,
67
+ normalizePlatformId,
68
+ parseParentBounds,
69
+ persistSemanticIndexConfig,
70
+ reciprocalRankFusion,
71
+ resolveApiKey,
72
+ resolveModelId,
73
+ resolveSemanticIndexApiKeySet,
74
+ runWarmup,
75
+ setCache,
76
+ snapshotPathProvider,
77
+ vecTableName,
78
+ vecTableSchema,
79
+ writeConfigField
80
+ } from "./chunk-ZVDOFWL7.mjs";
81
+ import {
82
+ __export
83
+ } from "./chunk-GFHSSCCR.mjs";
84
+
85
+ // ../../packages/node-runtime/src/node-path-provider.ts
86
+ import * as fs2 from "fs";
87
+ import * as os from "os";
88
+ import * as path2 from "path";
89
+
90
+ // ../../packages/node-runtime/src/data-dir-switch.ts
91
+ import * as fs from "fs";
92
+ import * as path from "path";
93
+ var CHATLAB_MARKER_FILE = ".chatlab";
94
+ var USER_DATA_REQUIRED_DIRS = ["databases"];
95
+ var PENDING_MIGRATION_FILE = "data-dir-migration.json";
96
+ var DANGEROUS_PATHS = [
97
+ "C:\\Windows",
98
+ "C:\\Program Files",
99
+ "C:\\Program Files (x86)",
100
+ "C:\\ProgramData",
101
+ "/usr",
102
+ "/etc",
103
+ "/bin",
104
+ "/sbin",
105
+ "/lib",
106
+ "/var",
107
+ "/boot",
108
+ "/root",
109
+ "/System",
110
+ "/Library"
111
+ ];
112
+ function normalizePathForCompare(input) {
113
+ const resolved = path.resolve(input);
114
+ const normalized = path.normalize(resolved);
115
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
116
+ }
117
+ function isSubPath(parent, child) {
118
+ const parentPath = normalizePathForCompare(parent);
119
+ const childPath = normalizePathForCompare(child);
120
+ if (parentPath === childPath) return false;
121
+ return childPath.startsWith(`${parentPath}${path.sep}`);
122
+ }
123
+ function isPathSafe(targetPath) {
124
+ const normalizedTarget = targetPath.toLowerCase().replace(/\//g, "\\");
125
+ for (const dangerous of DANGEROUS_PATHS) {
126
+ const normalizedDangerous = dangerous.toLowerCase().replace(/\//g, "\\");
127
+ if (normalizedTarget.startsWith(normalizedDangerous)) {
128
+ return false;
129
+ }
130
+ }
131
+ return true;
132
+ }
133
+ function ensureDir(dirPath) {
134
+ if (!fs.existsSync(dirPath)) {
135
+ fs.mkdirSync(dirPath, { recursive: true });
136
+ }
137
+ }
138
+ function hasChatLabUserDataStructure(entries) {
139
+ return entries.includes(CHATLAB_MARKER_FILE) && USER_DATA_REQUIRED_DIRS.every((dir) => entries.includes(dir));
140
+ }
141
+ function hasChatLabDatabaseFiles(dirPath, entries) {
142
+ const dirEntries = entries ?? fs.readdirSync(dirPath);
143
+ if (!dirEntries.includes("databases")) return false;
144
+ const dbDir = path.join(dirPath, "databases");
145
+ try {
146
+ return fs.existsSync(dbDir) && fs.readdirSync(dbDir).some((file) => file.endsWith(".db"));
147
+ } catch {
148
+ return false;
149
+ }
150
+ }
151
+ function isExistingUserDataDir(dirPath) {
152
+ if (!fs.existsSync(dirPath)) return false;
153
+ try {
154
+ const entries = fs.readdirSync(dirPath);
155
+ return hasChatLabUserDataStructure(entries) || hasChatLabDatabaseFiles(dirPath, entries);
156
+ } catch {
157
+ return false;
158
+ }
159
+ }
160
+ function isUserDataDirSafeToUse(dirPath) {
161
+ if (!fs.existsSync(dirPath)) return true;
162
+ try {
163
+ const entries = fs.readdirSync(dirPath);
164
+ if (entries.length === 0) return true;
165
+ return hasChatLabUserDataStructure(entries) || hasChatLabDatabaseFiles(dirPath, entries);
166
+ } catch {
167
+ return false;
168
+ }
169
+ }
170
+ function isDirectoryEmptyOrMissing(dirPath) {
171
+ if (!fs.existsSync(dirPath)) return true;
172
+ try {
173
+ return fs.readdirSync(dirPath).length === 0;
174
+ } catch {
175
+ return false;
176
+ }
177
+ }
178
+ function copyDirMerge(src, dest, mkdir = ensureDir, stats = { copied: 0, skipped: 0, errors: [] }) {
179
+ if (!fs.existsSync(src)) return stats;
180
+ try {
181
+ mkdir(dest);
182
+ const entries = fs.readdirSync(src, { withFileTypes: true });
183
+ for (const entry of entries) {
184
+ const srcPath = path.join(src, entry.name);
185
+ const destPath = path.join(dest, entry.name);
186
+ try {
187
+ if (entry.isDirectory()) {
188
+ copyDirMerge(srcPath, destPath, mkdir, stats);
189
+ } else if (!fs.existsSync(destPath)) {
190
+ fs.copyFileSync(srcPath, destPath);
191
+ stats.copied++;
192
+ } else {
193
+ stats.skipped++;
194
+ }
195
+ } catch (error) {
196
+ stats.errors.push(`\u590D\u5236\u5931\u8D25: ${srcPath} -> ${error instanceof Error ? error.message : String(error)}`);
197
+ }
198
+ }
199
+ } catch (error) {
200
+ stats.errors.push(`\u8BFB\u53D6\u76EE\u5F55\u5931\u8D25: ${src} -> ${error instanceof Error ? error.message : String(error)}`);
201
+ }
202
+ return stats;
203
+ }
204
+ function createPendingDataDirMigration(input) {
205
+ return {
206
+ from: input.from,
207
+ to: input.to,
208
+ migrate: input.migrate,
209
+ deleteSourceOnSuccess: input.migrate && input.targetWasEmpty,
210
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
211
+ };
212
+ }
213
+ function runPendingDataDirMigration(pending, deps) {
214
+ const copy = deps.copyDirMerge ?? copyDirMerge;
215
+ const mkdir = deps.ensureDir ?? ensureDir;
216
+ let stats = { copied: 0, skipped: 0, errors: [] };
217
+ if (pending.migrate && path.resolve(pending.from) !== path.resolve(pending.to)) {
218
+ if (!fs.existsSync(pending.from)) {
219
+ return {
220
+ success: false,
221
+ from: pending.from,
222
+ to: pending.to,
223
+ copied: 0,
224
+ skipped: 0,
225
+ errors: [`\u6E90\u6570\u636E\u76EE\u5F55\u4E0D\u5B58\u5728: ${pending.from}`]
226
+ };
227
+ }
228
+ stats = copy(pending.from, pending.to, mkdir);
229
+ deps.log?.(
230
+ `\u6570\u636E\u76EE\u5F55\u8FC1\u79FB\u5B8C\u6210: \u4ECE ${pending.from} \u5230 ${pending.to}\uFF0C\u590D\u5236 ${stats.copied} \u9879\uFF0C\u8DF3\u8FC7 ${stats.skipped} \u9879\uFF0C\u9519\u8BEF ${stats.errors.length} \u9879`
231
+ );
232
+ if (stats.errors.length > 0) {
233
+ return {
234
+ success: false,
235
+ from: pending.from,
236
+ to: pending.to,
237
+ copied: stats.copied,
238
+ skipped: stats.skipped,
239
+ errors: stats.errors
240
+ };
241
+ }
242
+ } else {
243
+ mkdir(pending.to);
244
+ }
245
+ deps.writeUserDataDir(pending.to);
246
+ deps.clearPendingMigration();
247
+ if (pending.deleteSourceOnSuccess && path.resolve(pending.from) !== path.resolve(pending.to)) {
248
+ deps.markPendingDeleteDir?.(pending.from);
249
+ }
250
+ return {
251
+ success: true,
252
+ from: pending.from,
253
+ to: pending.to,
254
+ copied: stats.copied,
255
+ skipped: stats.skipped,
256
+ errors: []
257
+ };
258
+ }
259
+ function getPendingMigrationPath(systemDir) {
260
+ return path.join(systemDir, "settings", PENDING_MIGRATION_FILE);
261
+ }
262
+ function getPendingNodeDataDirMigration(systemDir) {
263
+ const filePath = getPendingMigrationPath(systemDir);
264
+ if (!fs.existsSync(filePath)) return null;
265
+ try {
266
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8"));
267
+ if (!parsed.from || !parsed.to || typeof parsed.migrate !== "boolean") return null;
268
+ return parsed;
269
+ } catch {
270
+ return null;
271
+ }
272
+ }
273
+ function clearPendingNodeDataDirMigration(systemDir) {
274
+ const filePath = getPendingMigrationPath(systemDir);
275
+ if (fs.existsSync(filePath)) {
276
+ fs.unlinkSync(filePath);
277
+ }
278
+ }
279
+ function deleteOldUserDataDirIfSafe(dirPath, currentDir, removeDir) {
280
+ if (path.resolve(dirPath) === path.resolve(currentDir)) return false;
281
+ if (!isPathSafe(dirPath)) return false;
282
+ if (!fs.existsSync(dirPath)) return false;
283
+ if (!isExistingUserDataDir(dirPath)) return false;
284
+ const remove = removeDir ?? ((dir) => fs.rmSync(dir, { recursive: true, force: true }));
285
+ remove(dirPath);
286
+ return true;
287
+ }
288
+ function writePendingNodeDataDirMigration(systemDir, pending) {
289
+ const filePath = getPendingMigrationPath(systemDir);
290
+ ensureDir(path.dirname(filePath));
291
+ fs.writeFileSync(filePath, JSON.stringify(pending, null, 2), "utf-8");
292
+ }
293
+ function createNodeDataDirSwitch(input) {
294
+ if (input.envDataDir) {
295
+ return { success: false, error: "CHATLAB_DATA_DIR is set, data directory cannot be changed from Web UI" };
296
+ }
297
+ const newDir = (input.targetDir?.trim() || input.defaultDir || "").trim();
298
+ if (!newDir) return { success: false, error: "Data directory is required" };
299
+ if (!path.isAbsolute(newDir)) return { success: false, error: "Data directory must be an absolute path" };
300
+ if (!isPathSafe(newDir)) return { success: false, error: "System directories cannot be used as data directory" };
301
+ const migrate = input.migrate !== false;
302
+ if (migrate && path.resolve(input.currentDir) !== path.resolve(newDir) && isSubPath(input.currentDir, newDir)) {
303
+ return { success: false, error: "Target directory cannot be inside current data directory" };
304
+ }
305
+ if (!isUserDataDirSafeToUse(newDir)) {
306
+ return { success: false, error: "Target directory is not empty and is not a ChatLab data directory" };
307
+ }
308
+ if (path.resolve(input.currentDir) === path.resolve(newDir)) {
309
+ clearPendingNodeDataDirMigration(input.systemDir);
310
+ return { success: true, from: input.currentDir, to: newDir, requiresRelaunch: false };
311
+ }
312
+ const pending = createPendingDataDirMigration({
313
+ from: input.currentDir,
314
+ to: newDir,
315
+ migrate,
316
+ targetWasEmpty: isDirectoryEmptyOrMissing(newDir)
317
+ });
318
+ writePendingNodeDataDirMigration(input.systemDir, pending);
319
+ return { success: true, from: input.currentDir, to: newDir, requiresRelaunch: true };
320
+ }
321
+ function applyPendingNodeDataDirMigration(systemDir, deps = {}) {
322
+ const pending = getPendingNodeDataDirMigration(systemDir);
323
+ if (!pending) return { success: true, skipped: true };
324
+ const writeConfig = deps.writeConfigField ?? writeConfigField;
325
+ const result = runPendingDataDirMigration(pending, {
326
+ writeUserDataDir(dir) {
327
+ writeConfig("data", "user_data_dir", dir);
328
+ writeConfig("data", "electron_migration_done", true);
329
+ },
330
+ clearPendingMigration() {
331
+ clearPendingNodeDataDirMigration(systemDir);
332
+ },
333
+ markPendingDeleteDir(dir) {
334
+ deleteOldUserDataDirIfSafe(dir, pending.to, deps.removeDir);
335
+ }
336
+ });
337
+ if (!result.success) {
338
+ return { success: false, error: result.errors.join("; ") || "Data directory migration failed" };
339
+ }
340
+ return { success: true };
341
+ }
342
+
343
+ // ../../packages/node-runtime/src/node-path-provider.ts
344
+ var SYSTEM_DIR = path2.join(os.homedir(), ".chatlab");
345
+ var _pendingElectronDataWarning = false;
346
+ function hasPendingElectronDataWarning() {
347
+ return _pendingElectronDataWarning;
348
+ }
349
+ function applyPendingNodeDataDirMigrationIfNeeded() {
350
+ if (process.env.CHATLAB_DATA_DIR) return { success: true, skipped: true };
351
+ return applyPendingNodeDataDirMigration(SYSTEM_DIR);
352
+ }
353
+ var NodePathProvider = class {
354
+ systemDir;
355
+ userDataDir;
356
+ constructor(userDataDir) {
357
+ this.systemDir = SYSTEM_DIR;
358
+ this.userDataDir = userDataDir || resolveUserDataDir();
359
+ }
360
+ getSystemDir() {
361
+ return this.systemDir;
362
+ }
363
+ getUserDataDir() {
364
+ return this.userDataDir;
365
+ }
366
+ getDatabaseDir() {
367
+ return path2.join(this.userDataDir, "databases");
368
+ }
369
+ getVectorDir() {
370
+ return path2.join(this.userDataDir, "vector");
371
+ }
372
+ getAiDataDir() {
373
+ return path2.join(this.systemDir, "ai");
374
+ }
375
+ getSettingsDir() {
376
+ return path2.join(this.systemDir, "settings");
377
+ }
378
+ getCacheDir() {
379
+ return path2.join(this.systemDir, "cache");
380
+ }
381
+ getTempDir() {
382
+ return path2.join(this.systemDir, "temp");
383
+ }
384
+ getLogsDir() {
385
+ return path2.join(this.systemDir, "logs");
386
+ }
387
+ getDownloadsDir() {
388
+ return path2.join(os.homedir(), "Downloads");
389
+ }
390
+ /**
391
+ * 确保系统目录和用户数据目录都存在
392
+ */
393
+ ensureAllDirs() {
394
+ const dirs = [
395
+ this.systemDir,
396
+ this.userDataDir,
397
+ this.getDatabaseDir(),
398
+ this.getVectorDir(),
399
+ this.getAiDataDir(),
400
+ this.getSettingsDir(),
401
+ this.getCacheDir(),
402
+ this.getTempDir(),
403
+ this.getLogsDir()
404
+ ];
405
+ for (const dir of dirs) {
406
+ if (!fs2.existsSync(dir)) {
407
+ fs2.mkdirSync(dir, { recursive: true });
408
+ }
409
+ }
410
+ const markerPath = path2.join(this.userDataDir, ".chatlab");
411
+ if (!fs2.existsSync(markerPath)) {
412
+ fs2.writeFileSync(markerPath, "ChatLab Data Directory", "utf-8");
413
+ }
414
+ }
415
+ };
416
+ function resolveUserDataDir() {
417
+ const envDir = process.env.CHATLAB_DATA_DIR;
418
+ if (envDir) {
419
+ return expandHome(envDir);
420
+ }
421
+ const config = loadConfig();
422
+ if (config.data.user_data_dir) {
423
+ return expandHome(config.data.user_data_dir);
424
+ }
425
+ const result = migrateFromElectronIfNeeded(SYSTEM_DIR);
426
+ if (result.migrated && result.userDataDir) {
427
+ return result.userDataDir;
428
+ }
429
+ const defaultDir = getDefaultNodeUserDataDir();
430
+ if (result.electronDetected) {
431
+ _pendingElectronDataWarning = true;
432
+ return defaultDir;
433
+ }
434
+ writeConfigField("data", "user_data_dir", defaultDir);
435
+ return defaultDir;
436
+ }
437
+ function getDefaultNodeUserDataDir() {
438
+ return path2.join(os.homedir(), ".chatlab", "data");
439
+ }
440
+ function getSystemLogsDir() {
441
+ return path2.join(SYSTEM_DIR, "logs");
442
+ }
443
+ function expandHome(filePath) {
444
+ if (filePath.startsWith("~/") || filePath === "~") {
445
+ return path2.join(os.homedir(), filePath.slice(1));
446
+ }
447
+ return filePath;
448
+ }
449
+
450
+ // ../../packages/node-runtime/src/jieba-nlp-provider.ts
451
+ function createJiebaNlpProvider(dictType = "default") {
452
+ return {
453
+ tag(text) {
454
+ return getJieba(dictType).tag(text);
455
+ },
456
+ isStopword,
457
+ meaningfulPosTags: MEANINGFUL_POS_TAGS
458
+ };
459
+ }
460
+
461
+ // ../../packages/node-runtime/src/cache/analytics-cache.ts
462
+ import * as fs3 from "fs";
463
+ function getDbFileVersion(dbPath) {
464
+ const parts = [];
465
+ for (const p of [dbPath, `${dbPath}-wal`]) {
466
+ try {
467
+ const st = fs3.statSync(p);
468
+ parts.push(`${Math.floor(st.mtimeMs)}:${st.size}`);
469
+ } catch {
470
+ parts.push("-");
471
+ }
472
+ }
473
+ return parts.join("|");
474
+ }
475
+ function getOrComputeAnalysisCache(sessionId, key, queryCacheDir, version, compute) {
476
+ const cached = getCache(sessionId, key, queryCacheDir);
477
+ if (cached && cached.v === version) {
478
+ return cached.data;
479
+ }
480
+ const data = compute();
481
+ setCache(sessionId, key, { v: version, data }, queryCacheDir);
482
+ return data;
483
+ }
484
+
485
+ // ../../packages/node-runtime/src/preferences.ts
486
+ import * as fs4 from "fs";
487
+ import * as path3 from "path";
488
+ var DEFAULTS = {
489
+ pinnedSessionIds: [],
490
+ aiPreprocessConfig: {
491
+ dataCleaning: true,
492
+ mergeConsecutive: true,
493
+ mergeWindowSeconds: 180,
494
+ blacklistKeywords: [],
495
+ denoise: true,
496
+ desensitize: true,
497
+ desensitizeRulesSchemaVersion: DESENSITIZE_RULES_SCHEMA_VERSION,
498
+ desensitizeBuiltinRuleOverrides: {},
499
+ desensitizeRules: [],
500
+ anonymizeNames: false
501
+ },
502
+ aiGlobalSettings: {
503
+ maxMessagesPerRequest: 1e3,
504
+ exportFormat: "markdown",
505
+ sqlExportFormat: "csv",
506
+ enableAutoSkill: true,
507
+ chartAutoMode: "suggest",
508
+ searchContextBefore: 2,
509
+ searchContextAfter: 2,
510
+ contextCompression: {
511
+ enabled: true,
512
+ tokenThresholdPercent: 75,
513
+ bufferSizePercent: 20,
514
+ maxToolResultPercent: 50
515
+ }
516
+ },
517
+ customKeywordTemplates: [],
518
+ deletedPresetTemplateIds: [],
519
+ wordFilter: {
520
+ schemes: [],
521
+ defaultSchemeId: null,
522
+ sessionSchemeOverrides: {}
523
+ },
524
+ filterHistory: [],
525
+ thinkingLevels: {},
526
+ ownerProfilesByPlatform: {},
527
+ ownerPromptDismissedSessionIds: []
528
+ };
529
+ var PreferencesManager = class {
530
+ filePath;
531
+ cache = null;
532
+ constructor(systemDir) {
533
+ this.filePath = path3.join(systemDir, "preferences.json");
534
+ }
535
+ load() {
536
+ if (this.cache) return this.cache;
537
+ try {
538
+ if (fs4.existsSync(this.filePath)) {
539
+ const raw = fs4.readFileSync(this.filePath, "utf-8");
540
+ const parsed = JSON.parse(raw);
541
+ const migrated = this.migrateLegacyDesensitizeRules(parsed, raw);
542
+ this.cache = this.mergeDefaults(migrated.preferences);
543
+ if (migrated.changed) {
544
+ this.writePreferences(this.cache);
545
+ }
546
+ return this.cache;
547
+ }
548
+ } catch (err) {
549
+ console.warn("[Preferences] Failed to load preferences.json:", err);
550
+ }
551
+ this.cache = { ...DEFAULTS };
552
+ return this.cache;
553
+ }
554
+ save(partial) {
555
+ try {
556
+ const current = this.load();
557
+ const merged = this.deepMerge(
558
+ current,
559
+ partial
560
+ );
561
+ if (Object.prototype.hasOwnProperty.call(partial.aiPreprocessConfig ?? {}, "desensitizeBuiltinRuleOverrides")) {
562
+ const mergedAiPreprocessConfig = merged.aiPreprocessConfig;
563
+ mergedAiPreprocessConfig.desensitizeBuiltinRuleOverrides = partial.aiPreprocessConfig?.desensitizeBuiltinRuleOverrides;
564
+ }
565
+ this.cache = this.mergeDefaults(merged);
566
+ this.writePreferences(this.cache);
567
+ return { success: true };
568
+ } catch (err) {
569
+ const msg = err instanceof Error ? err.message : String(err);
570
+ console.error("[Preferences] Failed to save:", msg);
571
+ return { success: false, error: msg };
572
+ }
573
+ }
574
+ getFilePath() {
575
+ return this.filePath;
576
+ }
577
+ invalidateCache() {
578
+ this.cache = null;
579
+ }
580
+ mergeDefaults(partial) {
581
+ return {
582
+ pinnedSessionIds: partial.pinnedSessionIds ?? DEFAULTS.pinnedSessionIds,
583
+ aiPreprocessConfig: partial.aiPreprocessConfig ? this.normalizeAiPreprocessConfig(partial.aiPreprocessConfig) : { ...DEFAULTS.aiPreprocessConfig },
584
+ aiGlobalSettings: partial.aiGlobalSettings ? {
585
+ ...DEFAULTS.aiGlobalSettings,
586
+ ...partial.aiGlobalSettings,
587
+ contextCompression: {
588
+ ...DEFAULTS.aiGlobalSettings.contextCompression,
589
+ ...partial.aiGlobalSettings.contextCompression ?? {}
590
+ }
591
+ } : { ...DEFAULTS.aiGlobalSettings },
592
+ customKeywordTemplates: partial.customKeywordTemplates ?? DEFAULTS.customKeywordTemplates,
593
+ deletedPresetTemplateIds: partial.deletedPresetTemplateIds ?? DEFAULTS.deletedPresetTemplateIds,
594
+ wordFilter: partial.wordFilter ? { ...DEFAULTS.wordFilter, ...partial.wordFilter } : { ...DEFAULTS.wordFilter },
595
+ filterHistory: partial.filterHistory ?? DEFAULTS.filterHistory,
596
+ thinkingLevels: partial.thinkingLevels ?? DEFAULTS.thinkingLevels,
597
+ ownerProfilesByPlatform: partial.ownerProfilesByPlatform ?? DEFAULTS.ownerProfilesByPlatform,
598
+ ownerPromptDismissedSessionIds: partial.ownerPromptDismissedSessionIds ?? DEFAULTS.ownerPromptDismissedSessionIds
599
+ };
600
+ }
601
+ normalizeAiPreprocessConfig(partial) {
602
+ const defaults = DEFAULTS.aiPreprocessConfig;
603
+ const rules = Array.isArray(partial?.desensitizeRules) ? partial.desensitizeRules : [];
604
+ const customRules = rules.filter((rule) => !rule.builtin);
605
+ return {
606
+ dataCleaning: partial?.dataCleaning ?? defaults.dataCleaning,
607
+ mergeConsecutive: partial?.mergeConsecutive ?? defaults.mergeConsecutive,
608
+ mergeWindowSeconds: partial?.mergeWindowSeconds ?? defaults.mergeWindowSeconds,
609
+ blacklistKeywords: partial?.blacklistKeywords ?? defaults.blacklistKeywords,
610
+ denoise: partial?.denoise ?? defaults.denoise,
611
+ desensitize: partial?.desensitize ?? defaults.desensitize,
612
+ desensitizeRulesSchemaVersion: DESENSITIZE_RULES_SCHEMA_VERSION,
613
+ desensitizeBuiltinRuleOverrides: this.normalizeBooleanMap(partial?.desensitizeBuiltinRuleOverrides),
614
+ desensitizeRules: customRules,
615
+ anonymizeNames: partial?.anonymizeNames ?? defaults.anonymizeNames
616
+ };
617
+ }
618
+ normalizeBooleanMap(value) {
619
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
620
+ const result = {};
621
+ for (const [key, flag] of Object.entries(value)) {
622
+ if (typeof flag === "boolean") result[key] = flag;
623
+ }
624
+ return result;
625
+ }
626
+ migrateLegacyDesensitizeRules(partial, rawContent) {
627
+ const rules = partial.aiPreprocessConfig?.desensitizeRules;
628
+ if (!Array.isArray(rules) || !rules.some((rule) => rule.builtin)) {
629
+ return { preferences: partial, changed: false };
630
+ }
631
+ this.backupLegacyPreferences(rawContent);
632
+ const legacyBuiltinRuleOverrides = rules.filter((rule) => rule.builtin && typeof rule.enabled === "boolean").reduce((overrides, rule) => {
633
+ overrides[rule.id] = rule.enabled;
634
+ return overrides;
635
+ }, {});
636
+ const existingOverrides = this.normalizeBooleanMap(partial.aiPreprocessConfig?.desensitizeBuiltinRuleOverrides);
637
+ return {
638
+ preferences: {
639
+ ...partial,
640
+ aiPreprocessConfig: {
641
+ ...partial.aiPreprocessConfig,
642
+ desensitizeRulesSchemaVersion: DESENSITIZE_RULES_SCHEMA_VERSION,
643
+ desensitizeBuiltinRuleOverrides: {
644
+ ...legacyBuiltinRuleOverrides,
645
+ ...existingOverrides
646
+ },
647
+ desensitizeRules: rules.filter((rule) => !rule.builtin)
648
+ }
649
+ },
650
+ changed: true
651
+ };
652
+ }
653
+ backupLegacyPreferences(rawContent) {
654
+ const backupDir = path3.join(path3.dirname(this.filePath), "backups");
655
+ if (!fs4.existsSync(backupDir)) {
656
+ fs4.mkdirSync(backupDir, { recursive: true });
657
+ }
658
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
659
+ const backupPath = path3.join(backupDir, `preferences-pre-desensitize-groups-${timestamp}.json`);
660
+ fs4.writeFileSync(backupPath, rawContent, "utf-8");
661
+ console.info(`[Preferences] Backed up legacy desensitize rules to ${backupPath}`);
662
+ }
663
+ writePreferences(preferences) {
664
+ const dir = path3.dirname(this.filePath);
665
+ if (!fs4.existsSync(dir)) {
666
+ fs4.mkdirSync(dir, { recursive: true });
667
+ }
668
+ fs4.writeFileSync(this.filePath, JSON.stringify(preferences, null, 2), "utf-8");
669
+ }
670
+ /**
671
+ * Deep merge: arrays are replaced (not concatenated), objects are merged.
672
+ */
673
+ deepMerge(base, override) {
674
+ const result = { ...base };
675
+ for (const [key, value] of Object.entries(override)) {
676
+ if (value === void 0) continue;
677
+ if (value !== null && typeof value === "object" && !Array.isArray(value) && typeof base[key] === "object" && base[key] !== null && !Array.isArray(base[key])) {
678
+ result[key] = this.deepMerge(base[key], value);
679
+ } else {
680
+ result[key] = value;
681
+ }
682
+ }
683
+ return result;
684
+ }
685
+ };
686
+
687
+ // ../../packages/node-runtime/src/merger/index.ts
688
+ function checkConflictsFromSources(dataSources) {
689
+ const allMessages = [];
690
+ for (const { source, filename } of dataSources) {
691
+ const meta = source.getMeta();
692
+ const platform = meta?.platform || "unknown";
693
+ source.streamMessages(1e4, (messages) => {
694
+ for (const msg of messages) {
695
+ allMessages.push({ msg, source: filename, platform });
696
+ }
697
+ });
698
+ }
699
+ return detectConflictsInMessages(allMessages);
700
+ }
701
+ function buildMergedOutput(dataSources, outputName) {
702
+ const metas = dataSources.map(({ source, filename }) => ({
703
+ meta: source.getMeta(),
704
+ members: source.getMembers(),
705
+ filename,
706
+ source
707
+ }));
708
+ const collidingIds = getCollidingPlatformIds(
709
+ metas.map(({ meta, members }) => ({
710
+ platform: meta?.platform || "unknown",
711
+ members: members.map((m) => ({ platformId: m.platformId }))
712
+ }))
713
+ );
714
+ const memberMap = mergeMembers(
715
+ metas.map(({ meta, members }) => ({
716
+ platform: meta?.platform || "unknown",
717
+ members
718
+ })),
719
+ collidingIds
720
+ );
721
+ const seenKeys = /* @__PURE__ */ new Set();
722
+ const mergedMessages = [];
723
+ for (const { source, meta } of metas) {
724
+ const platform2 = meta?.platform || "unknown";
725
+ source.streamMessages(1e4, (messages) => {
726
+ for (const msg of messages) {
727
+ const nid = normalizePlatformId(msg.senderPlatformId, platform2, collidingIds);
728
+ const key = generateMessageKey(msg.timestamp, nid, msg.content ?? null);
729
+ if (seenKeys.has(key)) continue;
730
+ seenKeys.add(key);
731
+ mergedMessages.push({
732
+ sender: nid,
733
+ accountName: msg.senderAccountName,
734
+ groupNickname: msg.senderGroupNickname,
735
+ timestamp: msg.timestamp,
736
+ type: msg.type,
737
+ content: msg.content
738
+ });
739
+ }
740
+ });
741
+ }
742
+ mergedMessages.sort((a, b) => a.timestamp - b.timestamp);
743
+ const sources = dataSources.map(({ source, filename }) => ({
744
+ filename,
745
+ platform: source.getMeta()?.platform || "unknown",
746
+ messageCount: source.getMessageCount()
747
+ }));
748
+ const uniquePlatforms = [...new Set(metas.map(({ meta }) => meta?.platform || "unknown"))];
749
+ const platform = uniquePlatforms.length === 1 ? uniquePlatforms[0] : "mixed";
750
+ const groupIds = new Set(metas.map(({ meta }) => meta?.groupId).filter(Boolean));
751
+ const groupId = groupIds.size === 1 ? metas.find(({ meta }) => meta?.groupId)?.meta?.groupId : void 0;
752
+ const groupAvatar = groupId ? metas.filter(({ meta }) => meta?.groupId === groupId).pop()?.meta?.groupAvatar : void 0;
753
+ const chatLabData = {
754
+ chatlab: {
755
+ version: "0.0.1",
756
+ exportedAt: Math.floor(Date.now() / 1e3),
757
+ generator: "ChatLab Merge Tool",
758
+ description: `Merged from ${dataSources.length} files`
759
+ },
760
+ meta: {
761
+ name: outputName,
762
+ platform,
763
+ type: metas[0]?.meta?.type || "group",
764
+ sources,
765
+ groupId,
766
+ groupAvatar
767
+ },
768
+ members: Array.from(memberMap.values()),
769
+ messages: mergedMessages
770
+ };
771
+ return { success: true, chatLabData };
772
+ }
773
+ function* serializeChatLabToJsonl(data) {
774
+ yield JSON.stringify({
775
+ _type: "header",
776
+ chatlab: data.chatlab,
777
+ meta: data.meta
778
+ });
779
+ for (const member of data.members) {
780
+ yield JSON.stringify({ _type: "member", ...member });
781
+ }
782
+ for (const msg of data.messages) {
783
+ yield JSON.stringify({ _type: "message", ...msg });
784
+ }
785
+ }
786
+
787
+ // ../../packages/node-runtime/src/services/analytics.ts
788
+ import * as fs5 from "fs";
789
+ import * as path4 from "path";
790
+ var REGIONS = {
791
+ US: "https://us.aptabase.com",
792
+ EU: "https://eu.aptabase.com"
793
+ };
794
+ var DEFAULT_DATA = { lastReportDate: null, firstReportDate: null, enabled: true };
795
+ var AnalyticsService = class {
796
+ dataPath;
797
+ endpoint;
798
+ appKey;
799
+ appVersion;
800
+ sessionId;
801
+ constructor(systemDir, appKey, appVersion) {
802
+ this.dataPath = path4.join(systemDir, "analytics.json");
803
+ this.appKey = appKey;
804
+ this.appVersion = appVersion;
805
+ this.sessionId = `${Math.floor(Date.now() / 1e3)}${Math.floor(Math.random() * 1e8).toString().padStart(8, "0")}`;
806
+ const parts = appKey.split("-");
807
+ const base = parts.length === 3 ? REGIONS[parts[1]] : void 0;
808
+ this.endpoint = base ? `${base}/api/v0/event` : null;
809
+ }
810
+ load() {
811
+ try {
812
+ if (fs5.existsSync(this.dataPath)) {
813
+ return { ...DEFAULT_DATA, ...JSON.parse(fs5.readFileSync(this.dataPath, "utf-8")) };
814
+ }
815
+ } catch (_e) {
816
+ }
817
+ return { ...DEFAULT_DATA };
818
+ }
819
+ save(data) {
820
+ try {
821
+ fs5.writeFileSync(this.dataPath, JSON.stringify(data, null, 2), "utf-8");
822
+ } catch (e) {
823
+ console.error("[Analytics] Failed to save:", e);
824
+ }
825
+ }
826
+ getEnabled() {
827
+ return this.load().enabled;
828
+ }
829
+ setEnabled(enabled) {
830
+ const data = this.load();
831
+ data.enabled = enabled;
832
+ this.save(data);
833
+ }
834
+ async track(eventName, props) {
835
+ if (!this.endpoint) return false;
836
+ if (!this.getEnabled()) return false;
837
+ try {
838
+ const resp = await fetch(this.endpoint, {
839
+ method: "POST",
840
+ headers: { "Content-Type": "application/json", "App-Key": this.appKey },
841
+ body: JSON.stringify({
842
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
843
+ sessionId: this.sessionId,
844
+ eventName,
845
+ systemProps: {
846
+ isDebug: false,
847
+ locale: "",
848
+ osName: process.platform,
849
+ osVersion: "",
850
+ engineName: "Node.js",
851
+ engineVersion: process.versions.node,
852
+ appVersion: this.appVersion,
853
+ sdkVersion: "chatlab@1"
854
+ },
855
+ props
856
+ })
857
+ });
858
+ return resp.ok;
859
+ } catch (e) {
860
+ console.error(`[Analytics] Failed to track ${eventName}:`, e);
861
+ return false;
862
+ }
863
+ }
864
+ async trackDailyActive(props) {
865
+ if (!this.endpoint) return;
866
+ const data = this.load();
867
+ if (!data.enabled) return;
868
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
869
+ const isNew = data.firstReportDate === null;
870
+ if (isNew) data.firstReportDate = today;
871
+ if (data.lastReportDate === today) {
872
+ if (isNew) this.save(data);
873
+ return;
874
+ }
875
+ const tracked = await this.track(isNew ? "app_active_new" : "app_active", props);
876
+ if (!tracked) return;
877
+ data.lastReportDate = today;
878
+ this.save(data);
879
+ }
880
+ };
881
+
882
+ // ../../packages/node-runtime/src/semantic-index/index.ts
883
+ var semantic_index_exports = {};
884
+ __export(semantic_index_exports, {
885
+ CHUNKER_VERSION: () => CHUNKER_VERSION,
886
+ CHUNK_VECTOR_INDEX_INDEXES: () => CHUNK_VECTOR_INDEX_INDEXES,
887
+ CHUNK_VECTOR_INDEX_TABLE: () => CHUNK_VECTOR_INDEX_TABLE,
888
+ DEFAULT_CHUNKER_CONFIG: () => DEFAULT_CHUNKER_CONFIG,
889
+ EMBEDDING_INDEX_SCHEMA: () => EMBEDDING_INDEX_SCHEMA,
890
+ EmbeddingIndexStore: () => EmbeddingIndexStore,
891
+ SEARCH_MAX_RESULTS_DEFAULT: () => SEARCH_MAX_RESULTS_DEFAULT,
892
+ SEARCH_MAX_RESULTS_MAX: () => SEARCH_MAX_RESULTS_MAX,
893
+ SEARCH_MAX_RESULTS_MIN: () => SEARCH_MAX_RESULTS_MIN,
894
+ SEMANTIC_INDEX_AUTH_PROFILE: () => SEMANTIC_INDEX_AUTH_PROFILE,
895
+ SEMANTIC_INDEX_CONFIG_FILE: () => SEMANTIC_INDEX_CONFIG_FILE,
896
+ SEMANTIC_INDEX_CONFIG_VERSION: () => SEMANTIC_INDEX_CONFIG_VERSION,
897
+ SEMANTIC_INDEX_DB_FILE: () => SEMANTIC_INDEX_DB_FILE,
898
+ SEMANTIC_INDEX_SESSION_TABLE: () => SEMANTIC_INDEX_SESSION_TABLE,
899
+ STRATEGY_ID: () => STRATEGY_ID,
900
+ SemanticIndexConfigStore: () => SemanticIndexConfigStore,
901
+ SemanticIndexJobQueue: () => SemanticIndexJobQueue,
902
+ SemanticIndexService: () => SemanticIndexService,
903
+ SemanticIndexStateStore: () => SemanticIndexStateStore,
904
+ SemanticIndexWorkerClient: () => SemanticIndexWorkerClient,
905
+ StaticPathProvider: () => StaticPathProvider,
906
+ assembleEvidence: () => assembleEvidence,
907
+ chunkMessages: () => chunkMessages,
908
+ clampSearchMaxResults: () => clampSearchMaxResults,
909
+ composeChunkId: () => composeChunkId,
910
+ computeChunkerConfigHash: () => computeChunkerConfigHash,
911
+ computeDbPathHash: () => computeDbPathHash,
912
+ createChatDbFtsSearcher: () => createChatDbFtsSearcher,
913
+ createChatDbMessageRangeReader: () => createChatDbMessageRangeReader,
914
+ createChatDbMessageSource: () => createChatDbMessageSource,
915
+ createEmbedder: () => createEmbedder,
916
+ createSemanticIndexService: () => createSemanticIndexService,
917
+ createSemanticIndexWorkerClient: () => createSemanticIndexWorkerClient,
918
+ createSemanticIndexWorkerRuntimeClient: () => createSemanticIndexWorkerRuntimeClient,
919
+ createSemanticIndexWorkerThreadTransport: () => createSemanticIndexWorkerThreadTransport,
920
+ defaultSemanticIndexConfig: () => defaultSemanticIndexConfig,
921
+ deriveParentId: () => deriveParentId,
922
+ embedding: () => embedding_exports,
923
+ estimateTokens: () => estimateTokens,
924
+ extractFtsKeywords: () => extractFtsKeywords,
925
+ formatEvidenceMessages: () => formatEvidenceMessages,
926
+ hybridSearch: () => hybridSearch,
927
+ isSemanticIndexConfigured: () => isSemanticIndexConfigured,
928
+ isSemanticVoid: () => isSemanticVoid,
929
+ parseParentBounds: () => parseParentBounds,
930
+ persistSemanticIndexConfig: () => persistSemanticIndexConfig,
931
+ reciprocalRankFusion: () => reciprocalRankFusion,
932
+ resolveModelId: () => resolveModelId,
933
+ resolveSemanticIndexApiKeySet: () => resolveSemanticIndexApiKeySet,
934
+ runWarmup: () => runWarmup,
935
+ snapshotPathProvider: () => snapshotPathProvider,
936
+ vecTableName: () => vecTableName,
937
+ vecTableSchema: () => vecTableSchema
938
+ });
939
+
940
+ // ../../packages/node-runtime/src/semantic-index/worker-client.ts
941
+ import path5 from "path";
942
+
943
+ // ../../packages/node-runtime/src/semantic-index/worker-thread-transport.ts
944
+ import { Worker } from "worker_threads";
945
+ var DEFAULT_CLOSE_TIMEOUT_MS = 3e3;
946
+ function defaultWorkerEntryUrl() {
947
+ return import.meta.url.endsWith(".ts") ? new URL("./worker-thread-entry.ts", import.meta.url) : new URL("./worker-thread-entry.js", import.meta.url);
948
+ }
949
+ function normalizeWorkerEntryUrl(entryUrl) {
950
+ if (!entryUrl) return defaultWorkerEntryUrl();
951
+ return typeof entryUrl === "string" ? new URL(entryUrl) : entryUrl;
952
+ }
953
+ function createDefaultWorker(startup, entryUrlInput) {
954
+ const entryUrl = normalizeWorkerEntryUrl(entryUrlInput);
955
+ if (!entryUrl.href.endsWith(".ts")) {
956
+ return new Worker(entryUrl, { workerData: startup });
957
+ }
958
+ const bootstrap = `
959
+ import { register } from 'tsx/esm/api';
960
+ register();
961
+ await import(${JSON.stringify(entryUrl.href)});
962
+ `;
963
+ const options = {
964
+ eval: true,
965
+ type: "module",
966
+ workerData: startup,
967
+ execArgv: []
968
+ };
969
+ return new Worker(bootstrap, options);
970
+ }
971
+ var SemanticIndexWorkerThreadTransport = class {
972
+ worker;
973
+ pending = /* @__PURE__ */ new Map();
974
+ requestId = 0;
975
+ closeTimeoutMs;
976
+ constructor(options) {
977
+ this.closeTimeoutMs = options.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
978
+ this.worker = options.workerFactory?.() ?? createDefaultWorker(options.startup, options.workerEntryUrl);
979
+ this.worker.on("message", (message) => this.handleMessage(message));
980
+ this.worker.on("error", (error) => this.rejectAll(error));
981
+ this.worker.on("exit", (code) => {
982
+ if (code !== 0) this.rejectAll(new Error(`Semantic index worker exited with code ${code}`));
983
+ });
984
+ }
985
+ request(method, args) {
986
+ const id = `si_${++this.requestId}`;
987
+ return new Promise((resolve2, reject) => {
988
+ this.pending.set(id, { resolve: resolve2, reject });
989
+ this.worker.postMessage({ id, method, args });
990
+ });
991
+ }
992
+ async close() {
993
+ await this.requestRuntimeClose();
994
+ await this.worker.terminate();
995
+ this.rejectAll(new Error("Semantic index worker closed"));
996
+ }
997
+ async requestRuntimeClose() {
998
+ let timeout = null;
999
+ const timeoutPromise = new Promise((resolve2) => {
1000
+ timeout = setTimeout(resolve2, this.closeTimeoutMs);
1001
+ });
1002
+ try {
1003
+ await Promise.race([this.request("__close", []).then(() => void 0), timeoutPromise]);
1004
+ } catch {
1005
+ } finally {
1006
+ if (timeout) clearTimeout(timeout);
1007
+ }
1008
+ }
1009
+ handleMessage(message) {
1010
+ const payload = message;
1011
+ if (!payload.id) return;
1012
+ const pending = this.pending.get(payload.id);
1013
+ if (!pending) return;
1014
+ this.pending.delete(payload.id);
1015
+ if (payload.success) pending.resolve(payload.result);
1016
+ else pending.reject(new Error(payload.error ?? "Semantic index worker request failed"));
1017
+ }
1018
+ rejectAll(error) {
1019
+ for (const [id, pending] of this.pending.entries()) {
1020
+ this.pending.delete(id);
1021
+ pending.reject(error);
1022
+ }
1023
+ }
1024
+ };
1025
+ function createSemanticIndexWorkerThreadTransport(options) {
1026
+ return new SemanticIndexWorkerThreadTransport(options);
1027
+ }
1028
+
1029
+ // ../../packages/node-runtime/src/semantic-index/worker-client.ts
1030
+ var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1e3;
1031
+ var defaultTimers = {
1032
+ setTimeout: (callback, ms) => setTimeout(callback, ms),
1033
+ clearTimeout: (timer) => clearTimeout(timer)
1034
+ };
1035
+ var SemanticIndexWorkerClient = class {
1036
+ transport = null;
1037
+ pendingRequests = 0;
1038
+ idleTimer = null;
1039
+ activeBuildSessionIds = /* @__PURE__ */ new Set();
1040
+ hasUnknownActiveBuild = false;
1041
+ activeModelDownloadProxyUrl;
1042
+ configStore;
1043
+ transportFactory;
1044
+ idleTimeoutMs;
1045
+ timers;
1046
+ getModelDownloadProxyUrl;
1047
+ resolveApiKey;
1048
+ writeAuthProfile;
1049
+ constructor(options) {
1050
+ this.configStore = options.configStore;
1051
+ this.transportFactory = options.transportFactory;
1052
+ this.idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
1053
+ this.timers = options.timers ?? defaultTimers;
1054
+ this.getModelDownloadProxyUrl = options.getModelDownloadProxyUrl ?? (() => void 0);
1055
+ this.resolveApiKey = options.resolveApiKey ?? resolveApiKey;
1056
+ this.writeAuthProfile = options.writeAuthProfile;
1057
+ }
1058
+ getConfig() {
1059
+ return this.configStore.get();
1060
+ }
1061
+ async setConfig(config, options) {
1062
+ const saved = persistSemanticIndexConfig(this.configStore, config, {
1063
+ apiKey: options?.apiKey,
1064
+ writeAuthProfile: this.writeAuthProfile
1065
+ });
1066
+ if (!saved.enabled) this.clearActiveBuildTracking();
1067
+ const needsWorker = saved.enabled && saved.mode === "local" && this.configStore.isConfigured();
1068
+ if (!this.transport && !needsWorker) return saved;
1069
+ if (needsWorker) await this.closeTransportForLocalModelProxyChangeIfNeeded();
1070
+ return await this.call("setConfig", [saved]);
1071
+ }
1072
+ isConfigured() {
1073
+ return this.configStore.isConfigured();
1074
+ }
1075
+ hasApiKey() {
1076
+ return resolveSemanticIndexApiKeySet(this.configStore.get(), this.resolveApiKey);
1077
+ }
1078
+ async getModelStatus() {
1079
+ if (!this.transport) return "idle";
1080
+ return this.call("getModelStatus", []);
1081
+ }
1082
+ enable(sessionId) {
1083
+ return this.call("enable", [sessionId]);
1084
+ }
1085
+ remove(sessionId) {
1086
+ return this.call("remove", [sessionId]);
1087
+ }
1088
+ async build(sessionId) {
1089
+ await this.closeTransportForLocalModelProxyChangeIfNeeded();
1090
+ this.activeBuildSessionIds.add(sessionId);
1091
+ try {
1092
+ await this.call("build", [sessionId]);
1093
+ } catch (error) {
1094
+ this.activeBuildSessionIds.delete(sessionId);
1095
+ throw error;
1096
+ }
1097
+ }
1098
+ pause(sessionId) {
1099
+ return this.call("pause", [sessionId]);
1100
+ }
1101
+ cancel(sessionId) {
1102
+ return this.call("cancel", [sessionId]);
1103
+ }
1104
+ async rebuild(sessionId) {
1105
+ await this.closeTransportForLocalModelProxyChangeIfNeeded();
1106
+ this.activeBuildSessionIds.add(sessionId);
1107
+ try {
1108
+ await this.call("rebuild", [sessionId]);
1109
+ } catch (error) {
1110
+ this.activeBuildSessionIds.delete(sessionId);
1111
+ throw error;
1112
+ }
1113
+ }
1114
+ async buildAllPending() {
1115
+ await this.closeTransportForLocalModelProxyChangeIfNeeded();
1116
+ this.hasUnknownActiveBuild = true;
1117
+ try {
1118
+ await this.call("buildAllPending", []);
1119
+ } catch (error) {
1120
+ this.hasUnknownActiveBuild = false;
1121
+ throw error;
1122
+ }
1123
+ }
1124
+ async listEnabledStatuses() {
1125
+ const statuses = await this.callProbe("listEnabledStatuses", [], [], {
1126
+ scheduleIdle: false
1127
+ });
1128
+ this.updateActiveBuildFromCompleteSnapshot(statuses);
1129
+ this.scheduleIdleCloseIfNeeded();
1130
+ return statuses;
1131
+ }
1132
+ async status(sessionId) {
1133
+ const status = await this.callProbe("status", [sessionId], null, {
1134
+ scheduleIdle: false
1135
+ });
1136
+ this.updateActiveBuildFromPartialSnapshot([sessionId], status ? [status] : []);
1137
+ this.scheduleIdleCloseIfNeeded();
1138
+ return status;
1139
+ }
1140
+ async statusForSessions(sessionIds) {
1141
+ const statuses = await this.callProbe("statusForSessions", [sessionIds], [], {
1142
+ scheduleIdle: false
1143
+ });
1144
+ this.updateActiveBuildFromPartialSnapshot(sessionIds, statuses);
1145
+ this.scheduleIdleCloseIfNeeded();
1146
+ return statuses;
1147
+ }
1148
+ async canSearch(sessionId) {
1149
+ if (!this.canRunFromLocalConfig()) return false;
1150
+ return await this.callProbe("canSearch", [sessionId], false);
1151
+ }
1152
+ async search(sessionId, query, options) {
1153
+ await this.closeTransportForLocalModelProxyChangeIfNeeded();
1154
+ return await this.call("search", [sessionId, query, options]);
1155
+ }
1156
+ async searchForTool(sessionId, query, options) {
1157
+ await this.closeTransportForLocalModelProxyChangeIfNeeded();
1158
+ return await this.call("searchForTool", [sessionId, query, options]);
1159
+ }
1160
+ cleanupUnused() {
1161
+ return this.call("cleanupUnused", []);
1162
+ }
1163
+ recover() {
1164
+ return this.call("recover", []);
1165
+ }
1166
+ async close() {
1167
+ this.clearIdleTimer();
1168
+ await this.closeTransport();
1169
+ }
1170
+ async call(method, args, options) {
1171
+ const transport = await this.ensureTransport();
1172
+ this.pendingRequests++;
1173
+ this.clearIdleTimer();
1174
+ try {
1175
+ return await transport.request(method, args);
1176
+ } finally {
1177
+ this.pendingRequests--;
1178
+ if (options?.scheduleIdle !== false) this.scheduleIdleCloseIfNeeded();
1179
+ }
1180
+ }
1181
+ async callProbe(method, args, fallback, options) {
1182
+ try {
1183
+ return await this.call(method, args, options);
1184
+ } catch {
1185
+ await this.closeFailedProbeTransport();
1186
+ return fallback;
1187
+ }
1188
+ }
1189
+ async ensureTransport() {
1190
+ if (!this.transport) {
1191
+ const proxyUrl = await this.currentModelDownloadProxyUrl();
1192
+ if (!this.transport) {
1193
+ this.activeModelDownloadProxyUrl = proxyUrl;
1194
+ this.transport = this.transportFactory(proxyUrl);
1195
+ }
1196
+ }
1197
+ return this.transport;
1198
+ }
1199
+ async currentModelDownloadProxyUrl() {
1200
+ const proxyUrl = (await this.getModelDownloadProxyUrl())?.trim();
1201
+ return proxyUrl || void 0;
1202
+ }
1203
+ async closeTransportForLocalModelProxyChangeIfNeeded() {
1204
+ if (!this.transport) return;
1205
+ const config = this.configStore.get();
1206
+ if (!this.configStore.canRun() || config.mode !== "local") return;
1207
+ if (this.hasUnknownActiveBuild || this.activeBuildSessionIds.size > 0) return;
1208
+ if (await this.currentModelDownloadProxyUrl() === this.activeModelDownloadProxyUrl) return;
1209
+ await this.closeTransport();
1210
+ }
1211
+ canRunFromLocalConfig() {
1212
+ const config = this.configStore.get();
1213
+ if (!this.configStore.canRun()) return false;
1214
+ if (config.mode !== "api") return true;
1215
+ if (isKeylessSemanticIndexApiBaseUrl(config.api?.baseUrl)) return true;
1216
+ return resolveSemanticIndexApiKeySet(config, this.resolveApiKey);
1217
+ }
1218
+ updateActiveBuildFromCompleteSnapshot(statuses) {
1219
+ this.hasUnknownActiveBuild = false;
1220
+ this.activeBuildSessionIds = new Set(
1221
+ statuses.filter((status) => this.isActiveBuildStatus(status)).map((status) => status.sessionId)
1222
+ );
1223
+ }
1224
+ updateActiveBuildFromPartialSnapshot(requestedSessionIds, statuses) {
1225
+ const bySessionId = new Map(statuses.map((status) => [status.sessionId, status]));
1226
+ for (const sessionId of requestedSessionIds) {
1227
+ const status = bySessionId.get(sessionId);
1228
+ if (status && this.isActiveBuildStatus(status)) this.activeBuildSessionIds.add(sessionId);
1229
+ else this.activeBuildSessionIds.delete(sessionId);
1230
+ }
1231
+ }
1232
+ isActiveBuildStatus(status) {
1233
+ return status.running || status.queued || status.indexStatus === "running";
1234
+ }
1235
+ clearActiveBuildTracking() {
1236
+ this.hasUnknownActiveBuild = false;
1237
+ this.activeBuildSessionIds.clear();
1238
+ }
1239
+ scheduleIdleCloseIfNeeded() {
1240
+ if (!this.transport || this.pendingRequests > 0 || this.hasUnknownActiveBuild || this.activeBuildSessionIds.size > 0)
1241
+ return;
1242
+ this.clearIdleTimer();
1243
+ this.idleTimer = this.timers.setTimeout(() => {
1244
+ void this.closeTransport().catch((err) => {
1245
+ console.warn("[semantic-index] idle worker close failed:", err instanceof Error ? err.message : String(err));
1246
+ });
1247
+ }, this.idleTimeoutMs);
1248
+ }
1249
+ clearIdleTimer() {
1250
+ if (this.idleTimer) {
1251
+ this.timers.clearTimeout(this.idleTimer);
1252
+ this.idleTimer = null;
1253
+ }
1254
+ }
1255
+ async closeTransport() {
1256
+ const transport = this.transport;
1257
+ this.transport = null;
1258
+ this.activeModelDownloadProxyUrl = void 0;
1259
+ this.clearActiveBuildTracking();
1260
+ if (transport) await transport.close();
1261
+ }
1262
+ async closeFailedProbeTransport() {
1263
+ this.clearIdleTimer();
1264
+ try {
1265
+ await this.closeTransport();
1266
+ } catch {
1267
+ }
1268
+ }
1269
+ };
1270
+ function createSemanticIndexWorkerClient(options) {
1271
+ return new SemanticIndexWorkerClient(options);
1272
+ }
1273
+ function createSemanticIndexWorkerRuntimeClient(options) {
1274
+ const configStore = new SemanticIndexConfigStore(
1275
+ path5.join(options.pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE)
1276
+ );
1277
+ return createSemanticIndexWorkerClient({
1278
+ configStore,
1279
+ idleTimeoutMs: options.idleTimeoutMs,
1280
+ resolveApiKey: options.resolveApiKey,
1281
+ writeAuthProfile: options.writeAuthProfile,
1282
+ getModelDownloadProxyUrl: options.getModelDownloadProxyUrl,
1283
+ transportFactory: (modelDownloadProxyUrl) => createSemanticIndexWorkerThreadTransport({
1284
+ workerEntryUrl: options.workerEntryUrl,
1285
+ startup: {
1286
+ paths: snapshotPathProvider(options.pathProvider),
1287
+ runtime: options.runtime,
1288
+ nativeBinding: options.nativeBinding,
1289
+ sqliteVecLoadablePath: options.sqliteVecLoadablePath,
1290
+ modelDownloadProxyUrl
1291
+ }
1292
+ })
1293
+ });
1294
+ }
1295
+
1296
+ // ../../packages/node-runtime/src/semantic-index/embedding/index.ts
1297
+ var embedding_exports = {};
1298
+ __export(embedding_exports, {
1299
+ BGE_BASE_PROFILE: () => BGE_BASE_PROFILE,
1300
+ LocalEmbeddingProvider: () => LocalEmbeddingProvider,
1301
+ OpenAICompatibleEmbeddingProvider: () => OpenAICompatibleEmbeddingProvider,
1302
+ QWEN3_PROFILE: () => QWEN3_PROFILE,
1303
+ applyQueryInstruction: () => applyQueryInstruction,
1304
+ clampTextChars: () => clampTextChars,
1305
+ getLocalProfileByModelId: () => getLocalProfileByModelId,
1306
+ getLocalProfilesForLocale: () => getLocalProfilesForLocale
1307
+ });
1308
+
1309
+ export {
1310
+ isExistingUserDataDir,
1311
+ isUserDataDirSafeToUse,
1312
+ isDirectoryEmptyOrMissing,
1313
+ copyDirMerge,
1314
+ createPendingDataDirMigration,
1315
+ runPendingDataDirMigration,
1316
+ getPendingNodeDataDirMigration,
1317
+ clearPendingNodeDataDirMigration,
1318
+ createNodeDataDirSwitch,
1319
+ applyPendingNodeDataDirMigration,
1320
+ hasPendingElectronDataWarning,
1321
+ applyPendingNodeDataDirMigrationIfNeeded,
1322
+ NodePathProvider,
1323
+ getDefaultNodeUserDataDir,
1324
+ getSystemLogsDir,
1325
+ createJiebaNlpProvider,
1326
+ getDbFileVersion,
1327
+ getOrComputeAnalysisCache,
1328
+ PreferencesManager,
1329
+ checkConflictsFromSources,
1330
+ buildMergedOutput,
1331
+ serializeChatLabToJsonl,
1332
+ AnalyticsService,
1333
+ createSemanticIndexWorkerRuntimeClient,
1334
+ semantic_index_exports
1335
+ };
1336
+ //# sourceMappingURL=chunk-YBS3YQB6.mjs.map