chatlab-cli 0.28.0 → 0.29.0

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 (120) hide show
  1. package/dist/{chat-command-7WL5NMZ6.mjs → chat-command-JKG3FY5B.mjs} +8 -5
  2. package/dist/{chat-command-7WL5NMZ6.mjs.map → chat-command-JKG3FY5B.mjs.map} +1 -1
  3. package/dist/chunk-2MZ6G4AC.mjs +1339 -0
  4. package/dist/chunk-2MZ6G4AC.mjs.map +1 -0
  5. package/dist/chunk-5FGB42EQ.mjs +7 -0
  6. package/dist/{chunk-WGS33EWH.mjs → chunk-6FPEP2ZX.mjs} +2 -2
  7. package/dist/chunk-7RW4CQAO.mjs +1310 -0
  8. package/dist/chunk-7RW4CQAO.mjs.map +1 -0
  9. package/dist/{chunk-GFRG7TZQ.mjs → chunk-ARZM6HBX.mjs} +17 -15
  10. package/dist/{chunk-GFRG7TZQ.mjs.map → chunk-ARZM6HBX.mjs.map} +1 -1
  11. package/dist/{chunk-VASK54KT.mjs → chunk-CIB23U32.mjs} +2 -2
  12. package/dist/chunk-D4WTE7LV.mjs +526 -0
  13. package/dist/chunk-D4WTE7LV.mjs.map +1 -0
  14. package/dist/{chunk-ZSFVX6FM.mjs → chunk-I35WHWA6.mjs} +7 -21
  15. package/dist/chunk-I35WHWA6.mjs.map +1 -0
  16. package/dist/{chunk-YQ2FJGBT.mjs → chunk-KL2NGIMQ.mjs} +241 -80
  17. package/dist/chunk-KL2NGIMQ.mjs.map +1 -0
  18. package/dist/{chunk-55WR6WKW.mjs → chunk-QQK7MLCR.mjs} +10044 -8354
  19. package/dist/chunk-QQK7MLCR.mjs.map +1 -0
  20. package/dist/{chunk-XNU5X7EV.mjs → chunk-SKUG5XVD.mjs} +10 -8
  21. package/dist/{chunk-XNU5X7EV.mjs.map → chunk-SKUG5XVD.mjs.map} +1 -1
  22. package/dist/chunk-WPI6YSAR.mjs +8813 -0
  23. package/dist/chunk-WPI6YSAR.mjs.map +1 -0
  24. package/dist/cli.mjs +7 -4
  25. package/dist/contacts-worker.mjs +48 -0
  26. package/dist/contacts-worker.mjs.map +1 -0
  27. package/dist/{http-C2FBHNZG.mjs → http-5E7ARYFW.mjs} +12 -9
  28. package/dist/{import-ED6JCPSJ.mjs → import-3KG6VK6O.mjs} +8 -12
  29. package/dist/index.mjs +12 -9
  30. package/dist/{mcp-5JIBER4M.mjs → mcp-JBI4CUQT.mjs} +8 -5
  31. package/dist/{mcp-5JIBER4M.mjs.map → mcp-JBI4CUQT.mjs.map} +1 -1
  32. package/dist/people-relationships-worker.mjs +48 -0
  33. package/dist/people-relationships-worker.mjs.map +1 -0
  34. package/dist/semantic-index-worker.mjs +1 -1
  35. package/dist/{src-WBNM42SL.mjs → src-UTBQAOJ3.mjs} +86 -66
  36. package/dist/{stream-import-37U3SROO.mjs → stream-import-7HZ4IRYJ.mjs} +7 -4
  37. package/dist/stream-import-7HZ4IRYJ.mjs.map +1 -0
  38. package/dist/undici-ZSXBT7EA.mjs +18389 -0
  39. package/dist/undici-ZSXBT7EA.mjs.map +1 -0
  40. package/dist/{worker-runtime-6DGYL4TF.mjs → worker-runtime-ALS4MR2A.mjs} +13 -5
  41. package/dist/worker-runtime-ALS4MR2A.mjs.map +1 -0
  42. package/dist-web/assets/BufferResource-MsqP5sq3.js +185 -0
  43. package/dist-web/assets/CanvasRenderer-BKCvcc2p.js +1 -0
  44. package/dist-web/assets/DebugToolsPanel-D_lFIW6j.css +1 -0
  45. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-HGJb0Et1.js +110 -0
  46. package/dist-web/assets/{EChartWordcloud-B_YisOW5.js → EChartWordcloud-Clg60FMo.js} +1 -1
  47. package/dist-web/assets/Filter-wRJtdXx9.js +1 -0
  48. package/dist-web/assets/MessageExportModal-BCrMf5Kw.js +1 -0
  49. package/dist-web/assets/PageHeader-Bbn87QZS.css +1 -0
  50. package/dist-web/assets/PageHeader-C_yw54le.js +1 -0
  51. package/dist-web/assets/RelationshipGalaxyCanvas-DTzJq7q7.js +244 -0
  52. package/dist-web/assets/RelationshipGalaxyThreeCanvas-BluPHjCR.css +1 -0
  53. package/dist-web/assets/RelationshipGalaxyThreeCanvas-DIE-0_iM.js +4108 -0
  54. package/dist-web/assets/RenderTargetSystem-BSAQFamI.js +184 -0
  55. package/dist-web/assets/WebGLRenderer-lfzmCZNT.js +156 -0
  56. package/dist-web/assets/WebGPURenderer-BnEdfdr_.js +41 -0
  57. package/dist-web/assets/browserAll-gRNfDyPu.js +14 -0
  58. package/dist-web/assets/{electron-DjminAKK.js → electron-BHaEaaZP.js} +1 -1
  59. package/dist-web/assets/{fetch-B_kLRm6-.js → fetch-BW3aO7PS.js} +1 -1
  60. package/dist-web/assets/fetch-BwF5hNuF.js +1 -0
  61. package/dist-web/assets/{fetch-DV8A1dGB.js → fetch-C1fI_KOX.js} +1 -1
  62. package/dist-web/assets/{fetch-uM3erGZm.js → fetch-CBZbgZqk.js} +1 -1
  63. package/dist-web/assets/{fetch-Wad5mWVH.js → fetch-CFRoSIAn.js} +1 -1
  64. package/dist-web/assets/fetch-CN91TIwV.js +1 -0
  65. package/dist-web/assets/{fetch-DOhCQ5J8.js → fetch-CQt-gb-f.js} +1 -1
  66. package/dist-web/assets/{fetch-Cle6QKmL.js → fetch-DPCJ-1l-.js} +1 -1
  67. package/dist-web/assets/{fetch-r83wdzHy.js → fetch-gMB4wuBd.js} +1 -1
  68. package/dist-web/assets/{fetch-srCJzcWc.js → fetch-mFlEBZyB.js} +1 -1
  69. package/dist-web/assets/index---rXG1hZ.css +1 -0
  70. package/dist-web/assets/index--6C0sK6a.css +1 -0
  71. package/dist-web/assets/index-B6wEGata.js +173 -0
  72. package/dist-web/assets/index-Bg4GGPXv.js +1 -0
  73. package/dist-web/assets/index-BgVbj5qX.js +12 -0
  74. package/dist-web/assets/index-BkoXaBV_.js +64 -0
  75. package/dist-web/assets/index-C56IuV5U.css +1 -0
  76. package/dist-web/assets/index-CLRaKwpT.js +2 -0
  77. package/dist-web/assets/index-Dj1BSD7O.js +1 -0
  78. package/dist-web/assets/index-DosG7LmJ.css +1 -0
  79. package/dist-web/assets/index-DveHdPfK.js +1 -0
  80. package/dist-web/assets/{index-BX3tqfLz.css → index-MBRD3wPd.css} +1 -1
  81. package/dist-web/assets/index-RoDgJcHU.js +2 -0
  82. package/dist-web/assets/{index-tkbEq8av.js → index-ZdCB7xcf.js} +4 -4
  83. package/dist-web/assets/index-aljYO5ms.js +1 -0
  84. package/dist-web/assets/people-page-header-Mupn-U_b.js +1 -0
  85. package/dist-web/assets/relationship-galaxy-viewport-Cwfa51ER.js +1 -0
  86. package/dist-web/assets/{vendor-echarts-CITQeskI.js → vendor-echarts-hJVnODyU.js} +2 -2
  87. package/dist-web/assets/{vendor-echarts-wordcloud-B1kQMklB.js → vendor-echarts-wordcloud-k5ih2Jl4.js} +1 -1
  88. package/dist-web/assets/{vendor-nuxt-ui-Zy8txNdC.js → vendor-nuxt-ui-Dr2T8_OZ.js} +2 -2
  89. package/dist-web/assets/{vendor-reka-ui-mMvma1EP.js → vendor-reka-ui-CzM4kDQ7.js} +1 -1
  90. package/dist-web/assets/{vendor-zrender-DFl4U2Oe.js → vendor-zrender-5DcYjSZk.js} +1 -1
  91. package/dist-web/assets/{web-D27K6zSX.js → web-BakeV58u.js} +1 -1
  92. package/dist-web/assets/webworkerAll-D_6PgURS.js +83 -0
  93. package/dist-web/index.html +4 -4
  94. package/package.json +1 -1
  95. package/dist/chunk-55WR6WKW.mjs.map +0 -1
  96. package/dist/chunk-GPF34WXV.mjs +0 -9573
  97. package/dist/chunk-GPF34WXV.mjs.map +0 -1
  98. package/dist/chunk-YQ2FJGBT.mjs.map +0 -1
  99. package/dist/chunk-YZDEZ6UI.mjs +0 -389
  100. package/dist/chunk-YZDEZ6UI.mjs.map +0 -1
  101. package/dist/chunk-ZSFVX6FM.mjs.map +0 -1
  102. package/dist/worker-runtime-6DGYL4TF.mjs.map +0 -1
  103. package/dist-web/assets/DebugToolsPanel-DFw6_G5V.css +0 -1
  104. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-CCz0Syxo.js +0 -110
  105. package/dist-web/assets/MessageExportModal-Dd6R-cX_.js +0 -1
  106. package/dist-web/assets/fetch-CURbMNJV.js +0 -1
  107. package/dist-web/assets/fetch-DFCYOQe5.js +0 -1
  108. package/dist-web/assets/index-7E5GSvR2.css +0 -1
  109. package/dist-web/assets/index-BCRHSc1k.js +0 -173
  110. package/dist-web/assets/index-BIvLzdwg.js +0 -1
  111. package/dist-web/assets/index-BpszRZ8V.js +0 -64
  112. package/dist-web/assets/index-D5UgZUpS.js +0 -12
  113. package/dist-web/assets/index-I3SWZjnW.css +0 -1
  114. package/dist-web/assets/index-hOsKRsp6.js +0 -2
  115. /package/dist/{http-C2FBHNZG.mjs.map → chunk-5FGB42EQ.mjs.map} +0 -0
  116. /package/dist/{chunk-WGS33EWH.mjs.map → chunk-6FPEP2ZX.mjs.map} +0 -0
  117. /package/dist/{chunk-VASK54KT.mjs.map → chunk-CIB23U32.mjs.map} +0 -0
  118. /package/dist/{import-ED6JCPSJ.mjs.map → http-5E7ARYFW.mjs.map} +0 -0
  119. /package/dist/{src-WBNM42SL.mjs.map → import-3KG6VK6O.mjs.map} +0 -0
  120. /package/dist/{stream-import-37U3SROO.mjs.map → src-UTBQAOJ3.mjs.map} +0 -0
@@ -9,12 +9,10 @@ import {
9
9
  analyzeNewImport,
10
10
  incrementalImport,
11
11
  streamingImport
12
- } from "./chunk-GPF34WXV.mjs";
12
+ } from "./chunk-QQK7MLCR.mjs";
13
13
  import {
14
- DataDirCompatibilityError,
15
- generateIncrementalSessionIndex,
16
- generateSessionIndex
17
- } from "./chunk-55WR6WKW.mjs";
14
+ DataDirCompatibilityError
15
+ } from "./chunk-WPI6YSAR.mjs";
18
16
 
19
17
  // src/import/stream-import.ts
20
18
  import * as crypto from "crypto";
@@ -33,12 +31,6 @@ function buildStreamImportDeps(dbManager, onProgress) {
33
31
  },
34
32
  onProgress: onProgress ?? (() => {
35
33
  }),
36
- postImportHook(db) {
37
- try {
38
- generateSessionIndex(db);
39
- } catch {
40
- }
41
- },
42
34
  generateSessionId
43
35
  };
44
36
  }
@@ -46,7 +38,7 @@ function deleteSessionDatabase(dbManager, sessionId) {
46
38
  dbManager.deleteSessionDatabaseFiles(sessionId);
47
39
  }
48
40
  async function streamImport(dbManager, filePath, options) {
49
- const { formatId, chatIndex, onProgress } = options || {};
41
+ const { formatId, chatIndex, onProgress, sessionId } = options || {};
50
42
  const formatOptions = {};
51
43
  if (formatId) formatOptions.formatId = formatId;
52
44
  if (chatIndex !== void 0) formatOptions.chatIndex = chatIndex;
@@ -87,7 +79,7 @@ async function streamImport(dbManager, filePath, options) {
87
79
  } : () => {
88
80
  };
89
81
  const deps = buildStreamImportDeps(dbManager, progressAdapter);
90
- const result = await streamingImport(filePath, deps, formatOptions);
82
+ const result = await streamingImport(filePath, deps, formatOptions, sessionId);
91
83
  if (!result.success || !result.sessionId) return result;
92
84
  try {
93
85
  dbManager.raiseCurrentChatDbCompatibilityGate();
@@ -112,13 +104,7 @@ function buildIncrementalDeps(dbManager, onProgress, onCompatibilityError) {
112
104
  }
113
105
  },
114
106
  onProgress: onProgress ?? (() => {
115
- }),
116
- postImportHook(db) {
117
- try {
118
- generateIncrementalSessionIndex(db);
119
- } catch {
120
- }
121
- }
107
+ })
122
108
  };
123
109
  }
124
110
  async function incrementalImport2(dbManager, sessionId, filePath, options) {
@@ -169,4 +155,4 @@ export {
169
155
  analyzeIncrementalImport2 as analyzeIncrementalImport,
170
156
  analyzeNewImport2 as analyzeNewImport
171
157
  };
172
- //# sourceMappingURL=chunk-ZSFVX6FM.mjs.map
158
+ //# sourceMappingURL=chunk-I35WHWA6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/import/stream-import.ts"],"sourcesContent":["/**\n * Server/CLI streaming import — adapter for @openchatlab/node-runtime StreamingImporter.\n *\n * Replaces the old buffered-in-memory approach with the same high-performance\n * streaming pipeline used by Electron (batched transactions, deferred indexes,\n * nickname history, FTS, format fallback).\n */\n\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport {\n DataDirCompatibilityError,\n streamingImport,\n analyzeNewImport as sharedAnalyzeNewImport,\n analyzeIncrementalImport as sharedAnalyzeIncremental,\n incrementalImport as sharedIncrementalImport,\n} from '@openchatlab/node-runtime'\nimport type {\n StreamImportResult,\n StreamImportDeps,\n ImportProgressCallback,\n IncrementalImportResult,\n IncrementalAnalyzeResult,\n IncrementalImportDeps,\n ImportOptions,\n AnalyzeNewImportResult,\n} from '@openchatlab/node-runtime'\nimport {\n detectFormat as parserDetectFormat,\n detectAllFormats,\n getFormatFeatureById,\n getSupportedFormats as parserGetSupportedFormats,\n scanMultiChatFile as parserScanMultiChatFile,\n findEntryFileInDirectory,\n type FormatFeature,\n type MultiChatInfo,\n type ParseProgress,\n} from '@openchatlab/parser'\nimport * as crypto from 'crypto'\n\n// ==================== Legacy progress interface (for SSE routes) ====================\n\nexport interface StreamImportProgress {\n stage: 'detecting' | 'parsing' | 'saving' | 'indexing' | 'done' | 'error'\n progress: number\n message: string\n bytesRead?: number\n totalBytes?: number\n messagesProcessed?: number\n}\n\nexport interface StreamImportOptions {\n formatId?: string\n chatIndex?: number\n nativeBinding?: string\n onProgress?: (progress: StreamImportProgress) => void\n /** Fix the target session ID instead of auto-generating one. Used by sync/pull adapters. */\n sessionId?: string\n}\n\nfunction generateSessionId(): string {\n const ts = Date.now()\n const rand = crypto.randomBytes(4).toString('hex')\n return `chat_${ts}_${rand}`\n}\n\nfunction buildStreamImportDeps(dbManager: DatabaseManager, onProgress?: ImportProgressCallback): StreamImportDeps {\n return {\n openDatabase(sessionId: string) {\n return dbManager.openRawSessionDatabase(sessionId, { create: true, initializeChatTables: true })\n },\n deleteDatabase(sessionId: string) {\n dbManager.deleteSessionDatabaseFiles(sessionId)\n },\n onProgress: onProgress ?? (() => {}),\n generateSessionId,\n }\n}\n\nfunction deleteSessionDatabase(dbManager: DatabaseManager, sessionId: string): void {\n dbManager.deleteSessionDatabaseFiles(sessionId)\n}\n\n/**\n * High-performance streaming import: parse a file and write to DB\n * with batched transactions, deferred indexes, and FTS.\n */\nexport async function streamImport(\n dbManager: DatabaseManager,\n filePath: string,\n options?: StreamImportOptions\n): Promise<StreamImportResult> {\n const { formatId, chatIndex, onProgress, sessionId } = options || {}\n\n const formatOptions: Record<string, unknown> = {}\n if (formatId) formatOptions.formatId = formatId\n if (chatIndex !== undefined) formatOptions.chatIndex = chatIndex\n\n const progressAdapter: ImportProgressCallback = onProgress\n ? (progress) => {\n let stage: StreamImportProgress['stage'] = 'parsing'\n let pct = 0\n switch (progress.stage) {\n case 'detecting':\n stage = 'detecting'\n pct = 5\n break\n case 'parsing':\n stage = 'parsing'\n pct = Math.min(Math.round(progress.percentage * 0.7), 70)\n break\n case 'importing':\n case 'saving':\n stage = 'saving'\n pct = 80\n break\n case 'done':\n stage = 'done'\n pct = 100\n break\n case 'error':\n stage = 'error'\n pct = 0\n break\n }\n onProgress({\n stage,\n progress: pct,\n message: progress.message || '',\n bytesRead: progress.bytesRead,\n totalBytes: progress.totalBytes,\n messagesProcessed: progress.messagesProcessed,\n })\n }\n : () => {}\n\n const deps = buildStreamImportDeps(dbManager, progressAdapter)\n const result = await streamingImport(filePath, deps, formatOptions, sessionId)\n if (!result.success || !result.sessionId) return result\n\n try {\n dbManager.raiseCurrentChatDbCompatibilityGate()\n } catch (error) {\n deleteSessionDatabase(dbManager, result.sessionId)\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n diagnostics: result.diagnostics,\n }\n }\n\n return result\n}\n\n// ==================== Incremental import ====================\n\nfunction buildIncrementalDeps(\n dbManager: DatabaseManager,\n onProgress?: ImportProgressCallback,\n onCompatibilityError?: (error: DataDirCompatibilityError) => void\n): IncrementalImportDeps {\n return {\n openDatabase(sessionId: string, readonly?: boolean) {\n try {\n return dbManager.openRawSessionDatabase(sessionId, { readonly: readonly ?? false })\n } catch (error) {\n if (error instanceof DataDirCompatibilityError) onCompatibilityError?.(error)\n throw error\n }\n },\n onProgress: onProgress ?? (() => {}),\n }\n}\n\nexport async function incrementalImport(\n dbManager: DatabaseManager,\n sessionId: string,\n filePath: string,\n options?: ImportOptions & { onProgress?: ImportProgressCallback }\n): Promise<IncrementalImportResult> {\n const { onProgress, ...importOpts } = options || {}\n let compatibilityError: DataDirCompatibilityError | null = null\n const result = await sharedIncrementalImport(\n sessionId,\n filePath,\n buildIncrementalDeps(dbManager, onProgress, (error) => {\n compatibilityError = error\n }),\n importOpts\n )\n if (compatibilityError) throw compatibilityError\n if (!result.success) return result\n\n try {\n dbManager.raiseCurrentChatDbCompatibilityGate()\n } catch (error) {\n return {\n ...result,\n success: false,\n newMessageCount: 0,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n\n return result\n}\n\nexport async function analyzeIncrementalImport(\n dbManager: DatabaseManager,\n sessionId: string,\n filePath: string,\n onProgress?: ImportProgressCallback\n): Promise<IncrementalAnalyzeResult> {\n let compatibilityError: DataDirCompatibilityError | null = null\n const result = await sharedAnalyzeIncremental(\n sessionId,\n filePath,\n buildIncrementalDeps(dbManager, onProgress, (error) => {\n compatibilityError = error\n })\n )\n if (compatibilityError) throw compatibilityError\n return result\n}\n\nexport async function analyzeNewImport(\n filePath: string,\n onProgress?: ImportProgressCallback\n): Promise<AnalyzeNewImportResult> {\n return sharedAnalyzeNewImport(filePath, onProgress ?? (() => {}))\n}\n\n// ==================== Re-exports from parser ====================\n\nexport {\n parserDetectFormat as detectFormat,\n detectAllFormats,\n getFormatFeatureById,\n parserGetSupportedFormats as getSupportedFormats,\n parserScanMultiChatFile as scanMultiChatFile,\n findEntryFileInDirectory,\n}\nexport type { FormatFeature, MultiChatInfo, ParseProgress }\nexport type {\n StreamImportResult,\n IncrementalImportResult,\n IncrementalAnalyzeResult,\n AnalyzeNewImportResult,\n ImportOptions,\n}\n"],"mappings":"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","names":["incrementalImport","analyzeIncrementalImport","analyzeNewImport"]}
@@ -4,76 +4,54 @@ import { fileURLToPath as __fileURLToPath } from 'url';
4
4
  const require = __createRequire(import.meta.url);
5
5
  const __filename = __fileURLToPath(import.meta.url);
6
6
  const __dirname = __pathDirname(__filename);
7
+ import {
8
+ analyzeIncrementalImport,
9
+ analyzeNewImport,
10
+ incrementalImport,
11
+ streamImport
12
+ } from "./chunk-I35WHWA6.mjs";
7
13
  import {
8
14
  closeServerAiLogger,
9
15
  createCliRunAgentStream,
10
16
  initServerAiLogger
11
- } from "./chunk-XNU5X7EV.mjs";
17
+ } from "./chunk-SKUG5XVD.mjs";
12
18
  import {
13
19
  AGENT_TOOL_REGISTRY,
14
20
  CoreDataProvider
15
- } from "./chunk-VASK54KT.mjs";
21
+ } from "./chunk-CIB23U32.mjs";
16
22
  import {
17
23
  assertCliDataDirCompatible
18
- } from "./chunk-WGS33EWH.mjs";
24
+ } from "./chunk-6FPEP2ZX.mjs";
19
25
  import {
20
26
  getVersion
21
27
  } from "./chunk-5ADKYYNA.mjs";
22
28
  import {
23
29
  resolveCliPath
24
30
  } from "./chunk-FJ35V3TE.mjs";
25
- import {
26
- importData,
27
- parseFile
28
- } from "./chunk-YZDEZ6UI.mjs";
29
- import {
30
- analyzeIncrementalImport,
31
- analyzeNewImport,
32
- incrementalImport,
33
- streamImport
34
- } from "./chunk-ZSFVX6FM.mjs";
35
31
  import {
36
32
  AnalyticsService,
37
- ArchiveImportError,
38
- ArchiveImportSourceManager,
39
33
  NodePathProvider,
40
34
  PreferencesManager,
41
- appLogger,
42
35
  applyPendingNodeDataDirMigrationIfNeeded,
43
36
  buildMergedOutput,
44
37
  checkConflictsFromSources,
45
38
  createJiebaNlpProvider,
46
39
  createNodeDataDirSwitch,
47
40
  createSemanticIndexWorkerRuntimeClient,
48
- detectAllFormats,
49
- detectFormat,
50
- findEntryFileInDirectory,
51
- getDbFileVersion,
52
41
  getDefaultNodeUserDataDir,
53
- getOrComputeAnalysisCache,
54
42
  getPendingNodeDataDirMigration,
55
- getSupportedFormats,
56
43
  hasPendingElectronDataWarning,
57
- initAppLogger,
58
- scanMultiChatFile,
59
- serializeChatLabToJsonl,
60
- streamParseFileInfo
61
- } from "./chunk-GPF34WXV.mjs";
44
+ serializeChatLabToJsonl
45
+ } from "./chunk-7RW4CQAO.mjs";
62
46
  import {
63
47
  AIChatManager,
64
- ALL_MIGRATIONS,
48
+ ArchiveImportError,
49
+ ArchiveImportSourceManager,
65
50
  AssistantManager,
66
- BUILTIN_MODELS,
67
- BUILTIN_PROVIDERS,
68
- BUILTIN_TOOL_CATALOG,
69
51
  CustomModelStore,
70
52
  CustomProviderStore,
71
- DataDirCompatibilityError,
72
- DatabaseManager,
73
53
  LLMConfigStore,
74
54
  MergeSessionCache,
75
- MigrationRunner,
76
- POS_TAG_DEFINITIONS,
77
55
  SEMANTIC_INDEX_CONFIG_FILE,
78
56
  SemanticIndexConfigStore,
79
57
  SkillManagerCore,
@@ -81,28 +59,64 @@ import {
81
59
  buildPiModel,
82
60
  computeWordFrequency,
83
61
  countMessagesTokens,
84
- createDatabaseManagerAdapter,
85
- deleteAuthProfile,
62
+ createContactsService,
63
+ createPeopleRelationshipsService,
86
64
  deleteDict,
65
+ detectAllFormats,
66
+ detectFormat,
87
67
  downloadDict,
88
68
  ensureDefaultDict,
89
- executeReadonlySql,
90
- executeSql,
91
69
  exportSessionToJson,
92
70
  export_service_exports,
93
71
  fetchRemoteModels,
72
+ findEntryFileInDirectory,
73
+ getDefaultRulesForLocale,
74
+ getDictList,
75
+ getSupportedFormats,
76
+ isDictDownloaded,
77
+ isSemanticIndexConfigured,
78
+ member_service_exports,
79
+ mergeRulesForLocale,
80
+ owner_profile_service_exports,
81
+ persistSemanticIndexConfig,
82
+ pushImport,
83
+ resolveSemanticIndexApiKeySet,
84
+ runSimpleLlmStream,
85
+ scanMultiChatFile,
86
+ segmentText,
87
+ session_index_service_exports,
88
+ session_service_exports,
89
+ streamParseFileInfo,
90
+ summary_service_exports,
91
+ validateApiKey
92
+ } from "./chunk-QQK7MLCR.mjs";
93
+ import {
94
+ ALL_MIGRATIONS,
95
+ BUILTIN_MODELS,
96
+ BUILTIN_PROVIDERS,
97
+ BUILTIN_TOOL_CATALOG,
98
+ CONTACTS_TIME_RANGE_PRESETS,
99
+ DataDirCompatibilityError,
100
+ DatabaseManager,
101
+ MigrationRunner,
102
+ POS_TAG_DEFINITIONS,
103
+ appLogger,
104
+ createDatabaseManagerAdapter,
105
+ deleteAuthProfile,
106
+ executeReadonlySql,
107
+ executeSql,
94
108
  getAvailableYears,
95
109
  getBuiltinModelsByProvider,
96
110
  getCatchphraseAnalysis,
97
111
  getCheckInAnalysis,
98
112
  getClusterGraph,
99
113
  getDailyActivity,
100
- getDefaultRulesForLocale,
101
- getDictList,
114
+ getDbFileVersion,
102
115
  getDivingAnalysis,
103
116
  getDragonKingAnalysis,
104
117
  getHourlyActivity,
105
118
  getLanguagePreferenceAnalysis,
119
+ getLastPlatformMessageId,
106
120
  getLaughAnalysis,
107
121
  getLongMessageCount,
108
122
  getMemberActivity,
@@ -116,6 +130,7 @@ import {
116
130
  getMessageTypeStats,
117
131
  getMonthlyActivity,
118
132
  getNightOwlAnalysis,
133
+ getOrComputeAnalysisCache,
119
134
  getRelationshipStats,
120
135
  getRepeatAnalysis,
121
136
  getSchemaDetailed,
@@ -127,29 +142,17 @@ import {
127
142
  getTimeRange,
128
143
  getWeekdayActivity,
129
144
  getYearlyActivity,
145
+ initAppLogger,
130
146
  initNlpDir,
131
- isDictDownloaded,
132
147
  isNewerStableVersion,
133
- isSemanticIndexConfigured,
134
148
  loadConfig,
135
- member_service_exports,
136
- mergeRulesForLocale,
137
- owner_profile_service_exports,
138
- persistSemanticIndexConfig,
139
149
  queryMessages,
140
150
  resolveApiKey,
141
- resolveSemanticIndexApiKeySet,
142
- runSimpleLlmStream,
143
- segmentText,
144
- session_index_service_exports,
145
- session_service_exports,
146
151
  stripAvatarFields,
147
- summary_service_exports,
148
- validateApiKey,
149
152
  verifyCliDataPath,
150
153
  writeAuthProfile,
151
154
  writeConfigField
152
- } from "./chunk-55WR6WKW.mjs";
155
+ } from "./chunk-WPI6YSAR.mjs";
153
156
 
154
157
  // src/http/index.ts
155
158
  import * as fs11 from "fs";
@@ -168,6 +171,8 @@ var HTTP_STATUS = {
168
171
  ["SQL_EXECUTION_ERROR" /* SQL_EXECUTION_ERROR */]: 400,
169
172
  ["EXPORT_TOO_LARGE" /* EXPORT_TOO_LARGE */]: 400,
170
173
  ["BODY_TOO_LARGE" /* BODY_TOO_LARGE */]: 413,
174
+ ["IMPORT_IN_PROGRESS" /* IMPORT_IN_PROGRESS */]: 409,
175
+ ["IMPORT_FAILED" /* IMPORT_FAILED */]: 500,
171
176
  ["DATA_DIR_INCOMPATIBLE" /* DATA_DIR_INCOMPATIBLE */]: 409,
172
177
  ["SERVER_ERROR" /* SERVER_ERROR */]: 500
173
178
  };
@@ -187,6 +192,9 @@ function unauthorized(message = "Invalid or missing token") {
187
192
  function sessionNotFound(id) {
188
193
  return new ApiError("SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */, `Session not found: ${id}`);
189
194
  }
195
+ function invalidPayload(message) {
196
+ return new ApiError("INVALID_PAYLOAD" /* INVALID_PAYLOAD */, message);
197
+ }
190
198
  function sqlExecutionError(message) {
191
199
  return new ApiError("SQL_EXECUTION_ERROR" /* SQL_EXECUTION_ERROR */, message);
192
200
  }
@@ -199,6 +207,12 @@ function exportTooLarge(count, limit) {
199
207
  function serverError(message = "Internal server error") {
200
208
  return new ApiError("SERVER_ERROR" /* SERVER_ERROR */, message);
201
209
  }
210
+ function importInProgress() {
211
+ return new ApiError("IMPORT_IN_PROGRESS" /* IMPORT_IN_PROGRESS */, "Another import is already in progress");
212
+ }
213
+ function importFailed(message) {
214
+ return new ApiError("IMPORT_FAILED" /* IMPORT_FAILED */, message);
215
+ }
202
216
  function dataDirIncompatible(message) {
203
217
  return new ApiError("DATA_DIR_INCOMPATIBLE" /* DATA_DIR_INCOMPATIBLE */, message);
204
218
  }
@@ -347,7 +361,9 @@ function registerRestSessionRoutes(server2, ctx) {
347
361
  messageCount: info.messageCount,
348
362
  memberCount: info.memberCount,
349
363
  firstTimestamp: info.firstMessageTs,
350
- lastTimestamp: info.lastMessageTs
364
+ lastTimestamp: info.lastMessageTs,
365
+ lastPlatformMessageId: getLastPlatformMessageId(db),
366
+ importedAt: info.importedAt
351
367
  });
352
368
  });
353
369
  server2.get("/api/v1/sessions/:id/messages", async (request) => {
@@ -468,6 +484,39 @@ function registerRestSessionRoutes(server2, ctx) {
468
484
  });
469
485
  }
470
486
 
487
+ // ../../packages/http-routes/src/routes/imports.ts
488
+ function registerImportRoutes(server2, ctx) {
489
+ server2.post(
490
+ "/api/v1/imports/:sessionId",
491
+ async (request, reply) => {
492
+ const { sessionId } = request.params;
493
+ const contentType = request.headers["content-type"] || "";
494
+ if (!contentType.includes("application/json")) {
495
+ const err = invalidPayload("Content-Type must be application/json (JSONL is not yet supported)");
496
+ return reply.code(err.statusCode).send(errorResponse(err));
497
+ }
498
+ if (request.headers["x-dry-run"] === "true") {
499
+ const err = invalidPayload("X-Dry-Run is not yet supported");
500
+ return reply.code(err.statusCode).send(errorResponse(err));
501
+ }
502
+ const outcome = await pushImport(ctx.dbManager, sessionId, request.body ?? {});
503
+ if (!outcome.ok) {
504
+ if (outcome.reason === "import_in_progress") {
505
+ const err2 = importInProgress();
506
+ return reply.code(err2.statusCode).send(errorResponse(err2));
507
+ }
508
+ if (outcome.reason === "invalid_payload") {
509
+ const err2 = invalidPayload(outcome.message);
510
+ return reply.code(err2.statusCode).send(errorResponse(err2));
511
+ }
512
+ const err = importFailed(outcome.message);
513
+ return reply.code(err.statusCode).send(errorResponse(err));
514
+ }
515
+ return successResponse(outcome.result);
516
+ }
517
+ );
518
+ }
519
+
471
520
  // ../../packages/http-routes/src/routes/web/sessions.ts
472
521
  function registerSessionRoutes(server2, ctx) {
473
522
  const { sessionAdapter: adapter } = ctx;
@@ -582,6 +631,121 @@ function registerMemberRoutes(server2, ctx) {
582
631
  );
583
632
  }
584
633
 
634
+ // ../../packages/http-routes/src/routes/web/contacts.ts
635
+ function registerContactsRoutes(server2, ctx) {
636
+ const service = ctx.contactsService ?? createContactsService({
637
+ adapter: ctx.sessionAdapter,
638
+ pathProvider: ctx.pathProvider,
639
+ runtimeIdentity: ctx.runtimeIdentity,
640
+ nativeBinding: ctx.nativeBinding
641
+ });
642
+ server2.addHook("onClose", async () => {
643
+ await service.close();
644
+ });
645
+ server2.get("/_web/contacts", async (request) => {
646
+ return service.getContactsPage({
647
+ acceptStale: isTruthy(request.query.acceptStale),
648
+ timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),
649
+ pool: parseContactPool(request.query.pool),
650
+ page: parsePositiveInteger(request.query.page),
651
+ pageSize: parsePositiveInteger(request.query.pageSize),
652
+ query: request.query.q
653
+ });
654
+ });
655
+ server2.post("/_web/contacts/recompute", async (request) => {
656
+ return service.startRecompute({
657
+ timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),
658
+ pool: parseContactPool(request.query.pool),
659
+ page: parsePositiveInteger(request.query.page),
660
+ pageSize: parsePositiveInteger(request.query.pageSize),
661
+ query: request.query.q
662
+ });
663
+ });
664
+ server2.get("/_web/contacts/:key/detail", async (request) => {
665
+ return service.getContactDetail(request.params.key, {
666
+ acceptStale: isTruthy(request.query.acceptStale),
667
+ timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange)
668
+ });
669
+ });
670
+ server2.put(
671
+ "/_web/contacts/:key/mark-friend",
672
+ async (request) => {
673
+ return service.markContactAsFriend(request.params.key, {
674
+ timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange)
675
+ });
676
+ }
677
+ );
678
+ server2.delete(
679
+ "/_web/contacts/:key/mark-friend",
680
+ async (request) => {
681
+ return service.unmarkContactAsFriend(request.params.key, {
682
+ timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange)
683
+ });
684
+ }
685
+ );
686
+ }
687
+ function isTruthy(value) {
688
+ return value === "1" || value === "true" || value === "yes";
689
+ }
690
+ function parseContactsTimeRangePreset(value) {
691
+ return CONTACTS_TIME_RANGE_PRESETS.includes(value) ? value : "1y";
692
+ }
693
+ function parseContactPool(value) {
694
+ return value === "friend" || value === "non_friend" ? value : void 0;
695
+ }
696
+ function parsePositiveInteger(value) {
697
+ if (!value) return void 0;
698
+ const parsed = Number(value);
699
+ if (!Number.isFinite(parsed)) return void 0;
700
+ return Math.max(1, Math.trunc(parsed));
701
+ }
702
+
703
+ // ../../packages/http-routes/src/routes/web/people-relationships.ts
704
+ function registerPeopleRelationshipsRoutes(server2, ctx) {
705
+ const service = ctx.peopleRelationshipsService ?? createPeopleRelationshipsService({
706
+ adapter: ctx.sessionAdapter,
707
+ pathProvider: ctx.pathProvider,
708
+ runtimeIdentity: ctx.runtimeIdentity,
709
+ nativeBinding: ctx.nativeBinding
710
+ });
711
+ server2.addHook("onClose", async () => {
712
+ await service.close();
713
+ });
714
+ server2.get("/_web/people/relationships", async (request) => {
715
+ return service.getGraph({
716
+ acceptStale: isTruthy2(request.query.acceptStale),
717
+ timeRangePreset: parseContactsTimeRangePreset2(request.query.timeRange),
718
+ graphScope: parsePeopleRelationshipsGraphScope(request.query.scope),
719
+ query: request.query.q
720
+ });
721
+ });
722
+ server2.post("/_web/people/relationships/recompute", async (request) => {
723
+ return service.startRecompute({
724
+ timeRangePreset: parseContactsTimeRangePreset2(request.query.timeRange),
725
+ graphScope: parsePeopleRelationshipsGraphScope(request.query.scope),
726
+ query: request.query.q
727
+ });
728
+ });
729
+ server2.get(
730
+ "/_web/people/relationships/:key/neighborhood",
731
+ async (request) => {
732
+ return service.getNeighborhood(request.params.key, {
733
+ acceptStale: isTruthy2(request.query.acceptStale),
734
+ timeRangePreset: parseContactsTimeRangePreset2(request.query.timeRange)
735
+ });
736
+ }
737
+ );
738
+ }
739
+ function isTruthy2(value) {
740
+ return value === "1" || value === "true" || value === "yes";
741
+ }
742
+ function parseContactsTimeRangePreset2(value) {
743
+ return CONTACTS_TIME_RANGE_PRESETS.includes(value) ? value : "1y";
744
+ }
745
+ function parsePeopleRelationshipsGraphScope(value) {
746
+ return value === "close" || value === "friends" ? value : "panorama";
747
+ }
748
+
585
749
  // ../../packages/http-routes/src/routes/web/preferences.ts
586
750
  function registerPreferencesRoutes(server2, ctx) {
587
751
  const prefManager = ctx.preferencesManager ?? new PreferencesManager(ctx.pathProvider.getSystemDir());
@@ -2187,8 +2351,11 @@ function registerSharedRoutes(server2, ctx, options) {
2187
2351
  const resolvedCtx = ctx.preferencesManager ? ctx : { ...ctx, preferencesManager: new PreferencesManager(ctx.pathProvider.getSystemDir()) };
2188
2352
  registerSystemRoutes(server2, resolvedCtx);
2189
2353
  registerRestSessionRoutes(server2, resolvedCtx);
2354
+ registerImportRoutes(server2, resolvedCtx);
2190
2355
  registerSessionRoutes(server2, resolvedCtx);
2191
2356
  registerMemberRoutes(server2, resolvedCtx);
2357
+ registerContactsRoutes(server2, resolvedCtx);
2358
+ registerPeopleRelationshipsRoutes(server2, resolvedCtx);
2192
2359
  registerPreferencesRoutes(server2, resolvedCtx);
2193
2360
  registerAnalyticsRoutes(server2, resolvedCtx);
2194
2361
  registerSqlRoutes(server2, resolvedCtx);
@@ -2334,7 +2501,7 @@ function cleanupTemp(...paths) {
2334
2501
  }
2335
2502
  }
2336
2503
  }
2337
- function registerImportRoutes(server2, dbManager2, options = {}) {
2504
+ function registerImportRoutes2(server2, dbManager2, options = {}) {
2338
2505
  const sourceManager = options.sourceManager ?? new ArchiveImportSourceManager({
2339
2506
  tempRoot: fs6.mkdtempSync(path7.join(os2.tmpdir(), "chatlab-import-sources-"))
2340
2507
  });
@@ -2785,7 +2952,7 @@ function registerWebRoutes(server2, dbManager2, options) {
2785
2952
  const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider;
2786
2953
  const ai = options?.aiContext;
2787
2954
  const cliStreamImport = async (dm, filePath) => {
2788
- const { streamImport: streamImport2 } = await import("./stream-import-37U3SROO.mjs");
2955
+ const { streamImport: streamImport2 } = await import("./stream-import-7HZ4IRYJ.mjs");
2789
2956
  const result = await streamImport2(dm, filePath);
2790
2957
  if (!result.sessionId) throw new Error("Import succeeded but no sessionId returned");
2791
2958
  return { sessionId: result.sessionId };
@@ -2800,6 +2967,7 @@ function registerWebRoutes(server2, dbManager2, options) {
2800
2967
  dbManager: dbManager2,
2801
2968
  sessionAdapter: adapter,
2802
2969
  pathProvider: resolvedPathProvider,
2970
+ runtimeIdentity: options?.runtimeIdentity,
2803
2971
  getVersion,
2804
2972
  nativeBinding: options?.nativeBinding,
2805
2973
  semanticIndexService,
@@ -2836,7 +3004,7 @@ function registerWebRoutes(server2, dbManager2, options) {
2836
3004
  },
2837
3005
  ai ? { requireAi: true } : void 0
2838
3006
  );
2839
- registerImportRoutes(server2, dbManager2);
3007
+ registerImportRoutes2(server2, dbManager2);
2840
3008
  server2.get("/_web/system/check-update", async () => {
2841
3009
  const currentVersion = getVersion();
2842
3010
  try {
@@ -3287,7 +3455,8 @@ var PullEngine = class {
3287
3455
  this.logger.info(`[Pull] Skipping "${sess.name}": session no longer exists`);
3288
3456
  return { success: true, newMessageCount: 0 };
3289
3457
  }
3290
- if (this.isImporting()) {
3458
+ const importStatusSessionId = sess.targetSessionId || deriveLocalSessionId(ds.baseUrl, sess.remoteSessionId);
3459
+ if (this.isImporting(importStatusSessionId)) {
3291
3460
  this.logger.info(`[Pull] Skipping "${sess.name}": import in progress`);
3292
3461
  return { success: false, newMessageCount: 0, error: "Import in progress" };
3293
3462
  }
@@ -3704,22 +3873,17 @@ var DirectImporter = class {
3704
3873
  }
3705
3874
  async incrementalImportFile(sessionId, tempFile) {
3706
3875
  try {
3707
- const data = await parseFile(tempFile);
3708
3876
  this.dbManager.close(sessionId);
3709
- const result = await importData(this.dbManager, data, {
3710
- sessionId
3711
- });
3877
+ const result = await incrementalImport(this.dbManager, sessionId, tempFile);
3712
3878
  if (result.success) {
3879
+ const newMessageCount = result.newMessageCount;
3880
+ const duplicateCount = result.batch?.duplicateCount ?? 0;
3713
3881
  this.logger.info(
3714
- `[DirectImporter] Incremental OK: +${result.messageCount} messages (${result.duplicateCount} duplicates skipped)`
3882
+ `[DirectImporter] Incremental OK: +${newMessageCount} messages (${duplicateCount} duplicates skipped)`
3715
3883
  );
3716
- return {
3717
- success: true,
3718
- newMessageCount: result.messageCount,
3719
- sessionId
3720
- };
3884
+ return { success: true, newMessageCount, sessionId };
3721
3885
  }
3722
- if (result.error?.includes("not found") || result.error?.includes("session_not_found") || result.error?.includes("no such table")) {
3886
+ if (result.error === "error.session_not_found" || result.error?.includes("no such table")) {
3723
3887
  return { success: false, newMessageCount: 0, sessionId, needFullResync: true };
3724
3888
  }
3725
3889
  return { success: false, newMessageCount: 0, sessionId, error: result.error };
@@ -3730,15 +3894,11 @@ var DirectImporter = class {
3730
3894
  }
3731
3895
  async fullImportFile(tempFile, externalId) {
3732
3896
  try {
3733
- const data = await parseFile(tempFile);
3734
- const result = await importData(this.dbManager, data, {
3735
- sessionId: externalId
3736
- });
3897
+ const result = await streamImport(this.dbManager, tempFile, { sessionId: externalId });
3737
3898
  if (result.success) {
3738
- this.logger.info(
3739
- `[DirectImporter] Full import OK: ${result.messageCount} messages, ${result.memberCount} members`
3740
- );
3741
- return { success: true, newMessageCount: result.messageCount, sessionId: externalId };
3899
+ const newMessageCount = result.diagnostics?.messagesWritten ?? 0;
3900
+ this.logger.info(`[DirectImporter] Full import OK: +${newMessageCount} messages`);
3901
+ return { success: true, newMessageCount, sessionId: result.sessionId ?? externalId };
3742
3902
  }
3743
3903
  return { success: false, newMessageCount: 0, error: result.error };
3744
3904
  } catch (err) {
@@ -3998,6 +4158,7 @@ async function startHttpServer(options) {
3998
4158
  registerWebRoutes(server, dbManager, {
3999
4159
  pathProvider,
4000
4160
  nativeBinding,
4161
+ runtimeIdentity: runtime,
4001
4162
  semanticIndexService,
4002
4163
  aiContext: {
4003
4164
  aiDataDir,
@@ -4052,4 +4213,4 @@ export {
4052
4213
  startHttpServer,
4053
4214
  stopHttpServer
4054
4215
  };
4055
- //# sourceMappingURL=chunk-YQ2FJGBT.mjs.map
4216
+ //# sourceMappingURL=chunk-KL2NGIMQ.mjs.map