chatlab-cli 0.37.1 → 0.37.3

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 (153) hide show
  1. package/dist/{chat-command-YAFRLHMQ.mjs → chat-command-RQC44FPF.mjs} +53 -13
  2. package/dist/chat-command-RQC44FPF.mjs.map +1 -0
  3. package/dist/{chunk-FPVRSXQ4.mjs → chunk-4FAEB4C2.mjs} +12 -12
  4. package/dist/{chunk-MMTEGUQA.mjs → chunk-5OA4QI3Q.mjs} +3 -3
  5. package/dist/{chunk-UP6JIV3S.mjs → chunk-E2ZFGNZQ.mjs} +16 -12
  6. package/dist/chunk-E2ZFGNZQ.mjs.map +1 -0
  7. package/dist/{chunk-JWJREWVN.mjs → chunk-E6IRRNBQ.mjs} +27 -3
  8. package/dist/chunk-E6IRRNBQ.mjs.map +1 -0
  9. package/dist/{chunk-PDQV4RUA.mjs → chunk-GDKQKHJT.mjs} +2 -2
  10. package/dist/{chunk-GKCIRKOH.mjs → chunk-HJWBFHNR.mjs} +4 -4
  11. package/dist/{chunk-73TJ2S7W.mjs → chunk-IDDTW5JN.mjs} +313 -24
  12. package/dist/chunk-IDDTW5JN.mjs.map +1 -0
  13. package/dist/{chunk-2PY4XCH3.mjs → chunk-IMJVOODY.mjs} +2 -2
  14. package/dist/{chunk-ARIBCH47.mjs → chunk-LUENE6L7.mjs} +25 -15
  15. package/dist/chunk-LUENE6L7.mjs.map +1 -0
  16. package/dist/{chunk-WDLO7OLX.mjs → chunk-O57SQSCO.mjs} +2 -2
  17. package/dist/{chunk-N4SB6QZV.mjs → chunk-ZGXXAPLX.mjs} +2 -2
  18. package/dist/{chunk-OTYNMDDL.mjs → chunk-ZOHSWBD2.mjs} +2237 -1977
  19. package/dist/chunk-ZOHSWBD2.mjs.map +1 -0
  20. package/dist/cli.mjs +9 -9
  21. package/dist/contacts-worker.mjs +2 -2
  22. package/dist/global-insight-worker.mjs +1 -1
  23. package/dist/{http-LPFPVTBC.mjs → http-QJDZKDNJ.mjs} +12 -12
  24. package/dist/{import-T4WX2ZJL.mjs → import-XK6YM26A.mjs} +7 -7
  25. package/dist/index.mjs +12 -12
  26. package/dist/{mcp-SMF3NWIN.mjs → mcp-DMGZFSYN.mjs} +24 -17
  27. package/dist/mcp-DMGZFSYN.mjs.map +1 -0
  28. package/dist/people-relationships-worker.mjs +2 -2
  29. package/dist/semantic-index-worker.mjs +1 -1
  30. package/dist/{src-EGLLMTAU.mjs → src-4AHJUFCW.mjs} +6 -6
  31. package/dist/{stream-import-2BXJTTCE.mjs → stream-import-7VQVT5ST.mjs} +7 -7
  32. package/dist/{worker-runtime-RDLSPXFT.mjs → worker-runtime-PQBAV75N.mjs} +5 -5
  33. package/dist-cli-web/assets/{AISettingsTab-CEhrXlYR.js → AISettingsTab-qS3XKnvh.js} +1 -1
  34. package/dist-cli-web/assets/{AboutTab-Bbu0SsMM.js → AboutTab-K-i40dPv.js} +1 -1
  35. package/dist-cli-web/assets/{Alert-510jTN3l.js → Alert-GSvA5B7J.js} +1 -1
  36. package/dist-cli-web/assets/{ApiSettingsTab-Bi1GRMN4.js → ApiSettingsTab-DIVGTR3g.js} +1 -1
  37. package/dist-cli-web/assets/{BatchManageTab-DhnqMCSM.js → BatchManageTab-CJhwvYWV.js} +1 -1
  38. package/dist-cli-web/assets/{BufferResource-CKZxnACp.js → BufferResource-Cjm0m7sF.js} +1 -1
  39. package/dist-cli-web/assets/{CanvasRenderer-BeK5POBy.js → CanvasRenderer-C-fmrahh.js} +1 -1
  40. package/dist-cli-web/assets/{CardDecoration-RuBA3N2j.js → CardDecoration-Cz54ZPyh.js} +1 -1
  41. package/dist-cli-web/assets/{ChatRecordDrawer-BY_-lIEj.js → ChatRecordDrawer-Cst8zTUv.js} +1 -1
  42. package/dist-cli-web/assets/{ChatRecordWorkspace-7prKd-Tq.js → ChatRecordWorkspace-DKVKaimw.js} +1 -1
  43. package/dist-cli-web/assets/{Checkbox-_eH64bb0.js → Checkbox-CrlY3jiJ.js} +1 -1
  44. package/dist-cli-web/assets/{DataDirCleanupNotice-BHaXwlfr.js → DataDirCleanupNotice-Cjqiub4e.js} +1 -1
  45. package/dist-cli-web/assets/{DatePicker.vue_vue_type_script_setup_true_lang-D9Ul_GYz.js → DatePicker.vue_vue_type_script_setup_true_lang-BYY2UmPA.js} +1 -1
  46. package/dist-cli-web/assets/{DebugToolsPanel-ByKItGrS.js → DebugToolsPanel-I00RV_Lr.js} +1 -1
  47. package/dist-cli-web/assets/{EChart.vue_vue_type_script_setup_true_lang-DubnuUXI.js → EChart.vue_vue_type_script_setup_true_lang-CRTZh9kh.js} +1 -1
  48. package/dist-cli-web/assets/{EChartBar.vue_vue_type_script_setup_true_lang-DKNCZuFm.js → EChartBar.vue_vue_type_script_setup_true_lang-DjDFhnN9.js} +1 -1
  49. package/dist-cli-web/assets/{EChartLine.vue_vue_type_script_setup_true_lang-Fl7xAOSR.js → EChartLine.vue_vue_type_script_setup_true_lang-BLqlW9E4.js} +1 -1
  50. package/dist-cli-web/assets/{EChartWordcloud-C6XM4KOX.js → EChartWordcloud-ChKJM8bU.js} +1 -1
  51. package/dist-cli-web/assets/{FileDropZone.vue_vue_type_script_setup_true_lang-DYDdRSNE.js → FileDropZone.vue_vue_type_script_setup_true_lang-CsRmQhVQ.js} +1 -1
  52. package/dist-cli-web/assets/{Filter-CByj_rCR.js → Filter-Duzxgudo.js} +1 -1
  53. package/dist-cli-web/assets/{GlobalTaskBar-BdELjzrs.js → GlobalTaskBar-DL0IJxlt.js} +1 -1
  54. package/dist-cli-web/assets/{GroupRelationshipGalaxyView-CnzPEgUS.js → GroupRelationshipGalaxyView-BZrB2o2g.js} +1 -1
  55. package/dist-cli-web/assets/{Label-DCIcxkhU.js → Label-CaVKlQnJ.js} +1 -1
  56. package/dist-cli-web/assets/{LoadingState.vue_vue_type_script_setup_true_lang-BBcCt_Qm.js → LoadingState.vue_vue_type_script_setup_true_lang-uF54r-dT.js} +1 -1
  57. package/dist-cli-web/assets/{MessageExportModal-DNU16Bs8.js → MessageExportModal-JpurBsUW.js} +1 -1
  58. package/dist-cli-web/assets/{PageHeader-CKeZjNNR.js → PageHeader-BciykZ_-.js} +1 -1
  59. package/dist-cli-web/assets/{PageTabs.vue_vue_type_script_setup_true_lang-C8M3wNNH.js → PageTabs.vue_vue_type_script_setup_true_lang-2Xe2iUFO.js} +1 -1
  60. package/dist-cli-web/assets/{RelationshipGalaxyCanvas-CDhljGyJ.js → RelationshipGalaxyCanvas-BO5-MowG.js} +3 -3
  61. package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-BP8fsvvf.js → RelationshipGalaxyThreeCanvas-Dp4CcWU5.js} +1 -1
  62. package/dist-cli-web/assets/{RenderTargetSystem-D76QrDT_.js → RenderTargetSystem-CfuoUG_y.js} +1 -1
  63. package/dist-cli-web/assets/{RovingFocusItem-BJMUQ5DJ.js → RovingFocusItem-FpYwYEP_.js} +1 -1
  64. package/dist-cli-web/assets/{ScreenCaptureModal-DkX4z-M1.js → ScreenCaptureModal-cElYPaSj.js} +1 -1
  65. package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-pVQMbTsj.js +1 -0
  66. package/dist-cli-web/assets/{Select-B5oJc5y1.js → Select-H8Fz6RkU.js} +1 -1
  67. package/dist-cli-web/assets/{SettingsModal-BO-QKQ2h.js → SettingsModal-52Fw4fVW.js} +2 -2
  68. package/dist-cli-web/assets/{StorageTab-CPPXXaRm.js → StorageTab-BnugE5BO.js} +1 -1
  69. package/dist-cli-web/assets/{Switch-CDk3LZ4_.js → Switch-K4aqYC4Y.js} +1 -1
  70. package/dist-cli-web/assets/{Tabs-DqWTBV8x.js → Tabs-BXjD45rO.js} +1 -1
  71. package/dist-cli-web/assets/{Tabs-BMq9wODW.js → Tabs-DJ5p8gb6.js} +1 -1
  72. package/dist-cli-web/assets/{ThemeCard.vue_vue_type_script_setup_true_lang-D2outEOV.js → ThemeCard.vue_vue_type_script_setup_true_lang-BLmTpx4f.js} +1 -1
  73. package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-BcflxP_U.js → TimeSelect.vue_vue_type_script_setup_true_lang-geQAlopO.js} +1 -1
  74. package/dist-cli-web/assets/{VisuallyHiddenInput-BAFpkxMI.js → VisuallyHiddenInput-J2KEIQBX.js} +1 -1
  75. package/dist-cli-web/assets/{WebGLRenderer-DjCPvR_O.js → WebGLRenderer-BDFzRniS.js} +1 -1
  76. package/dist-cli-web/assets/{WebGPURenderer-C2B_u03z.js → WebGPURenderer-BKYZyUCZ.js} +1 -1
  77. package/dist-cli-web/assets/aiChat-CdJzpNYW.js +8 -0
  78. package/dist-cli-web/assets/{base-F6s0vTrr.js → base-129JztT1.js} +1 -1
  79. package/dist-cli-web/assets/{browserAll-DiUAZg4L.js → browserAll-CZNZDK1i.js} +1 -1
  80. package/dist-cli-web/assets/{chatMessages-Bd33SSXI.js → chatMessages-zmzHCUCy.js} +3 -3
  81. package/dist-cli-web/assets/{cli-web-DoibEdj2.js → cli-web-_WGCg-ZY.js} +1 -1
  82. package/dist-cli-web/assets/{fetch-CXM-cjDS.js → fetch-B7Tdp7Uo.js} +1 -1
  83. package/dist-cli-web/assets/{fetch-DBpDMy29.js → fetch-BBdyPNj3.js} +1 -1
  84. package/dist-cli-web/assets/{fetch-B_YFABxI.js → fetch-Bafz8jLM.js} +1 -1
  85. package/dist-cli-web/assets/{fetch-CxVcHNid.js → fetch-C4W6tD-D.js} +1 -1
  86. package/dist-cli-web/assets/{fetch-BeX69kpS.js → fetch-DOsmgros.js} +1 -1
  87. package/dist-cli-web/assets/{fetch-CRocA-4C.js → fetch-DTPDtL38.js} +1 -1
  88. package/dist-cli-web/assets/{fetch-CXqeAbnY.js → fetch-DaeoNUip.js} +1 -1
  89. package/dist-cli-web/assets/{fetch-7lUvXbhU.js → fetch-DgHdAlO7.js} +1 -1
  90. package/dist-cli-web/assets/{fetch-DKBBS9Op.js → fetch-Di4QpfqL.js} +1 -1
  91. package/dist-cli-web/assets/{fetch-4nh1LaVF.js → fetch-Dw33HaVP.js} +11 -13
  92. package/dist-cli-web/assets/{fetch-BEaW1j5H.js → fetch-IP6i-mtr.js} +1 -1
  93. package/dist-cli-web/assets/{fetch-epFXmPIQ.js → fetch-sbr95ipd.js} +1 -1
  94. package/dist-cli-web/assets/{host-CtSqR_Zm.js → host-CMnAiJSx.js} +1 -1
  95. package/dist-cli-web/assets/{host-C4rU8pKA.js → host-CuuNLUWx.js} +1 -1
  96. package/dist-cli-web/assets/{index-ekvsNmfe.js → index-BBYtZa7g.js} +1 -1
  97. package/dist-cli-web/assets/{index-mXe1LssU.js → index-BOXh7X5Y.js} +1 -1
  98. package/dist-cli-web/assets/index-BepItDCQ.js +64 -0
  99. package/dist-cli-web/assets/{index-4DVZ2g0M.js → index-BmGA3geF.js} +1 -1
  100. package/dist-cli-web/assets/{index-BvMAw3Zd.js → index-C-u3l4Uh.js} +1 -1
  101. package/dist-cli-web/assets/{index-D8cHMqV-.js → index-CN9WMxb3.js} +2 -2
  102. package/dist-cli-web/assets/{index-BFH1j_R9.js → index-Chh0gCp7.js} +1 -1
  103. package/dist-cli-web/assets/index-DRFMz0cs.css +1 -0
  104. package/dist-cli-web/assets/{index-BgelKQTW.css → index-DbP9vQhR.css} +1 -1
  105. package/dist-cli-web/assets/index-DgCXdbsG.js +2 -0
  106. package/dist-cli-web/assets/{index-CuCQ1d9f.js → index-DhRaZS6z.js} +1 -1
  107. package/dist-cli-web/assets/{index-_m1mf1jm.js → index-Dz4yfeg6.js} +1 -1
  108. package/dist-cli-web/assets/{index-mbLXPIyC.js → index-EtteazuD.js} +1 -1
  109. package/dist-cli-web/assets/index-GNMlsoVH.js +137 -0
  110. package/dist-cli-web/assets/{index-B1oj9KDv.js → index-bQ9oj54q.js} +4 -4
  111. package/dist-cli-web/assets/{index-DlHuILT_.js → index-fsLAooCi.js} +1 -1
  112. package/dist-cli-web/assets/{people-page-header-BbYSSpsO.js → people-page-header-CKXRSnpl.js} +1 -1
  113. package/dist-cli-web/assets/{prompt-C-ofJ7t_.js → prompt-DNxAd1Bj.js} +1 -1
  114. package/dist-cli-web/assets/{semantic-index-config-builder-D3TYVYC-.js → semantic-index-config-builder-CQ27G4TK.js} +1 -1
  115. package/dist-cli-web/assets/{service-CppETV4a.js → service-BwbGKwDn.js} +1 -1
  116. package/dist-cli-web/assets/service-DQjyjQZx.js +1 -0
  117. package/dist-cli-web/assets/service-Dtve_40X.js +1 -0
  118. package/dist-cli-web/assets/useFormControl-CNmp_2bd.js +1 -0
  119. package/dist-cli-web/assets/{ActionToolsPanel.vue_vue_type_script_setup_true_lang-IB1yZxCE.js → useInsightTabAnalytics-DaU_ADbQ.js} +8 -8
  120. package/dist-cli-web/assets/{useTable-Clk7ecq-.js → useTable-BYXxnZMd.js} +1 -1
  121. package/dist-cli-web/assets/{useToast-B5LaA6c-.js → useToast-DPkgv34s.js} +1 -1
  122. package/dist-cli-web/assets/{webworkerAll-CyA4b4LT.js → webworkerAll-Um4PrCaA.js} +1 -1
  123. package/dist-cli-web/index.html +1 -1
  124. package/package.json +1 -1
  125. package/dist/chat-command-YAFRLHMQ.mjs.map +0 -1
  126. package/dist/chunk-73TJ2S7W.mjs.map +0 -1
  127. package/dist/chunk-ARIBCH47.mjs.map +0 -1
  128. package/dist/chunk-JWJREWVN.mjs.map +0 -1
  129. package/dist/chunk-OTYNMDDL.mjs.map +0 -1
  130. package/dist/chunk-UP6JIV3S.mjs.map +0 -1
  131. package/dist/mcp-SMF3NWIN.mjs.map +0 -1
  132. package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-qFhJO5B0.js +0 -1
  133. package/dist-cli-web/assets/aiChat--CR4g2M7.js +0 -8
  134. package/dist-cli-web/assets/index-CIIyg_o9.css +0 -1
  135. package/dist-cli-web/assets/index-CaYtkONV.js +0 -64
  136. package/dist-cli-web/assets/index-D3Hyjv4e.js +0 -137
  137. package/dist-cli-web/assets/index-R4LqAnx9.js +0 -2
  138. package/dist-cli-web/assets/service-BYOUkk7V.js +0 -1
  139. package/dist-cli-web/assets/service-tEx-5LUL.js +0 -1
  140. package/dist-cli-web/assets/useFormControl-CrWi_6Hn.js +0 -1
  141. /package/dist/{chunk-FPVRSXQ4.mjs.map → chunk-4FAEB4C2.mjs.map} +0 -0
  142. /package/dist/{chunk-MMTEGUQA.mjs.map → chunk-5OA4QI3Q.mjs.map} +0 -0
  143. /package/dist/{chunk-PDQV4RUA.mjs.map → chunk-GDKQKHJT.mjs.map} +0 -0
  144. /package/dist/{chunk-GKCIRKOH.mjs.map → chunk-HJWBFHNR.mjs.map} +0 -0
  145. /package/dist/{chunk-2PY4XCH3.mjs.map → chunk-IMJVOODY.mjs.map} +0 -0
  146. /package/dist/{chunk-WDLO7OLX.mjs.map → chunk-O57SQSCO.mjs.map} +0 -0
  147. /package/dist/{chunk-N4SB6QZV.mjs.map → chunk-ZGXXAPLX.mjs.map} +0 -0
  148. /package/dist/{http-LPFPVTBC.mjs.map → http-QJDZKDNJ.mjs.map} +0 -0
  149. /package/dist/{import-T4WX2ZJL.mjs.map → import-XK6YM26A.mjs.map} +0 -0
  150. /package/dist/{src-EGLLMTAU.mjs.map → src-4AHJUFCW.mjs.map} +0 -0
  151. /package/dist/{stream-import-2BXJTTCE.mjs.map → stream-import-7VQVT5ST.mjs.map} +0 -0
  152. /package/dist/{worker-runtime-RDLSPXFT.mjs.map → worker-runtime-PQBAV75N.mjs.map} +0 -0
  153. /package/dist-cli-web/assets/{ActionToolsPanel-DDNXXH8v.css → useInsightTabAnalytics-DDNXXH8v.css} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ai/logger.ts","../src/ai/manager-factory.ts","../src/ai/tool-adapter.ts","../src/ai/assistant-loader.ts","../src/ai/agent.ts","../src/ai/cross-chat-tool-adapter.ts","../src/ai/agent-stream-runner.ts"],"sourcesContent":["/**\n * Server 端 AI 日志\n *\n * 复用 @openchatlab/node-runtime 的 AiLogger,\n * 在 startHttpServer() 中通过 initServerAiLogger() 初始化。\n */\n\nimport { AiLogger } from '@openchatlab/node-runtime'\n\nlet logger: AiLogger | null = null\n\nexport function initServerAiLogger(logsDir: string): AiLogger {\n if (!logger) {\n logger = new AiLogger(logsDir)\n }\n return logger\n}\n\nexport function getServerAiLogger(): AiLogger | null {\n return logger\n}\n\nexport function closeServerAiLogger(): void {\n if (logger) {\n logger.close()\n logger = null\n }\n}\n","/**\n * Factory functions for creating AssistantManager and SkillManagerCore instances.\n *\n * Server-side equivalent of the Electron adapter in electron/main/ai/assistant/manager.ts.\n * Uses Node.js fs directly (no Electron dependency).\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { createHash, randomUUID } from 'crypto'\nimport {\n appLogger,\n AssistantManager,\n DEFAULT_GENERAL_ASSISTANT_RAW_CONFIGS,\n LEGACY_GENERAL_ASSISTANT_DIGESTS,\n SkillManagerCore,\n type AssistantManagerFs,\n type SkillManagerFs,\n} from '@openchatlab/node-runtime'\n\nconst nodeFs: AssistantManagerFs & SkillManagerFs = {\n ensureDir(dir: string) {\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n },\n listFiles(dir: string, ext: string) {\n if (!fs.existsSync(dir)) return []\n return fs.readdirSync(dir).filter((f) => f.endsWith(ext))\n },\n readFile(filePath: string) {\n return fs.readFileSync(filePath, 'utf-8')\n },\n writeFile(filePath: string, content: string) {\n fs.writeFileSync(filePath, content, 'utf-8')\n },\n deleteFile(filePath: string) {\n if (fs.existsSync(filePath)) fs.unlinkSync(filePath)\n },\n fileExists(filePath: string) {\n return fs.existsSync(filePath)\n },\n joinPath(...parts: string[]) {\n return path.join(...parts)\n },\n}\n\nconst managerCache = new Map<string, { assistant: AssistantManager; skill: SkillManagerCore }>()\n\nexport function getAssistantManager(aiDataDir: string): AssistantManager {\n let cached = managerCache.get(aiDataDir)\n if (!cached) {\n cached = {\n assistant: new AssistantManager({\n fs: nodeFs,\n assistantsDir: path.join(aiDataDir, 'assistants'),\n builtinRawConfigs: DEFAULT_GENERAL_ASSISTANT_RAW_CONFIGS,\n contentHash: (content: string) => createHash('sha256').update(content).digest('hex'),\n legacyBuiltinDigests: LEGACY_GENERAL_ASSISTANT_DIGESTS,\n generateId: () => `custom_${randomUUID().replace(/-/g, '').slice(0, 12)}`,\n logger: appLogger,\n }),\n skill: new SkillManagerCore({\n fs: nodeFs,\n skillsDir: path.join(aiDataDir, 'skills'),\n builtinRawSkills: [],\n contentHash: (content: string) => createHash('md5').update(content).digest('hex'),\n }),\n }\n managerCache.set(aiDataDir, cached)\n }\n return cached.assistant\n}\n\nexport function getSkillManagerCore(aiDataDir: string): SkillManagerCore {\n let cached = managerCache.get(aiDataDir)\n if (!cached) {\n getAssistantManager(aiDataDir)\n cached = managerCache.get(aiDataDir)!\n }\n return cached.skill\n}\n","/**\n * 工具适配层\n *\n * 将 @openchatlab/tools 的 ToolDefinition 适配为 @earendil-works/pi-agent-core 的 AgentTool 格式。\n * 消息类工具返回 rawMessages 时自动执行预处理管道(清洗、去噪、脱敏、截断、格式化)。\n */\n\nimport type {\n ToolDefinition,\n ToolExecutionContext,\n SemanticSearchToolService,\n RawMessage,\n ToolTimeRange,\n} from '@openchatlab/tools'\nimport { CoreDataProvider, executeToolForAgent, toAgentToolParameters } from '@openchatlab/tools'\nimport type { DatabaseAdapter } from '@openchatlab/core'\nimport {\n applyPreprocessingPipeline,\n batchSegmentWithFrequency,\n preprocessMessages,\n type AgentTool,\n type PreprocessableMessage,\n type PreprocessConfig,\n type TruncationStrategy,\n createChartSchemaGateState,\n wrapWithChartSchemaGate,\n} from '@openchatlab/node-runtime'\nimport { getServerAiLogger } from './logger'\n\nconst DEFAULT_MAX_TOOL_RESULT_TOKENS = 8000\n\nconst TOOL_TRUNCATION_STRATEGY: Record<string, TruncationStrategy> = {\n search_messages: 'keep_first',\n deep_search_messages: 'keep_first',\n get_recent_messages: 'keep_last',\n get_message_context: 'keep_last',\n get_segment_messages: 'keep_last',\n get_conversation_between: 'keep_last',\n}\n\nexport interface ServerToolContext {\n db: DatabaseAdapter\n sessionId: string\n locale?: string\n /** 语义检索窄接口(仅当前会话可检索时由 runner 注入) */\n semanticIndexService?: SemanticSearchToolService\n /** 预处理配置(脱敏/匿名化/清洗) */\n preprocessConfig?: Record<string, unknown>\n /** 当前用户平台 id(昵称匿名化 owner 识别) */\n ownerPlatformId?: string\n /** 会话时间范围筛选(来自请求参数,供证据类工具继承) */\n timeFilter?: ToolTimeRange\n /** 关键词搜索消息条数上限 */\n maxMessagesLimit?: number\n}\n\nexport interface AdaptToolsOptions {\n maxToolResultTokens?: number\n}\n\nexport function adaptToolsForAgent(\n tools: ToolDefinition[],\n getContext: () => ServerToolContext,\n options?: AdaptToolsOptions\n): AgentTool<any, any>[] {\n const tokenBudget = options?.maxToolResultTokens ?? DEFAULT_MAX_TOOL_RESULT_TOKENS\n const chartSchemaGateState = createChartSchemaGateState()\n\n return tools.map((tool) =>\n wrapWithChartSchemaGate(\n {\n name: tool.name,\n label: tool.name,\n description: tool.description,\n parameters: toAgentToolParameters(tool.inputSchema) as any,\n executionMode: tool.executionMode,\n async execute(_toolCallId: string, params: unknown, signal, onUpdate) {\n const ctx = getContext()\n const execCtx: ToolExecutionContext = {\n db: ctx.db,\n dataProvider: new CoreDataProvider(ctx.db),\n sessionId: ctx.sessionId,\n locale: ctx.locale,\n abortSignal: signal,\n reportProgress: (progress) => onUpdate?.({ content: [], details: { progress } }),\n semanticIndexService: ctx.semanticIndexService,\n preprocessConfig: ctx.preprocessConfig,\n ownerPlatformId: ctx.ownerPlatformId,\n timeFilter: ctx.timeFilter,\n maxMessagesLimit: ctx.maxMessagesLimit,\n maxToolResultTokens: tokenBudget,\n segmentText: (texts, locale, options) => batchSegmentWithFrequency(texts, locale as any, options as any),\n desensitizeMessages: (messages: RawMessage[]): RawMessage[] =>\n preprocessMessages(\n messages as PreprocessableMessage[],\n ctx.preprocessConfig as PreprocessConfig | undefined\n ) as RawMessage[],\n }\n const result = await executeToolForAgent(tool, params, execCtx)\n const details = result.details as Record<string, unknown> | null\n if (!Array.isArray(details?.rawMessages)) return result\n\n const { rawMessages, chart, charts, ...extraDetails } = details\n const preprocessCfg = ctx.preprocessConfig as PreprocessConfig | undefined\n const pipelineResult = applyPreprocessingPipeline({\n rawMessages: rawMessages as PreprocessableMessage[],\n preprocessConfig: preprocessCfg,\n anonymizeNames: preprocessCfg?.anonymizeNames ?? false,\n ownerPlatformId: ctx.ownerPlatformId,\n locale: ctx.locale,\n maxToolResultTokens: tokenBudget,\n truncationStrategy: TOOL_TRUNCATION_STRATEGY[tool.name] ?? 'keep_last',\n extraDetails,\n logger: getServerAiLogger() ?? undefined,\n })\n const chartDetails = { ...(chart ? { chart } : {}), ...(charts ? { charts } : {}) }\n return {\n content: [{ type: 'text', text: pipelineResult.text }],\n details: Object.keys(chartDetails).length > 0 ? chartDetails : null,\n }\n },\n },\n chartSchemaGateState\n )\n )\n}\n","/**\n * 助手配置加载器\n *\n * 通过共享 AssistantManager 加载配置,确保 standalone CLI 在首次使用时\n * 也会创建默认助手,而不是绕过初始化直接读取磁盘。\n */\n\nimport type { AssistantConfig } from '@openchatlab/node-runtime'\nimport { getAssistantManager } from './manager-factory'\n\nexport function loadAssistantConfig(aiDataDir: string, assistantId: string): AssistantConfig | null {\n return getAssistantManager(aiDataDir).getAssistantConfig(assistantId)\n}\n","/**\n * 服务端 Agent\n *\n * 使用 @openchatlab/node-runtime 的 runAgentCore 编排对话流程,\n * 通过 AgentEventHandler 输出与 Electron 端一致的流式事件。\n */\n\nimport {\n DEFAULT_MAX_TOOL_ROUNDS,\n DEFAULT_CONTEXT_COMPRESSION_CONFIG,\n buildPiModel,\n buildPlanGuidance,\n createAnalysisPlanner,\n createLlmRouteDecider,\n createPlanContentBlock,\n decideRequestRoute,\n runAgentCore,\n checkAndCompress,\n buildSystemPrompt,\n createAiTranslate,\n createCompressionLlmAdapter,\n AgentEventHandler,\n formatAIError,\n shouldUseChartCapabilityForMessage,\n getChartPlannerCapabilityForMessage,\n initTokenizer,\n type AgentStreamChunk,\n type PiMessage,\n type SimpleHistoryMessage,\n type AIChatManager,\n type AgentTool,\n type DataSnapshot,\n type AIServiceConfig,\n type OwnerInfo,\n type MentionedMember,\n} from '@openchatlab/node-runtime'\nimport type { ChartAutoMode } from '@openchatlab/shared-types'\n\nimport { getServerAiLogger } from './logger'\n\nexport type { AgentStreamChunk }\n\nexport interface RunAgentOptions {\n userMessage: string\n aiChatId: string\n historyLeafMessageId?: string | null\n chatType?: 'group' | 'private'\n locale?: string\n assistantSystemPrompt?: string\n skillMenu?: string | null\n skillDef?: { name: string; prompt: string }\n tools?: AgentTool[]\n llmConfig: AIServiceConfig | null\n aiChatManager: AIChatManager\n onEvent: (event: AgentStreamChunk) => void\n abortSignal?: AbortSignal\n ownerInfo?: OwnerInfo\n mentionedMembers?: MentionedMember[]\n dataSnapshot?: DataSnapshot\n thinkingLevel?: string\n chartAutoMode?: ChartAutoMode\n}\n\nexport async function runServerAgent(options: RunAgentOptions): Promise<void> {\n const {\n userMessage,\n aiChatId,\n historyLeafMessageId,\n chatType = 'group',\n locale = 'zh-CN',\n assistantSystemPrompt,\n skillMenu,\n skillDef,\n tools = [],\n llmConfig,\n aiChatManager,\n onEvent,\n abortSignal,\n ownerInfo,\n mentionedMembers,\n dataSnapshot,\n thinkingLevel,\n chartAutoMode = 'suggest',\n } = options\n\n const aiLogger = getServerAiLogger()\n\n // 确保 tokenizer rank 表已加载(compression + agent 路径均依赖)\n await initTokenizer()\n\n if (!llmConfig) {\n onEvent({ type: 'error', error: { name: 'ConfigError', message: 'LLM service not configured' } })\n onEvent({ type: 'done', isFinished: true })\n return\n }\n\n const piModel = buildPiModel(llmConfig)\n const t = createAiTranslate(locale)\n\n let skillCtx: { skillDef?: { name: string; prompt: string }; skillMenu?: string } | undefined\n if (skillDef) {\n skillCtx = { skillDef }\n } else if (skillMenu) {\n skillCtx = { skillMenu }\n }\n\n const systemPrompt = buildSystemPrompt({\n t,\n chatType,\n assistantSystemPrompt,\n ownerInfo,\n locale,\n skillCtx,\n mentionedMembers,\n dataSnapshot,\n })\n\n const handler = new AgentEventHandler({\n onChunk: onEvent,\n context: {},\n systemPrompt,\n })\n\n if (historyLeafMessageId === undefined) {\n const llmAdapter = createCompressionLlmAdapter({\n piModel,\n apiKey: llmConfig.apiKey,\n onCompressing: () => handler.emitStatus('compressing', []),\n })\n const compressionResult = await checkAndCompress(\n aiChatId,\n DEFAULT_CONTEXT_COMPRESSION_CONFIG,\n systemPrompt,\n llmAdapter,\n aiChatManager,\n aiLogger ?? undefined\n )\n if (compressionResult.compressed) {\n onEvent({\n type: 'compression_done',\n compressionResult: {\n summaryContent: compressionResult.summaryContent ?? '',\n tokensBefore: compressionResult.tokensBefore ?? 0,\n tokensAfter: compressionResult.tokensAfter ?? 0,\n timestamp: Date.now(),\n },\n })\n }\n } else {\n aiLogger?.info?.('Compression', 'Skipping compression for edited branch request', {\n aiChatId,\n historyLeafMessageId,\n })\n }\n\n if (abortSignal?.aborted) {\n handler.emitStatus('aborted', [], { force: true })\n onEvent({ type: 'done', isFinished: true, usage: handler.cloneUsage() })\n return\n }\n\n let history: SimpleHistoryMessage[] = []\n try {\n history = aiChatManager.getHistoryForAgent(aiChatId, undefined, historyLeafMessageId)\n } catch {\n // empty history on failure\n }\n\n handler.emitStatus('preparing', [], { pendingUserMessage: userMessage, force: true })\n\n const steerMessage = t('ai.agent.answerWithoutTools')\n let cachedMessages: PiMessage[] = []\n const effectiveTools =\n chartAutoMode === 'explicit' && !shouldUseChartCapabilityForMessage(userMessage)\n ? tools.filter((tool) => tool.name !== 'render_chart')\n : tools\n\n try {\n const routeInput = {\n userMessage,\n chatType,\n locale,\n dataSnapshot,\n availableTools: effectiveTools.map((tool) => tool.name),\n availableCapabilities: [\n getChartPlannerCapabilityForMessage({\n userMessage,\n locale,\n availableTools: effectiveTools.map((tool) => tool.name),\n chartAutoMode,\n }),\n ].filter((capability) => capability !== null),\n skillSummary: skillDef?.name ?? (skillMenu ? 'auto_skill_menu' : undefined),\n }\n const routeStartedAt = Date.now()\n const routeDecision = await decideRequestRoute(routeInput, {\n llmRouter: createLlmRouteDecider({\n piModel,\n apiKey: llmConfig.apiKey,\n abortSignal,\n }),\n })\n aiLogger?.info('Router', 'Shadow route decision', {\n ...routeDecision,\n elapsedMs: Date.now() - routeStartedAt,\n availableToolCount: tools.length,\n shadowOnly: true,\n })\n onEvent({ type: 'route', routeDecision })\n\n let effectiveSystemPrompt = systemPrompt\n if (routeDecision.route === 'planned_execution') {\n const planStartedAt = Date.now()\n const planner = createAnalysisPlanner({\n piModel,\n apiKey: llmConfig.apiKey,\n onPlanDelta: (delta) => onEvent({ type: 'plan_delta', planDelta: delta }),\n onThinkingDelta: (delta) => onEvent({ type: 'think', content: delta, thinkTag: 'thinking' }),\n onThinkingEnd: (durationMs) =>\n onEvent({ type: 'think', content: '', thinkTag: 'thinking', thinkDurationMs: durationMs }),\n onValidationDelta: (delta) => onEvent({ type: 'think', content: delta, thinkTag: 'plan_validation' }),\n onValidationEnd: (durationMs) =>\n onEvent({ type: 'think', content: '', thinkTag: 'plan_validation', thinkDurationMs: durationMs }),\n })\n const plan = await planner(routeInput, abortSignal)\n if (plan) {\n const planBlock = createPlanContentBlock(plan)\n onEvent({ type: 'plan', plan: planBlock })\n effectiveSystemPrompt = `${systemPrompt}\\n\\n${buildPlanGuidance(plan)}`\n aiLogger?.info('Planner', 'Plan generated', {\n title: plan.title,\n steps: plan.steps.length,\n successCriteria: plan.successCriteria.length,\n elapsedMs: Date.now() - planStartedAt,\n })\n } else {\n aiLogger?.warn('Planner', 'Plan generation skipped or failed', {\n elapsedMs: Date.now() - planStartedAt,\n route: routeDecision.route,\n })\n onEvent({ type: 'plan_skipped' })\n }\n }\n\n const result = await runAgentCore({\n piModel,\n apiKey: llmConfig.apiKey,\n systemPrompt: effectiveSystemPrompt,\n tools: effectiveTools,\n history,\n userMessage,\n maxToolRounds: DEFAULT_MAX_TOOL_ROUNDS,\n abortSignal,\n providerSessionId: aiChatId,\n steerMessage,\n thinkingLevel: thinkingLevel as import('@openchatlab/core').ThinkingLevel | undefined,\n onConvertToLlm: (filteredMessages) => {\n cachedMessages = filteredMessages as PiMessage[]\n },\n onEvent: (coreEvent) => handler.handleCoreEvent(coreEvent, cachedMessages),\n onDebugContext: (messages) => {\n try {\n aiChatManager.setPendingDebugContext(aiChatId, JSON.stringify(messages, null, 2))\n } catch {\n // silent\n }\n },\n })\n\n if (result.error) {\n const friendlyMessage = formatAIError(result.error)\n onEvent({ type: 'error', error: { name: 'AgentError', message: friendlyMessage } })\n }\n\n handler.emitStatus('completed', cachedMessages, { force: true })\n onEvent({ type: 'done', isFinished: true, usage: result.usage })\n } catch (error) {\n const friendlyMessage = formatAIError(error)\n aiLogger?.error('ServerAgent', 'Agent execution error', { error: String(error) })\n handler.emitStatus('error', cachedMessages, { force: true })\n onEvent({ type: 'error', error: { name: 'AgentError', message: friendlyMessage } })\n onEvent({ type: 'done', isFinished: true, usage: handler.cloneUsage() })\n }\n}\n","import type {\n AgentTool,\n AIMemoryService,\n CrossChatAnalysisService,\n PreprocessConfig,\n SessionRuntimeAdapter,\n} from '@openchatlab/node-runtime'\nimport type { AIEntityRef } from '@openchatlab/shared-types'\nimport {\n countTokens,\n preprocessCrossChatLabel,\n preprocessCrossChatMessages,\n preprocessCrossChatSummaries,\n} from '@openchatlab/node-runtime'\nimport { createCrossChatAgentToolAdapters, type CrossChatToolExecutionContext } from '@openchatlab/tools'\n\nexport function createCliCrossChatTools(options: {\n analysisService: CrossChatAnalysisService\n sessionAdapter: SessionRuntimeAdapter\n locale?: string\n entityRefs?: AIEntityRef[]\n preprocessConfig?: Record<string, unknown>\n maxToolResultTokens: number\n memoryService: AIMemoryService\n aiChatId: string\n reportMemoryChange?: (memoryId: string) => void\n}): AgentTool<any, any>[] {\n const context: Omit<CrossChatToolExecutionContext, 'abortSignal' | 'reportProgress'> = {\n locale: options.locale,\n entityRefs: options.entityRefs,\n analysisService: options.analysisService,\n memoryService: options.memoryService,\n aiChatId: options.aiChatId,\n reportMemoryChange: options.reportMemoryChange,\n maxToolResultTokens: options.maxToolResultTokens,\n countTokens,\n preprocessMessagesBySession: (sessionId, messages) =>\n preprocessCrossChatMessages(\n options.sessionAdapter,\n sessionId,\n messages,\n options.preprocessConfig as PreprocessConfig | undefined\n ),\n preprocessSummariesBySession: (sessionId, summaries) =>\n preprocessCrossChatSummaries(\n options.sessionAdapter,\n sessionId,\n summaries,\n options.preprocessConfig as PreprocessConfig | undefined\n ),\n preprocessModelLabel: (value, pseudonym) =>\n preprocessCrossChatLabel(value, pseudonym, options.preprocessConfig as PreprocessConfig | undefined),\n }\n\n return createCrossChatAgentToolAdapters(context) as AgentTool<any, any>[]\n}\n","/**\n * CLI Agent stream runner — provides runAgentStream implementation\n * for the shared HTTP route context.\n */\n\nimport type {\n DatabaseManager,\n AIChatManager,\n AgentStreamChunk,\n LLMConfigStore,\n SemanticIndexRuntime,\n CrossChatAnalysisService,\n SessionRuntimeAdapter,\n AIMemoryService,\n} from '@openchatlab/node-runtime'\nimport {\n CHART_CAPABILITY_CORE_TOOLS,\n DEFAULT_CONTEXT_COMPRESSION_CONFIG,\n SkillManager,\n buildPiModel,\n buildSkillMenuWithBuiltinChart,\n createLlmRuntimeStores,\n createActivateSkillTool,\n createDataSnapshotFromOverview,\n getAllowedBuiltinToolsForChartAutoSkill,\n getChartCapabilitySkill,\n getSkillConfigWithBuiltinChart,\n resolveChartRuntimeForRequest,\n resolveCrossChatToolResultTokenBudget,\n runCrossChatAgent,\n} from '@openchatlab/node-runtime'\nimport { getChatOverview, normalizeBuiltinToolNames } from '@openchatlab/core'\nimport type { ChartAutoMode } from '@openchatlab/shared-types'\nimport type { DataSnapshot } from '@openchatlab/node-runtime'\nimport type { AgentStreamRequest } from '@openchatlab/http-routes'\nimport { AGENT_TOOL_REGISTRY, SEMANTIC_SEARCH_TOOL_NAME } from '@openchatlab/tools'\nimport { buildSemanticSearchGuidance } from '@openchatlab/node-runtime'\nimport { adaptToolsForAgent } from './tool-adapter'\nimport { loadAssistantConfig } from './assistant-loader'\nimport { runServerAgent } from './agent'\nimport { createCliCrossChatTools } from './cross-chat-tool-adapter'\nimport { getServerAiLogger } from './logger'\n\nfunction getAiDir(dbManager: DatabaseManager): string {\n const pathProvider = (dbManager as any)['pathProvider']\n if (!pathProvider) {\n throw Object.assign(new Error('PathProvider not available'), { statusCode: 500 })\n }\n return pathProvider.getAiDataDir()\n}\n\nconst RAW_SQL_TOOL_NAMES = new Set(['execute_sql'])\n\nexport function getAvailableToolDefs(isChartCapability: boolean, allowedToolSet: Set<string> | null) {\n if (isChartCapability) {\n const chartCoreTools = new Set<string>(CHART_CAPABILITY_CORE_TOOLS)\n return AGENT_TOOL_REGISTRY.filter(\n (tool) =>\n chartCoreTools.has(tool.name) ||\n (tool.category === 'analysis' && allowedToolSet?.has(tool.name) && !RAW_SQL_TOOL_NAMES.has(tool.name))\n )\n }\n\n return allowedToolSet\n ? AGENT_TOOL_REGISTRY.filter((tool) => tool.category !== 'analysis' || allowedToolSet.has(tool.name))\n : AGENT_TOOL_REGISTRY\n}\n\n// 区分“未配置白名单”和“配置为空白名单”:前者无限制,后者禁用 analysis 工具。\nexport function getAllowedToolSet(\n isChartCapability: boolean,\n allowedBuiltinTools?: readonly string[]\n): Set<string> | null {\n if (isChartCapability) {\n return new Set(normalizeBuiltinToolNames(allowedBuiltinTools ?? []))\n }\n return allowedBuiltinTools === undefined ? null : new Set(normalizeBuiltinToolNames(allowedBuiltinTools))\n}\n\nexport function createCliRunAgentStream(\n dbManager: DatabaseManager,\n aiChatManager: AIChatManager,\n options: {\n llmConfigStore?: LLMConfigStore\n semanticIndexService?: SemanticIndexRuntime\n crossChatAnalysisService?: CrossChatAnalysisService\n sessionAdapter?: SessionRuntimeAdapter\n memoryService?: AIMemoryService\n } = {}\n): (params: AgentStreamRequest, onEvent: (chunk: AgentStreamChunk) => void, abortSignal: AbortSignal) => Promise<void> {\n const aiDataDir = getAiDir(dbManager)\n const llmConfigStore = options.llmConfigStore ?? createLlmRuntimeStores(aiDataDir).llmConfigStore\n const semanticIndexService = options.semanticIndexService\n\n return async (params, onEvent, abortSignal) => {\n const {\n userMessage,\n aiChatId,\n historyLeafMessageId,\n chatKind = 'session',\n sessionId,\n entityRefs,\n chatType,\n locale,\n assistantId,\n skillId,\n enableAutoSkill,\n chartAutoMode,\n ownerInfo,\n mentionedMembers,\n thinkingLevel,\n } = params\n\n const conversation = aiChatManager.getAIChat(aiChatId)\n if (\n !conversation ||\n conversation.kind !== chatKind ||\n (chatKind === 'session' && conversation.sessionId !== sessionId)\n ) {\n onEvent({\n type: 'error',\n error: { name: 'ValidationError', message: 'AI conversation does not match the requested target' },\n })\n onEvent({ type: 'done', isFinished: true })\n return\n }\n\n let assistantSystemPrompt: string | undefined\n let assistantAllowedTools: string[] | undefined\n if (assistantId) {\n const assistantConfig = loadAssistantConfig(aiDataDir, assistantId)\n if (assistantConfig?.systemPrompt) {\n assistantSystemPrompt = assistantConfig.systemPrompt\n }\n assistantAllowedTools = assistantConfig?.allowedBuiltinTools\n }\n\n const llmConfig = llmConfigStore.getDefaultAssistantConfig()\n const maxToolResultPercent = DEFAULT_CONTEXT_COMPRESSION_CONFIG.maxToolResultPercent ?? 50\n const contextWindow = llmConfig ? (buildPiModel(llmConfig).contextWindow ?? 128000) : 128000\n const maxToolResultTokens = Math.floor(contextWindow * (maxToolResultPercent / 100))\n\n if (chatKind === 'global') {\n if (!llmConfig) {\n onEvent({ type: 'error', error: { name: 'ConfigError', message: 'LLM service not configured' } })\n onEvent({ type: 'done', isFinished: true })\n return\n }\n if (!options.crossChatAnalysisService || !options.sessionAdapter || !options.memoryService) {\n onEvent({ type: 'error', error: { name: 'RuntimeError', message: 'Cross-chat analysis is unavailable' } })\n onEvent({ type: 'done', isFinished: true })\n return\n }\n const tools = createCliCrossChatTools({\n analysisService: options.crossChatAnalysisService,\n sessionAdapter: options.sessionAdapter,\n locale,\n entityRefs,\n preprocessConfig: params.preprocessConfig,\n maxToolResultTokens: resolveCrossChatToolResultTokenBudget(contextWindow),\n memoryService: options.memoryService,\n aiChatId,\n reportMemoryChange: (memoryId) => onEvent({ type: 'memory_change', memoryId }),\n })\n await runCrossChatAgent({\n userMessage,\n entityRefs,\n aiChatId,\n historyLeafMessageId,\n locale,\n piModel: buildPiModel(llmConfig),\n apiKey: llmConfig.apiKey,\n tools,\n aiChatManager,\n memoryService: options.memoryService,\n onEvent,\n abortSignal,\n thinkingLevel: thinkingLevel as import('@openchatlab/core').ThinkingLevel | undefined,\n logger: getServerAiLogger() ?? undefined,\n })\n return\n }\n\n if (!sessionId) {\n onEvent({ type: 'error', error: { name: 'ValidationError', message: 'Session ID is required' } })\n onEvent({ type: 'done', isFinished: true })\n return\n }\n\n const db = (dbManager as any).open?.(sessionId)\n const resolvedChartAutoMode: ChartAutoMode = chartAutoMode ?? 'suggest'\n const chartRuntime = resolveChartRuntimeForRequest({\n skillId,\n userMessage,\n locale,\n assistantAllowedTools,\n enableAutoDetection: enableAutoSkill === true,\n chartAutoMode: resolvedChartAutoMode,\n })\n const isChartCapability = chartRuntime.isChartCapability\n const autoSkillAllowedTools =\n !skillId && enableAutoSkill && resolvedChartAutoMode !== 'explicit'\n ? getAllowedBuiltinToolsForChartAutoSkill(assistantAllowedTools)\n : assistantAllowedTools\n const allowedToolSet = getAllowedToolSet(\n isChartCapability,\n isChartCapability ? chartRuntime.allowedBuiltinTools : autoSkillAllowedTools\n )\n const availableToolDefs = getAvailableToolDefs(isChartCapability, allowedToolSet)\n\n // 语义检索按需暴露:仅当前会话可检索时保留工具,否则从工具集中过滤掉以减少 schema token 与无效调用。\n const canSemanticSearch = !!db && !!semanticIndexService && (await semanticIndexService.canSearch(sessionId))\n const filteredToolDefs = canSemanticSearch\n ? availableToolDefs\n : availableToolDefs.filter((tool) => tool.name !== SEMANTIC_SEARCH_TOOL_NAME)\n\n const agentTools = db\n ? adaptToolsForAgent(\n filteredToolDefs,\n () => ({\n db,\n sessionId,\n locale,\n semanticIndexService,\n preprocessConfig: params.preprocessConfig,\n ownerPlatformId: ownerInfo?.platformId,\n timeFilter: params.timeFilter,\n maxMessagesLimit: params.maxMessagesLimit,\n }),\n { maxToolResultTokens }\n )\n : []\n\n // 工具可用时向 system prompt 加简短引导,提示何时调用语义检索。\n if (canSemanticSearch) {\n assistantSystemPrompt = [assistantSystemPrompt, buildSemanticSearchGuidance(locale)].filter(Boolean).join('\\n\\n')\n }\n\n const skillMgr = new SkillManager(aiDataDir)\n skillMgr.init()\n const toolNames = agentTools.map((t: { name: string }) => t.name)\n\n let resolvedSkillDef: { name: string; prompt: string } | undefined\n let resolvedSkillMenu: string | undefined\n if (isChartCapability) {\n const def = chartRuntime.skillDef ?? getChartCapabilitySkill(locale ?? 'zh-CN')\n resolvedSkillDef = { name: def.name, prompt: def.prompt }\n } else if (skillId) {\n const def = skillMgr.getSkillConfig(skillId)\n if (def) resolvedSkillDef = { name: def.name, prompt: def.prompt }\n } else if (enableAutoSkill) {\n const baseMenu = skillMgr.getSkillMenu(chatType ?? 'group', toolNames)\n const menu =\n resolvedChartAutoMode === 'aggressive' ? buildSkillMenuWithBuiltinChart(baseMenu, locale, toolNames) : baseMenu\n if (menu) resolvedSkillMenu = menu\n }\n\n if (resolvedSkillMenu) {\n const activateSkillTool = createActivateSkillTool({\n chatType: chatType ?? 'group',\n allowedTools: toolNames,\n coreToolNames: new Set<string>(CHART_CAPABILITY_CORE_TOOLS),\n locale,\n getSkillConfig: (id) =>\n resolvedChartAutoMode === 'aggressive'\n ? getSkillConfigWithBuiltinChart(id, locale, (skillConfigId) => skillMgr.getSkillConfig(skillConfigId))\n : skillMgr.getSkillConfig(id),\n })\n agentTools.push(activateSkillTool as any)\n }\n\n let dataSnapshot: DataSnapshot | undefined\n if (db) {\n try {\n dataSnapshot = createDataSnapshotFromOverview(getChatOverview(db, 10))\n } catch {\n // non-fatal\n }\n }\n\n await runServerAgent({\n userMessage,\n aiChatId,\n historyLeafMessageId,\n chatType,\n locale,\n assistantSystemPrompt,\n skillMenu: resolvedSkillMenu,\n skillDef: resolvedSkillDef,\n tools: agentTools,\n llmConfig,\n aiChatManager,\n onEvent,\n abortSignal,\n ownerInfo,\n mentionedMembers,\n dataSnapshot,\n thinkingLevel,\n chartAutoMode: resolvedChartAutoMode,\n })\n }\n}\n"],"mappings":"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","names":["options"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../packages/node-runtime/src/node-path-provider.ts","../../../packages/node-runtime/src/data-dir-switch.ts","../../../packages/node-runtime/src/jieba-nlp-provider.ts","../../../packages/node-runtime/src/nlp/word-frequency.ts","../../../packages/node-runtime/src/nlp/dict-manager.ts","../../../packages/node-runtime/src/preferences.ts","../../../packages/node-runtime/src/merger/index.ts","../../../packages/node-runtime/src/services/analytics.ts","../../../packages/node-runtime/src/services/demo-import.ts","../../../packages/node-runtime/src/semantic-index/index.ts","../../../packages/node-runtime/src/semantic-index/worker-client.ts","../../../packages/node-runtime/src/semantic-index/worker-thread-transport.ts","../../../packages/node-runtime/src/semantic-index/embedding/index.ts"],"sourcesContent":["/**\n * PathProvider 的 Node.js 独立实现\n *\n * 为 CLI / npm 服务版提供路径管理,不依赖 Electron。\n *\n * 目录分为两类:\n * - 系统数据:固定在 ~/.chatlab/,存放配置、日志、缓存、AI 数据等\n * - 用户数据:可配置位置,存放聊天记录数据库等核心资产\n *\n * 用户数据目录(userDataDir)解析优先级:\n * 1. 构造函数传入的 userDataDir 参数\n * 2. CHATLAB_DATA_DIR 环境变量\n * 3. ~/.chatlab/config.toml → [data] user_data_dir\n * 4. 平台默认路径\n */\n\nimport * as fs from 'fs'\nimport * as os from 'os'\nimport * as path from 'path'\nimport type { PathProvider } from '@openchatlab/core'\nimport { writeConfigField, loadConfig } from '@openchatlab/config'\nimport { migrateFromElectronIfNeeded } from './migrations/electron-data-migration'\nimport { applyPendingNodeDataDirMigration } from './data-dir-switch'\nimport { getChatLabTempScopeDir } from './temp-workspace'\n\nconst SYSTEM_DIR = path.join(os.homedir(), '.chatlab')\n\n/**\n * Set after resolveUserDataDir() detects Electron installation but cannot find databases.\n * CLI should check this and block execution with instructions.\n */\nlet _pendingElectronDataWarning = false\n\nexport function hasPendingElectronDataWarning(): boolean {\n return _pendingElectronDataWarning\n}\n\nexport function applyPendingNodeDataDirMigrationIfNeeded(): { success: boolean; skipped?: boolean; error?: string } {\n if (process.env.CHATLAB_DATA_DIR) return { success: true, skipped: true }\n return applyPendingNodeDataDirMigration(SYSTEM_DIR)\n}\n\nexport class NodePathProvider implements PathProvider {\n private systemDir: string\n private userDataDir: string\n\n constructor(userDataDir?: string) {\n this.systemDir = SYSTEM_DIR\n this.userDataDir = userDataDir || resolveUserDataDir()\n }\n\n getSystemDir(): string {\n return this.systemDir\n }\n\n getUserDataDir(): string {\n return this.userDataDir\n }\n\n getDatabaseDir(): string {\n return path.join(this.userDataDir, 'databases')\n }\n\n getVectorDir(): string {\n return path.join(this.userDataDir, 'vector')\n }\n\n getAiDataDir(): string {\n return path.join(this.systemDir, 'ai')\n }\n\n getSettingsDir(): string {\n return path.join(this.systemDir, 'settings')\n }\n\n getCacheDir(): string {\n return path.join(this.systemDir, 'cache')\n }\n\n getTempDir(): string {\n return getChatLabTempScopeDir('runtime')\n }\n\n getLogsDir(): string {\n return path.join(this.systemDir, 'logs')\n }\n\n getDownloadsDir(): string {\n return path.join(os.homedir(), 'Downloads')\n }\n\n /**\n * 确保系统目录和用户数据目录都存在\n */\n ensureAllDirs(): void {\n const dirs = [\n this.systemDir,\n this.userDataDir,\n this.getDatabaseDir(),\n this.getVectorDir(),\n this.getAiDataDir(),\n this.getSettingsDir(),\n this.getCacheDir(),\n this.getTempDir(),\n this.getLogsDir(),\n ]\n for (const dir of dirs) {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n }\n\n const markerPath = path.join(this.userDataDir, '.chatlab')\n if (!fs.existsSync(markerPath)) {\n fs.writeFileSync(markerPath, 'ChatLab Data Directory', 'utf-8')\n }\n }\n}\n\nfunction resolveUserDataDir(): string {\n const envDir = process.env.CHATLAB_DATA_DIR\n if (envDir) {\n return expandHome(envDir)\n }\n\n const config = loadConfig()\n if (config.data.user_data_dir) {\n return expandHome(config.data.user_data_dir)\n }\n\n // First run: check for existing Electron desktop data before using default\n const result = migrateFromElectronIfNeeded(SYSTEM_DIR)\n if (result.migrated && result.userDataDir) {\n return result.userDataDir\n }\n\n const defaultDir = getDefaultNodeUserDataDir()\n\n if (result.electronDetected) {\n // Electron was used but we couldn't find databases — likely a custom data directory.\n // Don't persist default to config.toml so migration retries on next startup.\n _pendingElectronDataWarning = true\n return defaultDir\n }\n\n writeConfigField('data', 'user_data_dir', defaultDir)\n return defaultDir\n}\n\nexport function getDefaultNodeUserDataDir(): string {\n return path.join(os.homedir(), '.chatlab', 'data')\n}\n\nexport function getSystemLogsDir(): string {\n return path.join(SYSTEM_DIR, 'logs')\n}\n\nfunction expandHome(filePath: string): string {\n if (filePath.startsWith('~/') || filePath === '~') {\n return path.join(os.homedir(), filePath.slice(1))\n }\n return filePath\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport { randomUUID } from 'node:crypto'\nimport { writeConfigField } from '@openchatlab/config'\nimport { appLogger } from './logging/app-logger'\n\nconst CHATLAB_MARKER_FILE = '.chatlab'\nconst USER_DATA_REQUIRED_DIRS = ['databases']\nconst PENDING_MIGRATION_FILE = 'data-dir-migration.json'\nconst PENDING_CLEANUPS_FILE = 'data-dir-cleanups.json'\n\nconst DANGEROUS_PATHS = [\n 'C:\\\\Windows',\n 'C:\\\\Program Files',\n 'C:\\\\Program Files (x86)',\n 'C:\\\\ProgramData',\n '/usr',\n '/etc',\n '/bin',\n '/sbin',\n '/lib',\n '/var',\n '/boot',\n '/root',\n '/System',\n '/Library',\n]\n\nexport interface CopyStats {\n copied: number\n skipped: number\n errors: string[]\n}\n\nexport interface PendingDataDirMigration {\n from: string\n to: string\n migrate: boolean\n /** Legacy field retained so older runtimes also leave the source directory untouched. */\n deleteSourceOnSuccess: boolean\n createdAt: string\n}\n\nexport interface RunPendingDataDirMigrationDeps {\n copyDirMerge?: typeof copyDirMerge\n ensureDir?: (dirPath: string) => void\n writeUserDataDir: (dir: string) => void\n clearPendingMigration: () => void\n recordPendingCleanup?: (sourceDir: string, targetDir: string) => void\n log?: (message: string) => void\n}\n\nexport interface PendingDataDirCleanup {\n id: string\n sourceDir: string\n targetDir: string\n createdAt: string\n noticeDismissed: boolean\n}\n\ninterface PendingDataDirCleanupFile {\n version: 1\n entries: PendingDataDirCleanup[]\n}\n\nexport interface RunPendingDataDirMigrationResult {\n success: boolean\n from: string\n to: string\n copied: number\n skipped: number\n errors: string[]\n}\n\nexport interface DataDirSwitchResult {\n success: boolean\n error?: string\n from?: string\n to?: string\n requiresRelaunch?: boolean\n}\n\nexport interface ApplyPendingNodeDataDirMigrationDeps {\n writeConfigField?: typeof writeConfigField\n}\n\nexport interface DeletePendingDataDirCleanupDeps {\n removeDir?: (dir: string) => void\n}\n\nfunction normalizePathForCompare(input: string): string {\n const resolved = path.resolve(input)\n const normalized = path.normalize(resolved)\n return process.platform === 'win32' ? normalized.toLowerCase() : normalized\n}\n\nfunction isSubPath(parent: string, child: string): boolean {\n const parentPath = normalizePathForCompare(parent)\n const childPath = normalizePathForCompare(child)\n\n if (parentPath === childPath) return false\n return childPath.startsWith(`${parentPath}${path.sep}`)\n}\n\nfunction isPathSafe(targetPath: string): boolean {\n const normalizedTarget = targetPath.toLowerCase().replace(/\\//g, '\\\\')\n\n for (const dangerous of DANGEROUS_PATHS) {\n const normalizedDangerous = dangerous.toLowerCase().replace(/\\//g, '\\\\')\n if (normalizedTarget.startsWith(normalizedDangerous)) {\n return false\n }\n }\n\n return true\n}\n\nfunction ensureDir(dirPath: string): void {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true })\n }\n}\n\nfunction hasChatLabUserDataStructure(entries: string[]): boolean {\n return entries.includes(CHATLAB_MARKER_FILE) && USER_DATA_REQUIRED_DIRS.every((dir) => entries.includes(dir))\n}\n\nfunction hasChatLabDatabaseFiles(dirPath: string, entries?: string[]): boolean {\n const dirEntries = entries ?? fs.readdirSync(dirPath)\n if (!dirEntries.includes('databases')) return false\n\n const dbDir = path.join(dirPath, 'databases')\n try {\n return fs.existsSync(dbDir) && fs.readdirSync(dbDir).some((file) => file.endsWith('.db'))\n } catch {\n return false\n }\n}\n\nexport function isExistingUserDataDir(dirPath: string): boolean {\n if (!fs.existsSync(dirPath)) return false\n\n try {\n const entries = fs.readdirSync(dirPath)\n return hasChatLabUserDataStructure(entries) || hasChatLabDatabaseFiles(dirPath, entries)\n } catch {\n return false\n }\n}\n\nexport function isUserDataDirSafeToUse(dirPath: string): boolean {\n if (!fs.existsSync(dirPath)) return true\n\n try {\n const entries = fs.readdirSync(dirPath)\n if (entries.length === 0) return true\n return hasChatLabUserDataStructure(entries) || hasChatLabDatabaseFiles(dirPath, entries)\n } catch {\n return false\n }\n}\n\nexport function isDirectoryEmptyOrMissing(dirPath: string): boolean {\n if (!fs.existsSync(dirPath)) return true\n\n try {\n return fs.readdirSync(dirPath).length === 0\n } catch {\n return false\n }\n}\n\nexport function copyDirMerge(\n src: string,\n dest: string,\n mkdir: (dirPath: string) => void = ensureDir,\n stats: CopyStats = { copied: 0, skipped: 0, errors: [] }\n): CopyStats {\n if (!fs.existsSync(src)) return stats\n\n try {\n mkdir(dest)\n const entries = fs.readdirSync(src, { withFileTypes: true })\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n\n try {\n if (entry.isDirectory()) {\n copyDirMerge(srcPath, destPath, mkdir, stats)\n } else if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath)\n stats.copied++\n } else {\n stats.skipped++\n }\n } catch (error) {\n stats.errors.push(`复制失败: ${srcPath} -> ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n } catch (error) {\n stats.errors.push(`读取目录失败: ${src} -> ${error instanceof Error ? error.message : String(error)}`)\n }\n\n return stats\n}\n\nexport function createPendingDataDirMigration(input: {\n from: string\n to: string\n migrate: boolean\n targetWasEmpty: boolean\n}): PendingDataDirMigration {\n return {\n from: input.from,\n to: input.to,\n migrate: input.migrate,\n deleteSourceOnSuccess: false,\n createdAt: new Date().toISOString(),\n }\n}\n\nexport function runPendingDataDirMigration(\n pending: PendingDataDirMigration,\n deps: RunPendingDataDirMigrationDeps\n): RunPendingDataDirMigrationResult {\n const copy = deps.copyDirMerge ?? copyDirMerge\n const mkdir = deps.ensureDir ?? ensureDir\n\n let stats: CopyStats = { copied: 0, skipped: 0, errors: [] }\n if (pending.migrate && path.resolve(pending.from) !== path.resolve(pending.to)) {\n if (!fs.existsSync(pending.from)) {\n return {\n success: false,\n from: pending.from,\n to: pending.to,\n copied: 0,\n skipped: 0,\n errors: [`源数据目录不存在: ${pending.from}`],\n }\n }\n\n stats = copy(pending.from, pending.to, mkdir)\n deps.log?.(\n `数据目录迁移完成: 从 ${pending.from} 到 ${pending.to},复制 ${stats.copied} 项,跳过 ${stats.skipped} 项,错误 ${stats.errors.length} 项`\n )\n if (stats.errors.length > 0) {\n return {\n success: false,\n from: pending.from,\n to: pending.to,\n copied: stats.copied,\n skipped: stats.skipped,\n errors: stats.errors,\n }\n }\n } else {\n mkdir(pending.to)\n }\n\n deps.writeUserDataDir(pending.to)\n\n // Skipped files may leave unique data in either directory, so cleanup records stay unchanged; deletion revalidates active paths.\n if (pending.migrate && path.resolve(pending.from) !== path.resolve(pending.to) && stats.skipped === 0) {\n deps.recordPendingCleanup?.(pending.from, pending.to)\n } else if (stats.skipped > 0) {\n deps.log?.(\n `Old data directory retained without cleanup registration because ${stats.skipped} target file(s) were skipped`\n )\n }\n deps.clearPendingMigration()\n\n return {\n success: true,\n from: pending.from,\n to: pending.to,\n copied: stats.copied,\n skipped: stats.skipped,\n errors: [],\n }\n}\n\nfunction getPendingMigrationPath(systemDir: string): string {\n return path.join(systemDir, 'settings', PENDING_MIGRATION_FILE)\n}\n\nfunction getPendingCleanupsPath(systemDir: string): string {\n return path.join(systemDir, 'settings', PENDING_CLEANUPS_FILE)\n}\n\nfunction isPendingDataDirCleanup(value: unknown): value is PendingDataDirCleanup {\n if (!value || typeof value !== 'object') return false\n const entry = value as Partial<PendingDataDirCleanup>\n return (\n typeof entry.id === 'string' &&\n typeof entry.sourceDir === 'string' &&\n path.isAbsolute(entry.sourceDir) &&\n typeof entry.targetDir === 'string' &&\n path.isAbsolute(entry.targetDir) &&\n typeof entry.createdAt === 'string' &&\n typeof entry.noticeDismissed === 'boolean'\n )\n}\n\nfunction writePendingDataDirCleanups(systemDir: string, entries: PendingDataDirCleanup[]): void {\n const filePath = getPendingCleanupsPath(systemDir)\n ensureDir(path.dirname(filePath))\n const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`\n const payload: PendingDataDirCleanupFile = { version: 1, entries }\n\n try {\n fs.writeFileSync(tempPath, `${JSON.stringify(payload, null, 2)}\\n`, 'utf-8')\n fs.renameSync(tempPath, filePath)\n } finally {\n if (fs.existsSync(tempPath)) fs.rmSync(tempPath, { force: true })\n }\n}\n\nexport function getPendingDataDirCleanups(systemDir: string): PendingDataDirCleanup[] {\n const filePath = getPendingCleanupsPath(systemDir)\n if (!fs.existsSync(filePath)) return []\n\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as Partial<PendingDataDirCleanupFile>\n if (parsed.version !== 1 || !Array.isArray(parsed.entries)) return []\n return parsed.entries.filter(isPendingDataDirCleanup)\n } catch {\n return []\n }\n}\n\nexport function registerPendingDataDirCleanup(\n systemDir: string,\n input: { sourceDir: string; targetDir: string; createdAt?: string }\n): PendingDataDirCleanup | null {\n if (!path.isAbsolute(input.sourceDir) || !path.isAbsolute(input.targetDir)) return null\n if (normalizePathForCompare(input.sourceDir) === normalizePathForCompare(input.targetDir)) return null\n\n // A directory selected as the new active target is no longer an old backup candidate.\n const entries = getPendingDataDirCleanups(systemDir).filter(\n (entry) => normalizePathForCompare(entry.sourceDir) !== normalizePathForCompare(input.targetDir)\n )\n const existingIndex = entries.findIndex(\n (entry) => normalizePathForCompare(entry.sourceDir) === normalizePathForCompare(input.sourceDir)\n )\n const cleanup: PendingDataDirCleanup = {\n id: existingIndex >= 0 ? entries[existingIndex].id : randomUUID(),\n sourceDir: input.sourceDir,\n targetDir: input.targetDir,\n createdAt: input.createdAt ?? new Date().toISOString(),\n noticeDismissed: false,\n }\n\n if (existingIndex >= 0) entries.splice(existingIndex, 1, cleanup)\n else entries.push(cleanup)\n writePendingDataDirCleanups(systemDir, entries)\n return cleanup\n}\n\nexport function dismissPendingDataDirCleanupNotice(systemDir: string, cleanupId: string): boolean {\n const entries = getPendingDataDirCleanups(systemDir)\n const cleanup = entries.find((entry) => entry.id === cleanupId)\n if (!cleanup) return false\n if (cleanup.noticeDismissed) return true\n\n cleanup.noticeDismissed = true\n writePendingDataDirCleanups(systemDir, entries)\n return true\n}\n\nexport function deletePendingDataDirCleanup(\n systemDir: string,\n currentDir: string,\n cleanupId: string,\n deps: DeletePendingDataDirCleanupDeps = {}\n): { success: boolean; error?: string } {\n const entries = getPendingDataDirCleanups(systemDir)\n const cleanup = entries.find((entry) => entry.id === cleanupId)\n if (!cleanup) return { success: false, error: 'Pending data directory cleanup not found' }\n\n const sourceDir = cleanup.sourceDir\n const overlapsCurrentDir =\n normalizePathForCompare(sourceDir) === normalizePathForCompare(currentDir) ||\n isSubPath(sourceDir, currentDir) ||\n isSubPath(currentDir, sourceDir)\n const overlapsSystemDir =\n normalizePathForCompare(sourceDir) === normalizePathForCompare(systemDir) ||\n isSubPath(sourceDir, systemDir) ||\n isSubPath(systemDir, sourceDir)\n\n if (overlapsCurrentDir || overlapsSystemDir) {\n appLogger.warn('data-dir', 'Old data directory cleanup rejected because the path is still in use', { cleanupId })\n return { success: false, error: 'Old data directory overlaps a directory still in use' }\n }\n if (!isPathSafe(sourceDir)) {\n appLogger.warn('data-dir', 'Old data directory cleanup rejected because the path is unsafe', { cleanupId })\n return { success: false, error: 'Old data directory is not safe to delete' }\n }\n\n try {\n if (fs.existsSync(sourceDir)) {\n if (!isExistingUserDataDir(sourceDir)) {\n appLogger.warn('data-dir', 'Old data directory cleanup rejected because the path is unrecognized', {\n cleanupId,\n })\n return { success: false, error: 'Old data directory is no longer recognized as ChatLab data' }\n }\n const remove = deps.removeDir ?? ((dir: string) => fs.rmSync(dir, { recursive: true, force: true }))\n remove(sourceDir)\n }\n\n writePendingDataDirCleanups(\n systemDir,\n entries.filter((entry) => entry.id !== cleanupId)\n )\n appLogger.info('data-dir', 'Old data directory cleanup completed by user', { cleanupId })\n return { success: true }\n } catch (error) {\n appLogger.error('data-dir', 'Failed to delete old data directory', error)\n return { success: false, error: 'Failed to delete old data directory' }\n }\n}\n\nexport function getPendingNodeDataDirMigration(systemDir: string): PendingDataDirMigration | null {\n const filePath = getPendingMigrationPath(systemDir)\n if (!fs.existsSync(filePath)) return null\n\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as PendingDataDirMigration\n if (!parsed.from || !parsed.to || typeof parsed.migrate !== 'boolean') return null\n return parsed\n } catch {\n return null\n }\n}\n\nexport function clearPendingNodeDataDirMigration(systemDir: string): void {\n const filePath = getPendingMigrationPath(systemDir)\n if (fs.existsSync(filePath)) {\n fs.unlinkSync(filePath)\n }\n}\n\nfunction writePendingNodeDataDirMigration(systemDir: string, pending: PendingDataDirMigration): void {\n const filePath = getPendingMigrationPath(systemDir)\n ensureDir(path.dirname(filePath))\n fs.writeFileSync(filePath, JSON.stringify(pending, null, 2), 'utf-8')\n}\n\nexport function createNodeDataDirSwitch(input: {\n systemDir: string\n currentDir: string\n targetDir: string | null\n defaultDir?: string\n migrate?: boolean\n envDataDir?: string\n}): DataDirSwitchResult {\n if (input.envDataDir) {\n return { success: false, error: 'CHATLAB_DATA_DIR is set, data directory cannot be changed from Web UI' }\n }\n\n const newDir = (input.targetDir?.trim() || input.defaultDir || '').trim()\n if (!newDir) return { success: false, error: 'Data directory is required' }\n if (!path.isAbsolute(newDir)) return { success: false, error: 'Data directory must be an absolute path' }\n if (!isPathSafe(newDir)) return { success: false, error: 'System directories cannot be used as data directory' }\n\n const migrate = input.migrate !== false\n if (migrate && path.resolve(input.currentDir) !== path.resolve(newDir) && isSubPath(input.currentDir, newDir)) {\n return { success: false, error: 'Target directory cannot be inside current data directory' }\n }\n\n if (!isUserDataDirSafeToUse(newDir)) {\n return { success: false, error: 'Target directory is not empty and is not a ChatLab data directory' }\n }\n\n if (path.resolve(input.currentDir) === path.resolve(newDir)) {\n clearPendingNodeDataDirMigration(input.systemDir)\n return { success: true, from: input.currentDir, to: newDir, requiresRelaunch: false }\n }\n\n const pending = createPendingDataDirMigration({\n from: input.currentDir,\n to: newDir,\n migrate,\n targetWasEmpty: isDirectoryEmptyOrMissing(newDir),\n })\n writePendingNodeDataDirMigration(input.systemDir, pending)\n\n return { success: true, from: input.currentDir, to: newDir, requiresRelaunch: true }\n}\n\nexport function applyPendingNodeDataDirMigration(\n systemDir: string,\n deps: ApplyPendingNodeDataDirMigrationDeps = {}\n): {\n success: boolean\n skipped?: boolean\n error?: string\n} {\n const pending = getPendingNodeDataDirMigration(systemDir)\n if (!pending) return { success: true, skipped: true }\n const writeConfig = deps.writeConfigField ?? writeConfigField\n\n const result = runPendingDataDirMigration(pending, {\n writeUserDataDir(dir) {\n writeConfig('data', 'user_data_dir', dir)\n writeConfig('data', 'electron_migration_done', true)\n },\n clearPendingMigration() {\n clearPendingNodeDataDirMigration(systemDir)\n },\n recordPendingCleanup(sourceDir, targetDir) {\n registerPendingDataDirCleanup(systemDir, { sourceDir, targetDir })\n },\n })\n\n if (!result.success) {\n return { success: false, error: result.errors.join('; ') || 'Data directory migration failed' }\n }\n\n return { success: true }\n}\n","/**\n * JiebaNlpProvider — NlpProvider 实现(基于 @node-rs/jieba)\n *\n * 提供给 @openchatlab/core 的 getLanguagePreferenceAnalysis 使用。\n * 仅在 Node.js 环境中可用(Electron worker / CLI server)。\n *\n * 使用 nlp/segmenter 的共享 getJieba() 实例,自动加载磁盘词库。\n */\n\nimport type { NlpProvider, PosTagResult } from '@openchatlab/core'\nimport { MEANINGFUL_POS_TAGS, isStopword } from '@openchatlab/core'\nimport { getJieba } from './nlp/segmenter'\nimport type { DictType } from '@openchatlab/core'\n\nexport function createJiebaNlpProvider(dictType: DictType = 'default'): NlpProvider {\n return {\n tag(text: string): PosTagResult[] {\n return getJieba(dictType).tag(text)\n },\n isStopword,\n meaningfulPosTags: MEANINGFUL_POS_TAGS,\n }\n}\n","/**\n * 词频统计(Node.js 实现)\n *\n * 从数据库查询消息,调用分词引擎进行词频统计。\n * 供 Electron worker 和 Server HTTP 路由共用。\n */\n\nimport { buildExcludeKeywordsConditions, isSystemMessageContent, type DatabaseAdapter } from '@openchatlab/core'\nimport { MessageType } from '@openchatlab/shared-types'\nimport type {\n SupportedLocale,\n DictType,\n WordFrequencyParams,\n WordFrequencyResult,\n PosTagStat,\n BatchSegmentResult,\n} from '@openchatlab/core'\nimport { segment, batchSegmentWithFrequency, batchSegmentChineseWithStats, collectPosTagStats } from './segmenter'\n\nfunction buildMessageQuery(\n timeFilter?: { startTs?: number; endTs?: number },\n memberId?: number,\n excludeKeywords?: string[]\n): { clause: string; params: unknown[] } {\n const conditions: string[] = []\n const params: unknown[] = []\n\n if (timeFilter?.startTs !== undefined) {\n conditions.push('msg.ts >= ?')\n params.push(timeFilter.startTs)\n }\n if (timeFilter?.endTs !== undefined) {\n conditions.push('msg.ts <= ?')\n params.push(timeFilter.endTs)\n }\n if (memberId !== undefined && memberId !== null) {\n conditions.push('msg.sender_id = ?')\n params.push(memberId)\n }\n\n if (excludeKeywords && excludeKeywords.length > 0) {\n const exclude = buildExcludeKeywordsConditions(excludeKeywords)\n conditions.push(...exclude.conditions)\n params.push(...exclude.params)\n }\n\n conditions.push(\"COALESCE(m.account_name, '') != '系统消息'\")\n conditions.push(`msg.type IN (${MessageType.TEXT}, ${MessageType.EMOJI})`)\n conditions.push('msg.content IS NOT NULL')\n conditions.push(\"TRIM(msg.content) != ''\")\n\n return {\n clause: ` WHERE ${conditions.join(' AND ')}`,\n params,\n }\n}\n\n/**\n * 从数据库计算词频统计\n */\nexport function computeWordFrequency(db: DatabaseAdapter, params: WordFrequencyParams): WordFrequencyResult {\n const {\n locale,\n timeFilter,\n memberId,\n topN = 100,\n minWordLength,\n minCount = 2,\n posFilterMode = 'meaningful',\n customPosTags,\n enableStopwords = true,\n dictType = 'default',\n excludeWords,\n excludeKeywords,\n } = params\n\n const { clause, params: filterParams } = buildMessageQuery(timeFilter, memberId, excludeKeywords)\n\n const messages = db\n .prepare(`SELECT msg.content FROM message msg JOIN member m ON msg.sender_id = m.id${clause}`)\n .all(...filterParams) as Array<{ content: string }>\n\n if (messages.length === 0) {\n return { words: [], totalWords: 0, totalMessages: 0, uniqueWords: 0 }\n }\n\n const analyzableMessages = messages.filter((message) => !isSystemMessageContent(message.content))\n if (analyzableMessages.length === 0) {\n return { words: [], totalWords: 0, totalMessages: 0, uniqueWords: 0 }\n }\n\n const texts = analyzableMessages.map((m) => m.content)\n\n const segmentOptions = {\n minLength: minWordLength,\n minCount,\n topN,\n posFilterMode,\n customPosTags,\n enableStopwords,\n dictType: dictType as DictType,\n excludeWords,\n }\n\n let posTagStats: PosTagStat[] | undefined\n let result: BatchSegmentResult\n\n // 中文 meaningful/custom 模式下,词频与词性统计可在一次分词内同时产出,避免重复分词。\n if (locale.startsWith('zh') && posFilterMode !== 'all') {\n const combined = batchSegmentChineseWithStats(texts, locale as SupportedLocale, segmentOptions)\n result = { words: combined.words, uniqueWords: combined.uniqueWords, totalWords: combined.totalWords }\n posTagStats = [...combined.posTagStats.entries()].map(([tag, count]) => ({ tag, count }))\n } else {\n if (locale.startsWith('zh')) {\n const posStatsMap = collectPosTagStats(texts, minWordLength ?? 2, enableStopwords, dictType as DictType)\n posTagStats = [...posStatsMap.entries()].map(([tag, count]) => ({ tag, count }))\n }\n result = batchSegmentWithFrequency(texts, locale as SupportedLocale, segmentOptions)\n }\n\n let topNTotalWords = 0\n for (const count of result.words.values()) topNTotalWords += count\n\n const words = [...result.words.entries()].map(([word, count]) => ({\n word,\n count,\n percentage: topNTotalWords > 0 ? Math.round((count / topNTotalWords) * 10000) / 100 : 0,\n }))\n\n return {\n words,\n totalWords: result.totalWords,\n totalMessages: analyzableMessages.length,\n uniqueWords: result.uniqueWords,\n posTagStats,\n }\n}\n\n/**\n * 单文本分词\n */\nexport function segmentText(text: string, locale: SupportedLocale, minLength?: number): string[] {\n return segment(text, locale, { minLength })\n}\n","/**\n * 词库管理器(Node.js 实现)\n *\n * 接收 nlpDir 参数而非依赖 Electron app 模块。\n * Electron 和 Server 各自传入自己的 nlpDir 路径。\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { createHash } from 'crypto'\nimport type { DictInfo } from '@openchatlab/core'\nimport { clearJiebaInstance } from './segmenter'\n\nconst DICT_DOWNLOAD_URL_BASE = 'https://chatlab.fun/assets/nlp'\nconst DICT_SHA256: Record<string, string> = {\n 'zh-CN': '139519822fe8ab9e10d9d07e68ea0451045380aedaf54ecc51e2a28c6b42a13f',\n 'zh-TW': 'a63ec7e388f16f1b486dcd948a9f1a3b492be5d9b6bdab786a95e59966786dfd',\n}\n\nconst AVAILABLE_DICTS: Array<{ id: string; label: string; locale: string }> = [\n { id: 'zh-CN', label: '简体中文', locale: 'zh-CN' },\n { id: 'zh-TW', label: '繁體中文', locale: 'zh-TW' },\n]\n\nfunction getDictFilePath(nlpDir: string, dictId: string): string {\n return path.join(nlpDir, `${dictId}.dict`)\n}\n\nexport function isDictDownloaded(nlpDir: string, dictId: string): boolean {\n return fs.existsSync(getDictFilePath(nlpDir, dictId))\n}\n\nexport function getDictList(nlpDir: string): DictInfo[] {\n return AVAILABLE_DICTS.map((d) => {\n const filePath = getDictFilePath(nlpDir, d.id)\n const downloaded = fs.existsSync(filePath)\n let fileSize: number | undefined\n if (downloaded) {\n try {\n fileSize = fs.statSync(filePath).size\n } catch {\n /* ignore */\n }\n }\n return { ...d, downloaded, fileSize }\n })\n}\n\nexport function loadDictBuffer(nlpDir: string, dictId: string): Buffer | null {\n const filePath = getDictFilePath(nlpDir, dictId)\n if (!fs.existsSync(filePath)) return null\n try {\n return fs.readFileSync(filePath)\n } catch (error) {\n console.error(`[NLP DictManager] Failed to read dict file: ${filePath}`, error)\n return null\n }\n}\n\nexport async function downloadDict(\n nlpDir: string,\n dictId: string,\n onProgress?: (percent: number) => void\n): Promise<{ success: boolean; error?: string }> {\n if (!AVAILABLE_DICTS.find((d) => d.id === dictId)) {\n return { success: false, error: `Unknown dict: ${dictId}` }\n }\n\n fs.mkdirSync(nlpDir, { recursive: true })\n const url = `${DICT_DOWNLOAD_URL_BASE}/${dictId}.dict`\n const filePath = getDictFilePath(nlpDir, dictId)\n const tmpPath = filePath + '.tmp'\n\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(120_000) })\n if (!response.ok) throw new Error(`Download failed: HTTP ${response.status}`)\n\n const total = Number(response.headers.get('content-length') || 0)\n let buffer: Buffer\n\n if (!response.body) {\n buffer = Buffer.from(await response.arrayBuffer())\n } else {\n const reader = response.body.getReader()\n const chunks: Buffer[] = []\n let loaded = 0\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n const chunk = Buffer.from(value)\n chunks.push(chunk)\n loaded += chunk.length\n if (total > 0 && onProgress) onProgress(Math.round((loaded / total) * 100))\n }\n buffer = Buffer.concat(chunks)\n }\n\n const MIN_DICT_SIZE = 1_000_000\n if (buffer.length < MIN_DICT_SIZE) {\n return { success: false, error: `Downloaded file is invalid (${buffer.length} bytes)` }\n }\n const head = buffer.subarray(0, 50).toString('utf-8').trim()\n if (head.startsWith('<!') || head.startsWith('<html')) {\n return { success: false, error: 'Downloaded file is HTML, not a dictionary file' }\n }\n\n const expectedSha256 = DICT_SHA256[dictId]\n if (!expectedSha256) {\n return { success: false, error: `Missing SHA256 checksum for dict: ${dictId}` }\n }\n const actualSha256 = createHash('sha256').update(buffer).digest('hex')\n if (actualSha256 !== expectedSha256) {\n return { success: false, error: 'Dictionary integrity check failed (SHA256 mismatch)' }\n }\n\n fs.writeFileSync(tmpPath, buffer)\n if (fs.existsSync(filePath)) fs.unlinkSync(filePath)\n fs.renameSync(tmpPath, filePath)\n clearJiebaInstance(dictId as any)\n\n console.log(`[NLP DictManager] Dict downloaded: ${dictId} (${fs.statSync(filePath).size} bytes)`)\n return { success: true }\n } catch (error) {\n if (fs.existsSync(tmpPath)) {\n try {\n fs.unlinkSync(tmpPath)\n } catch {\n /* ignore */\n }\n }\n const msg = error instanceof Error ? error.message : String(error)\n console.error(`[NLP DictManager] Download failed for ${dictId}:`, msg)\n return { success: false, error: msg }\n }\n}\n\nexport function deleteDict(nlpDir: string, dictId: string): { success: boolean; error?: string } {\n const filePath = getDictFilePath(nlpDir, dictId)\n if (!fs.existsSync(filePath)) return { success: true }\n try {\n fs.unlinkSync(filePath)\n clearJiebaInstance(dictId as any)\n console.log(`[NLP DictManager] Dict deleted: ${dictId}`)\n return { success: true }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n console.error(`[NLP DictManager] Delete failed for ${dictId}:`, msg)\n return { success: false, error: msg }\n }\n}\n\n/**\n * 自动下载默认词库(应用启动时调用)\n */\nexport async function ensureDefaultDict(nlpDir: string, bundledDictDir?: string): Promise<void> {\n if (isDictDownloaded(nlpDir, 'zh-CN')) return\n if (bundledDictDir) {\n const bundledPath = getDictFilePath(bundledDictDir, 'zh-CN')\n if (fs.existsSync(bundledPath)) {\n fs.mkdirSync(nlpDir, { recursive: true })\n const filePath = getDictFilePath(nlpDir, 'zh-CN')\n const tmpPath = filePath + '.tmp'\n fs.copyFileSync(bundledPath, tmpPath)\n fs.renameSync(tmpPath, filePath)\n console.log('[NLP DictManager] Installed bundled zh-CN dictionary')\n return\n }\n }\n console.log('[NLP DictManager] zh-CN dict not found, starting background download...')\n const result = await downloadDict(nlpDir, 'zh-CN')\n if (result.success) {\n console.log('[NLP DictManager] zh-CN dict auto-downloaded successfully')\n } else {\n console.warn('[NLP DictManager] zh-CN dict auto-download failed:', result.error)\n }\n}\n","/**\n * PreferencesManager — manages ~/.chatlab/preferences.json\n *\n * Stores complex user preferences that cannot fit into config.toml\n * (arrays, nested objects) and need cross-client consistency.\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { DESENSITIZE_RULES_SCHEMA_VERSION } from './ai/preprocessor'\nimport type {\n Preferences,\n AIGlobalSettings,\n AIPreprocessConfig,\n WordFilterScheme,\n KeywordTemplate,\n DesensitizeRule,\n FilterHistoryItem,\n} from '@openchatlab/shared-types'\n\nexport type {\n Preferences,\n AIGlobalSettings,\n AIPreprocessConfig,\n WordFilterScheme,\n KeywordTemplate,\n DesensitizeRule,\n FilterHistoryItem,\n}\n\nconst DEFAULTS: Preferences = {\n pinnedSessionIds: [],\n assistantUpgradeSkippedVersions: {},\n aiPreprocessConfig: {\n dataCleaning: true,\n mergeConsecutive: true,\n mergeWindowSeconds: 180,\n blacklistKeywords: [],\n denoise: true,\n desensitize: true,\n desensitizeRulesSchemaVersion: DESENSITIZE_RULES_SCHEMA_VERSION,\n desensitizeBuiltinRuleOverrides: {},\n desensitizeRules: [],\n anonymizeNames: false,\n },\n aiGlobalSettings: {\n maxMessagesPerRequest: 1000,\n exportFormat: 'markdown',\n sqlExportFormat: 'csv',\n enableAutoSkill: true,\n chartAutoMode: 'suggest',\n searchContextBefore: 2,\n searchContextAfter: 2,\n },\n customKeywordTemplates: [],\n deletedPresetTemplateIds: [],\n wordFilter: {\n schemes: [],\n defaultSchemeId: null,\n sessionSchemeOverrides: {},\n },\n filterHistory: [],\n thinkingLevels: {},\n ownerProfilesByPlatform: {},\n ownerExcludedSessionIds: [],\n}\n\ntype LegacyPreferences = Partial<Preferences> & {\n ownerPromptDismissedSessionIds?: unknown\n}\n\nexport class PreferencesManager {\n private filePath: string\n private cache: Preferences | null = null\n\n constructor(systemDir: string) {\n this.filePath = path.join(systemDir, 'preferences.json')\n }\n\n load(): Preferences {\n if (this.cache) return this.cache\n\n try {\n if (fs.existsSync(this.filePath)) {\n const raw = fs.readFileSync(this.filePath, 'utf-8')\n const parsed = JSON.parse(raw) as LegacyPreferences\n const desensitizeMigration = this.migrateLegacyDesensitizeRules(parsed, raw)\n const ownerMigration = this.migrateLegacyOwnerExclusions(desensitizeMigration.preferences)\n this.cache = this.mergeDefaults(ownerMigration.preferences)\n if (desensitizeMigration.changed || ownerMigration.changed) {\n this.writePreferences(this.cache)\n }\n return this.cache\n }\n } catch (err) {\n console.warn('[Preferences] Failed to load preferences.json:', err)\n }\n\n this.cache = { ...DEFAULTS }\n return this.cache\n }\n\n save(partial: Partial<Preferences>): { success: boolean; error?: string } {\n try {\n const current = this.load()\n const merged = this.deepMerge(\n current as unknown as Record<string, unknown>,\n partial as unknown as Record<string, unknown>\n )\n if (Object.prototype.hasOwnProperty.call(partial.aiPreprocessConfig ?? {}, 'desensitizeBuiltinRuleOverrides')) {\n const mergedAiPreprocessConfig = merged.aiPreprocessConfig as Record<string, unknown>\n mergedAiPreprocessConfig.desensitizeBuiltinRuleOverrides =\n partial.aiPreprocessConfig?.desensitizeBuiltinRuleOverrides\n }\n this.cache = this.mergeDefaults(merged as unknown as Partial<Preferences>)\n\n this.writePreferences(this.cache)\n return { success: true }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n console.error('[Preferences] Failed to save:', msg)\n return { success: false, error: msg }\n }\n }\n\n getFilePath(): string {\n return this.filePath\n }\n\n invalidateCache(): void {\n this.cache = null\n }\n\n private mergeDefaults(partial: Partial<Preferences>): Preferences {\n return {\n pinnedSessionIds: partial.pinnedSessionIds ?? DEFAULTS.pinnedSessionIds,\n assistantUpgradeSkippedVersions: this.normalizePositiveIntegerMap(partial.assistantUpgradeSkippedVersions),\n aiPreprocessConfig: partial.aiPreprocessConfig\n ? this.normalizeAiPreprocessConfig(partial.aiPreprocessConfig)\n : { ...DEFAULTS.aiPreprocessConfig },\n aiGlobalSettings: this.normalizeAiGlobalSettings(partial.aiGlobalSettings),\n customKeywordTemplates: partial.customKeywordTemplates ?? DEFAULTS.customKeywordTemplates,\n deletedPresetTemplateIds: partial.deletedPresetTemplateIds ?? DEFAULTS.deletedPresetTemplateIds,\n wordFilter: partial.wordFilter ? { ...DEFAULTS.wordFilter, ...partial.wordFilter } : { ...DEFAULTS.wordFilter },\n filterHistory: partial.filterHistory ?? DEFAULTS.filterHistory,\n thinkingLevels: partial.thinkingLevels ?? DEFAULTS.thinkingLevels,\n ownerProfilesByPlatform: partial.ownerProfilesByPlatform ?? DEFAULTS.ownerProfilesByPlatform,\n ownerExcludedSessionIds: this.normalizeStringArray(partial.ownerExcludedSessionIds),\n }\n }\n\n private normalizeAiGlobalSettings(partial: Partial<AIGlobalSettings> | undefined): AIGlobalSettings {\n const normalized = { ...(partial ?? {}) } as Record<string, unknown>\n // Ignore removed settings so legacy values cannot survive normalization\n // and accidentally re-enable obsolete behavior after a later save.\n delete normalized.contextCompression\n delete normalized.allowProactiveMemory\n return { ...DEFAULTS.aiGlobalSettings, ...(normalized as Partial<AIGlobalSettings>) }\n }\n\n private normalizeAiPreprocessConfig(partial: Partial<AIPreprocessConfig> | undefined): AIPreprocessConfig {\n const defaults = DEFAULTS.aiPreprocessConfig\n const rules = Array.isArray(partial?.desensitizeRules) ? partial.desensitizeRules : []\n const customRules = rules.filter((rule) => !rule.builtin)\n return {\n dataCleaning: partial?.dataCleaning ?? defaults.dataCleaning,\n mergeConsecutive: partial?.mergeConsecutive ?? defaults.mergeConsecutive,\n mergeWindowSeconds: partial?.mergeWindowSeconds ?? defaults.mergeWindowSeconds,\n blacklistKeywords: partial?.blacklistKeywords ?? defaults.blacklistKeywords,\n denoise: partial?.denoise ?? defaults.denoise,\n desensitize: partial?.desensitize ?? defaults.desensitize,\n desensitizeRulesSchemaVersion: DESENSITIZE_RULES_SCHEMA_VERSION,\n desensitizeBuiltinRuleOverrides: this.normalizeBooleanMap(partial?.desensitizeBuiltinRuleOverrides),\n desensitizeRules: customRules,\n anonymizeNames: partial?.anonymizeNames ?? defaults.anonymizeNames,\n }\n }\n\n private normalizeBooleanMap(value: unknown): Record<string, boolean> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return {}\n const result: Record<string, boolean> = {}\n for (const [key, flag] of Object.entries(value as Record<string, unknown>)) {\n if (typeof flag === 'boolean') result[key] = flag\n }\n return result\n }\n\n private normalizePositiveIntegerMap(value: unknown): Record<string, number> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return {}\n const result: Record<string, number> = {}\n for (const [key, version] of Object.entries(value as Record<string, unknown>)) {\n if (typeof version === 'number' && Number.isInteger(version) && version > 0) {\n result[key] = version\n }\n }\n return result\n }\n\n private normalizeStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return []\n return [...new Set(value.filter((item): item is string => typeof item === 'string' && item.length > 0))]\n }\n\n private migrateLegacyOwnerExclusions(partial: LegacyPreferences): {\n preferences: Partial<Preferences>\n changed: boolean\n } {\n if (partial.ownerPromptDismissedSessionIds === undefined) {\n return { preferences: partial, changed: false }\n }\n const { ownerPromptDismissedSessionIds, ...preferences } = partial\n return {\n preferences: {\n ...preferences,\n ownerExcludedSessionIds:\n partial.ownerExcludedSessionIds ?? this.normalizeStringArray(ownerPromptDismissedSessionIds),\n },\n changed: true,\n }\n }\n\n private migrateLegacyDesensitizeRules(\n partial: Partial<Preferences>,\n rawContent: string\n ): { preferences: Partial<Preferences>; changed: boolean } {\n const rules = partial.aiPreprocessConfig?.desensitizeRules\n if (!Array.isArray(rules) || !rules.some((rule) => rule.builtin)) {\n return { preferences: partial, changed: false }\n }\n\n this.backupLegacyPreferences(rawContent)\n\n const legacyBuiltinRuleOverrides = rules\n .filter((rule) => rule.builtin && typeof rule.enabled === 'boolean')\n .reduce<Record<string, boolean>>((overrides, rule) => {\n overrides[rule.id] = rule.enabled\n return overrides\n }, {})\n const existingOverrides = this.normalizeBooleanMap(partial.aiPreprocessConfig?.desensitizeBuiltinRuleOverrides)\n\n return {\n preferences: {\n ...partial,\n aiPreprocessConfig: {\n ...partial.aiPreprocessConfig,\n desensitizeRulesSchemaVersion: DESENSITIZE_RULES_SCHEMA_VERSION,\n desensitizeBuiltinRuleOverrides: {\n ...legacyBuiltinRuleOverrides,\n ...existingOverrides,\n },\n desensitizeRules: rules.filter((rule) => !rule.builtin),\n },\n } as Partial<Preferences>,\n changed: true,\n }\n }\n\n private backupLegacyPreferences(rawContent: string): void {\n const backupDir = path.join(path.dirname(this.filePath), 'backups')\n if (!fs.existsSync(backupDir)) {\n fs.mkdirSync(backupDir, { recursive: true })\n }\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-')\n const backupPath = path.join(backupDir, `preferences-pre-desensitize-groups-${timestamp}.json`)\n fs.writeFileSync(backupPath, rawContent, 'utf-8')\n console.info(`[Preferences] Backed up legacy desensitize rules to ${backupPath}`)\n }\n\n private writePreferences(preferences: Preferences): void {\n const dir = path.dirname(this.filePath)\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n fs.writeFileSync(this.filePath, JSON.stringify(preferences, null, 2), 'utf-8')\n }\n\n /**\n * Deep merge: arrays are replaced (not concatenated), objects are merged.\n */\n private deepMerge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const [key, value] of Object.entries(override)) {\n if (value === undefined) continue\n if (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n typeof base[key] === 'object' &&\n base[key] !== null &&\n !Array.isArray(base[key])\n ) {\n result[key] = this.deepMerge(base[key] as Record<string, unknown>, value as Record<string, unknown>)\n } else {\n result[key] = value\n }\n }\n return result\n }\n}\n","/**\n * Merger orchestration — abstract data-source reading, conflict checking,\n * merge assembly, and ChatLab output formatting.\n *\n * Decoupled from Electron-specific TempDbReader via MergerDataSource interface.\n */\n\nimport {\n getCollidingPlatformIds,\n getCollidingPlatformIdsFromMessages,\n normalizePlatformId,\n detectConflictsInMessages,\n mergeMergerMembers,\n type MergerMember,\n type MergerMessage,\n type ConflictCheckResult,\n type MergedMember,\n type MergedMessage,\n} from '@openchatlab/core'\nimport { CHATLAB_FORMAT_VERSION } from '@openchatlab/shared-types'\nimport {\n createMessageDedupState,\n generateFallbackMessageKey,\n hasUnmatchedFallbackOnlyMessage,\n registerMessageAndCheckDuplicate,\n} from '../import/message-deduplicator'\n\nexport interface MergerInputMessage extends MergerMessage {\n platformMessageId?: string\n replyToMessageId?: string\n}\n\nexport interface ChatLabMergedMessage extends MergedMessage {\n platformMessageId?: string\n replyToMessageId?: string\n}\n\n// ==================== Data source abstraction ====================\n\nexport interface MergerSourceMeta {\n name: string\n platform: string\n type: string\n groupId?: string\n groupAvatar?: string\n ownerId?: string\n}\n\nfunction createMessageScope(meta: MergerSourceMeta | null, members: MergerMember[], sourceIndex: number): string {\n const platform = meta?.platform || 'unknown'\n const type = meta?.type || 'unknown'\n\n if (meta?.groupId) return JSON.stringify([platform, type, 'group', meta.groupId])\n\n // A group name and its membership can both collide or change over time. Keep\n // the source isolated until exact overlapping messages prove it is the same chat.\n if (type === 'group') return JSON.stringify([platform, type, 'source', sourceIndex])\n\n const memberIds = [...new Set(members.map((member) => member.platformId))].sort()\n if (memberIds.length > 0) {\n if (type === 'private') {\n if (memberIds.length >= 2) return JSON.stringify([platform, type, 'members', memberIds])\n } else {\n return JSON.stringify([platform, type, 'name-members', meta?.name || '', memberIds])\n }\n }\n\n // A one-sided private export does not identify the other participant. Without\n // a stable group ID or complete participant set, keep message IDs source-local.\n return JSON.stringify([platform, type, 'source', sourceIndex])\n}\n\nfunction createMessageBridgeFamily(meta: MergerSourceMeta | null): string | undefined {\n if (!meta || meta.groupId || (meta.type !== 'group' && meta.type !== 'private')) return undefined\n // The exact message signature proves overlap; the editable chat name must\n // not prevent two exports of the same chat from sharing a scope.\n return JSON.stringify([meta.platform || 'unknown', meta.type])\n}\n\nfunction createMessageIdNormalizer(\n scopes: Iterable<string>\n): (id: string | undefined, scope: string) => string | undefined {\n const uniqueScopes = [...new Set(scopes)]\n const scopeIndexes = new Map(uniqueScopes.map((scope, index) => [scope, index]))\n const namespaceMessageIds = uniqueScopes.length > 1\n\n return (id, scope) => {\n if (!id || !namespaceMessageIds) return id\n return `__chatlab_message_scope__${scopeIndexes.get(scope) ?? 0}__${encodeURIComponent(id)}`\n }\n}\n\ninterface MessageScopeContext {\n sourceIndex: number\n messageScope: string\n messageBridgeFamily?: string\n}\n\nfunction createFallbackOccurrenceTracker(): (message: MergerInputMessage, sourceIndex: number) => boolean {\n // Overlapping exports contribute the maximum occurrence count for each\n // fallback key, rather than collapsing to one message or summing all copies.\n const maximumOccurrences = new Map<string, number>()\n const sourceOccurrences = new Map<number, Map<string, number>>()\n\n return (message, sourceIndex) => {\n if (message.platformMessageId) return false\n\n const fallbackKey = generateFallbackMessageKey({\n timestamp: message.timestamp,\n senderPlatformId: message.senderPlatformId,\n type: message.type,\n content: message.content ?? null,\n replyToMessageId: message.replyToMessageId,\n })\n let occurrences = sourceOccurrences.get(sourceIndex)\n if (!occurrences) {\n occurrences = new Map<string, number>()\n sourceOccurrences.set(sourceIndex, occurrences)\n }\n const occurrence = (occurrences.get(fallbackKey) ?? 0) + 1\n occurrences.set(fallbackKey, occurrence)\n\n const previousMaximum = maximumOccurrences.get(fallbackKey) ?? 0\n if (occurrence <= previousMaximum) return true\n maximumOccurrences.set(fallbackKey, occurrence)\n return false\n }\n}\n\nfunction createMessageScopeResolver(contexts: Iterable<MessageScopeContext>): {\n addMessage: (message: MergerInputMessage, context: MessageScopeContext) => void\n complete: () => void\n resolve: (sourceIndex: number) => string\n} {\n const contextBySource = new Map<number, MessageScopeContext>()\n const parents = new Map<number, number>()\n const firstSourceBySignature = new Map<string, number>()\n\n for (const context of contexts) {\n contextBySource.set(context.sourceIndex, context)\n parents.set(context.sourceIndex, context.sourceIndex)\n }\n\n const find = (sourceIndex: number): number => {\n const parent = parents.get(sourceIndex) ?? sourceIndex\n if (parent === sourceIndex) return sourceIndex\n const root = find(parent)\n parents.set(sourceIndex, root)\n return root\n }\n\n const union = (firstSourceIndex: number, secondSourceIndex: number): void => {\n const firstRoot = find(firstSourceIndex)\n const secondRoot = find(secondSourceIndex)\n if (firstRoot === secondRoot) return\n\n const root = Math.min(firstRoot, secondRoot)\n parents.set(firstRoot === root ? secondRoot : firstRoot, root)\n }\n\n return {\n addMessage(message, context) {\n if (!context.messageBridgeFamily || !message.platformMessageId) return\n\n const fallbackKey = generateFallbackMessageKey({\n timestamp: message.timestamp,\n senderPlatformId: message.senderPlatformId,\n type: message.type,\n content: message.content ?? null,\n replyToMessageId: message.replyToMessageId,\n })\n const signature = JSON.stringify([context.messageBridgeFamily, message.platformMessageId, fallbackKey])\n const firstSourceIndex = firstSourceBySignature.get(signature)\n if (firstSourceIndex === undefined) {\n firstSourceBySignature.set(signature, context.sourceIndex)\n return\n }\n union(firstSourceIndex, context.sourceIndex)\n },\n complete() {\n firstSourceBySignature.clear()\n },\n resolve(sourceIndex) {\n const rootContext = contextBySource.get(find(sourceIndex))\n return rootContext?.messageScope ?? JSON.stringify(['unknown', 'source', sourceIndex])\n },\n }\n}\n\n/**\n * Abstract data source for merger input.\n * In Electron, this wraps TempDbReader. Other platforms can implement\n * their own (e.g. reading from IndexedDB, REST API, etc.).\n */\nexport interface MergerDataSource {\n getMeta(): MergerSourceMeta | null\n getMembers(): MergerMember[]\n getMessageCount(): number\n streamMessages(batchSize: number, callback: (messages: MergerInputMessage[]) => void): void\n}\n\n// ==================== Output types ====================\n\nexport interface MergeSourceInfo {\n filename: string\n platform: string\n messageCount: number\n}\n\nexport interface ChatLabHeader {\n version: typeof CHATLAB_FORMAT_VERSION\n exportedAt: number\n generator: string\n description: string\n}\n\nexport interface ChatLabMeta {\n name: string\n platform: string\n type: string\n sources: MergeSourceInfo[]\n groupId?: string\n groupAvatar?: string\n ownerId?: string\n}\n\nexport interface ChatLabOutput {\n chatlab: ChatLabHeader\n meta: ChatLabMeta\n members: MergedMember[]\n messages: ChatLabMergedMessage[]\n}\n\n// ==================== Conflict checking ====================\n\nexport function checkConflictsFromSources(\n dataSources: Array<{ source: MergerDataSource; filename: string }>\n): ConflictCheckResult {\n const preparedSources = dataSources.map(({ source, filename }, sourceIndex) => {\n const meta = source.getMeta()\n const members = source.getMembers()\n return {\n source,\n filename,\n sourceIndex,\n platform: meta?.platform || 'unknown',\n messageScope: createMessageScope(meta, members, sourceIndex),\n messageBridgeFamily: createMessageBridgeFamily(meta),\n }\n })\n const allMessages: Array<{\n msg: MergerInputMessage\n source: string\n sourceIndex: number\n platform: string\n messageScope: string\n messageBridgeFamily?: string\n }> = []\n\n for (const { source, filename, sourceIndex, platform, messageScope, messageBridgeFamily } of preparedSources) {\n source.streamMessages(10000, (messages) => {\n for (const msg of messages) {\n allMessages.push({ msg, source: filename, sourceIndex, platform, messageScope, messageBridgeFamily })\n }\n })\n }\n\n const result = detectConflictsInMessages(allMessages)\n const collidingIds = getCollidingPlatformIdsFromMessages(allMessages)\n const scopeResolver = createMessageScopeResolver(preparedSources)\n for (const message of allMessages) scopeResolver.addMessage(message.msg, message)\n scopeResolver.complete()\n const normalizeMessageId = createMessageIdNormalizer(\n preparedSources.map(({ sourceIndex }) => scopeResolver.resolve(sourceIndex))\n )\n const dedupState = createMessageDedupState([], [], [], { preserveFallbackMultiplicity: true })\n const isCoveredFallbackOccurrence = createFallbackOccurrenceTracker()\n let totalMessages = 0\n\n for (const { msg, sourceIndex, platform } of allMessages) {\n const messageScope = scopeResolver.resolve(sourceIndex)\n const senderPlatformId = normalizePlatformId(msg.senderPlatformId, platform, collidingIds)\n const dedupMessage = {\n platformMessageId: normalizeMessageId(msg.platformMessageId, messageScope),\n timestamp: msg.timestamp,\n senderPlatformId,\n type: msg.type,\n content: msg.content ?? null,\n replyToMessageId: normalizeMessageId(msg.replyToMessageId, messageScope),\n }\n const duplicate =\n isCoveredFallbackOccurrence(dedupMessage, sourceIndex) ||\n registerMessageAndCheckDuplicate(dedupMessage, dedupState)\n if (!duplicate) totalMessages++\n }\n\n return { ...result, totalMessages }\n}\n\n// ==================== Merge orchestration ====================\n\nexport interface MergeOrchestrationResult {\n success: true\n chatLabData: ChatLabOutput\n}\n\n/**\n * Build a merged ChatLabOutput from multiple data sources.\n * Pure orchestration: reads data sources, calls core algorithms,\n * assembles the output. Does NOT write to disk or import to DB.\n */\nexport function buildMergedOutput(\n dataSources: Array<{ source: MergerDataSource; filename: string }>,\n outputName: string\n): MergeOrchestrationResult {\n const metas = dataSources.map(({ source, filename }, sourceIndex) => {\n const meta = source.getMeta()\n const members = source.getMembers()\n return {\n meta,\n members,\n filename,\n source,\n sourceIndex,\n messageScope: createMessageScope(meta, members, sourceIndex),\n messageBridgeFamily: createMessageBridgeFamily(meta),\n }\n })\n\n const collidingIds = getCollidingPlatformIds(\n metas.map(({ meta, members }) => ({\n platform: meta?.platform || 'unknown',\n members: members.map((m) => ({ platformId: m.platformId })),\n }))\n )\n\n const memberMap = mergeMergerMembers(\n metas.map(({ meta, members }) => ({\n platform: meta?.platform || 'unknown',\n members,\n })),\n collidingIds\n )\n\n const uniquePlatforms = [...new Set(metas.map(({ meta }) => meta?.platform || 'unknown'))]\n const scopeResolver = createMessageScopeResolver(metas)\n for (const context of metas) {\n if (!context.messageBridgeFamily) continue\n context.source.streamMessages(10000, (messages) => {\n for (const message of messages) scopeResolver.addMessage(message, context)\n })\n }\n scopeResolver.complete()\n const normalizeMessageId = createMessageIdNormalizer(\n metas.map(({ sourceIndex }) => scopeResolver.resolve(sourceIndex))\n )\n\n // Streaming dedup: prefer stable platform message IDs and use the content\n // fingerprint only for messages that do not have one.\n const dedupState = createMessageDedupState([], [], [], { preserveFallbackMultiplicity: true })\n const isCoveredFallbackOccurrence = createFallbackOccurrenceTracker()\n const fallbackOnlyMessageIndexes = new Map<string, number[]>()\n const mergedMessages: ChatLabMergedMessage[] = []\n\n for (const { source, meta, sourceIndex } of metas) {\n const platform = meta?.platform || 'unknown'\n const messageScope = scopeResolver.resolve(sourceIndex)\n source.streamMessages(10000, (messages) => {\n for (const msg of messages) {\n const nid = normalizePlatformId(msg.senderPlatformId, platform, collidingIds)\n const platformMessageId = normalizeMessageId(msg.platformMessageId, messageScope)\n const replyToMessageId = normalizeMessageId(msg.replyToMessageId, messageScope)\n const dedupMessage = {\n platformMessageId,\n timestamp: msg.timestamp,\n senderPlatformId: nid,\n type: msg.type,\n content: msg.content ?? null,\n replyToMessageId,\n }\n const fallbackKey = generateFallbackMessageKey(dedupMessage)\n if (isCoveredFallbackOccurrence(dedupMessage, sourceIndex)) continue\n const shouldBackfillId = Boolean(\n platformMessageId &&\n !dedupState.platformMessageIds.has(platformMessageId) &&\n hasUnmatchedFallbackOnlyMessage(dedupState, fallbackKey)\n )\n\n if (registerMessageAndCheckDuplicate(dedupMessage, dedupState)) {\n if (shouldBackfillId) {\n const retainedIndexes = fallbackOnlyMessageIndexes.get(fallbackKey)\n const retainedIndex = retainedIndexes?.shift()\n if (retainedIndex !== undefined) {\n mergedMessages[retainedIndex].platformMessageId = platformMessageId\n if (retainedIndexes?.length === 0) fallbackOnlyMessageIndexes.delete(fallbackKey)\n }\n }\n continue\n }\n\n const retainedIndex = mergedMessages.length\n mergedMessages.push({\n platformMessageId,\n sender: nid,\n accountName: msg.senderAccountName,\n groupNickname: msg.senderGroupNickname,\n timestamp: msg.timestamp,\n type: msg.type,\n content: msg.content,\n replyToMessageId,\n })\n if (!platformMessageId) {\n const retainedIndexes = fallbackOnlyMessageIndexes.get(fallbackKey) ?? []\n retainedIndexes.push(retainedIndex)\n fallbackOnlyMessageIndexes.set(fallbackKey, retainedIndexes)\n }\n }\n })\n }\n\n mergedMessages.sort((a, b) => a.timestamp - b.timestamp)\n\n const sources: MergeSourceInfo[] = dataSources.map(({ source, filename }) => ({\n filename,\n platform: source.getMeta()?.platform || 'unknown',\n messageCount: source.getMessageCount(),\n }))\n\n const platform = uniquePlatforms.length === 1 ? uniquePlatforms[0] : 'mixed'\n\n const groupIds = new Set(metas.map(({ meta }) => meta?.groupId).filter(Boolean))\n const groupId = groupIds.size === 1 ? metas.find(({ meta }) => meta?.groupId)?.meta?.groupId : undefined\n const groupAvatar = groupId\n ? metas.filter(({ meta }) => meta?.groupId === groupId).pop()?.meta?.groupAvatar\n : undefined\n const ownerIds = new Set(metas.map(({ meta }) => meta?.ownerId).filter((id): id is string => Boolean(id)))\n const ownerCandidate = uniquePlatforms.length === 1 && ownerIds.size === 1 ? [...ownerIds][0] : undefined\n const ownerId = ownerCandidate && memberMap.has(ownerCandidate) ? ownerCandidate : undefined\n\n const chatLabData: ChatLabOutput = {\n chatlab: {\n version: CHATLAB_FORMAT_VERSION,\n exportedAt: Math.floor(Date.now() / 1000),\n generator: 'ChatLab Merge Tool',\n description: `Merged from ${dataSources.length} files`,\n },\n meta: {\n name: outputName,\n platform,\n type: metas[0]?.meta?.type || 'group',\n sources,\n groupId,\n groupAvatar,\n ownerId,\n },\n members: Array.from(memberMap.values()),\n messages: mergedMessages,\n }\n\n return { success: true, chatLabData }\n}\n\n// ==================== JSONL serialization ====================\n\n/**\n * Serialize ChatLabOutput to JSONL lines (generator for streaming writes).\n */\nexport function* serializeChatLabToJsonl(data: ChatLabOutput): Generator<string> {\n yield JSON.stringify({\n _type: 'header',\n chatlab: data.chatlab,\n meta: data.meta,\n })\n\n for (const member of data.members) {\n yield JSON.stringify({ _type: 'member', ...member })\n }\n\n for (const msg of data.messages) {\n yield JSON.stringify({ _type: 'message', ...msg })\n }\n}\n","import * as path from 'path'\nimport { randomUUID } from 'node:crypto'\nimport type { AnalyticsAppType, AnalyticsEventName, AnalyticsPropertyValue } from '@openchatlab/shared-types'\nimport { readJsonFile, withFileLock, writeJsonFileAtomically } from '@openchatlab/config'\nimport { appLogger } from '../logging/app-logger'\n\nexport interface AnalyticsServiceOptions {\n appVersion: string\n appType: AnalyticsAppType\n umami?: {\n endpoint: string\n websiteId: string\n }\n getAiModelConfigured?: () => boolean\n}\n\ninterface AnalyticsData {\n lastReportDate: string | null\n firstReportDate: string | null\n anonymousId: string | null\n enabled: boolean\n}\n\ninterface NormalizedEvent {\n name: AnalyticsEventName\n properties: Record<string, AnalyticsPropertyValue>\n}\n\ninterface AnalyticsEnvelope extends NormalizedEvent {\n anonymousId: string\n sessionId: string\n appVersion: string\n appType: AnalyticsAppType\n os: 'macos' | 'windows' | 'linux' | 'other'\n appLocale: string\n aiModelConfigured: boolean\n}\n\nconst DEFAULT_DATA: AnalyticsData = {\n lastReportDate: null,\n firstReportDate: null,\n anonymousId: null,\n enabled: true,\n}\n\nconst EVENT_NAMES = new Set<AnalyticsEventName>([\n 'app_started',\n 'app_active_new',\n 'app_active',\n 'chat_import_started',\n 'chat_import_completed',\n 'chat_import_failed',\n 'incremental_import_used',\n 'feature_used',\n 'ai_setup_completed',\n 'ai_request_started',\n 'ai_request_completed',\n])\n\nconst FEATURE_IDS = new Set([\n 'insights',\n 'ranking',\n 'ai_chat',\n 'sql_lab',\n 'message_search',\n 'member_management',\n 'session_merge',\n 'export',\n])\n\nconst FAILURE_REASONS = new Set([\n 'auth',\n 'network',\n 'rate_limit',\n 'model_not_found',\n 'aborted',\n 'parse',\n 'write',\n 'unknown',\n])\n\nconst APP_LOCALES = new Set(['zh-CN', 'zh-TW', 'en-US', 'ja-JP'])\n\nfunction getUmamiConfigFromEnv(): AnalyticsServiceOptions['umami'] | undefined {\n const endpoint = process.env.UMAMI_ENDPOINT?.trim()\n const websiteId = process.env.UMAMI_WEBSITE_ID?.trim()\n return endpoint && websiteId ? { endpoint, websiteId } : undefined\n}\n\nfunction normalizeOs(): AnalyticsEnvelope['os'] {\n if (process.platform === 'darwin') return 'macos'\n if (process.platform === 'win32') return 'windows'\n if (process.platform === 'linux') return 'linux'\n return 'other'\n}\n\nfunction normalizeLocale(value: unknown): string {\n if (typeof value !== 'string') return 'unknown'\n const trimmed = value.trim()\n return APP_LOCALES.has(trimmed) ? trimmed : 'unknown'\n}\n\nfunction normalizeAnalyticsImportPlatform(value: unknown): string {\n if (typeof value !== 'string') return 'unknown'\n const platform = value.trim()\n // Keep custom import-format categories to measure unsupported formats.\n // This is not a general privacy sanitizer; only paths and control characters are excluded.\n const hasPathOrControlCharacter = [...platform].some(\n (char) => char === '/' || char === '\\\\' || char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127\n )\n return platform.length > 0 && platform.length <= 64 && !hasPathOrControlCharacter ? platform : 'unknown'\n}\n\nfunction normalizeDuration(value: unknown): number | null {\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) return null\n return Math.min(Math.round(value), 24 * 60 * 60 * 1000)\n}\n\nfunction normalizeEvent(eventName: string, props: Record<string, unknown> = {}): NormalizedEvent | null {\n if (!EVENT_NAMES.has(eventName as AnalyticsEventName)) return null\n const name = eventName as AnalyticsEventName\n const properties: Record<string, AnalyticsPropertyValue> = {}\n\n if (name.startsWith('chat_import_')) {\n properties.chat_platform = normalizeAnalyticsImportPlatform(props.chat_platform)\n }\n\n if (name === 'chat_import_completed' || name === 'ai_request_completed') {\n const duration = normalizeDuration(props.duration_ms)\n if (duration !== null) properties.duration_ms = duration\n }\n\n if (name === 'feature_used') {\n if (typeof props.feature_id !== 'string' || !FEATURE_IDS.has(props.feature_id)) return null\n properties.feature_id = props.feature_id\n }\n\n if (name === 'ai_request_completed') {\n if (typeof props.success !== 'boolean') return null\n properties.success = props.success\n }\n\n if (name === 'chat_import_failed' || (name === 'ai_request_completed' && props.success === false)) {\n const reason = typeof props.failure_reason === 'string' ? props.failure_reason : 'unknown'\n properties.failure_reason = FAILURE_REASONS.has(reason) ? reason : 'unknown'\n }\n\n return { name, properties }\n}\n\nfunction eventPath(event: NormalizedEvent): string {\n if (event.name === 'incremental_import_used') return '/import/incremental'\n if (event.name.startsWith('chat_import_')) return '/import'\n if (event.name.startsWith('ai_')) return '/ai'\n if (event.name === 'feature_used') return `/features/${event.properties.feature_id}`\n return '/app'\n}\n\nexport class AnalyticsService {\n private readonly dataPath: string\n private readonly options: AnalyticsServiceOptions\n private readonly sessionId = randomUUID()\n private appLocale = 'unknown'\n private startupAttempted = false\n // Product constraint: only one ChatLab runtime is expected to use a system directory at a time.\n // Daily-active deduplication is intentionally process-local unless concurrent runtimes become supported.\n private dailyActivePromise: Promise<void> | null = null\n\n constructor(systemDir: string, options: AnalyticsServiceOptions) {\n this.dataPath = path.join(systemDir, 'analytics.json')\n this.options = {\n ...options,\n umami: options.umami ?? getUmamiConfigFromEnv(),\n }\n }\n\n private load(): AnalyticsData {\n try {\n const stored = readJsonFile<Partial<AnalyticsData>>(this.dataPath)\n if (stored) return { ...DEFAULT_DATA, ...stored }\n } catch (error) {\n appLogger.error('analytics', 'Failed to read analytics settings; using defaults', error)\n }\n return { ...DEFAULT_DATA }\n }\n\n private updateData<T>(update: (data: AnalyticsData) => T, fallback: T): T {\n try {\n return withFileLock(this.dataPath, () => {\n const data = this.load()\n const result = update(data)\n writeJsonFileAtomically(this.dataPath, data, 0o600)\n return result\n })\n } catch (error) {\n appLogger.error('analytics', 'Failed to update analytics settings', error)\n return fallback\n }\n }\n\n private getOrCreateAnonymousId(): string {\n const fallback = randomUUID()\n return this.updateData((data) => {\n data.anonymousId ??= randomUUID()\n return data.anonymousId\n }, fallback)\n }\n\n private isAiModelConfigured(): boolean {\n try {\n return this.options.getAiModelConfigured?.() === true\n } catch (error) {\n appLogger.error('analytics', 'Failed to resolve AI configuration state', error)\n return false\n }\n }\n\n private buildEnvelope(event: NormalizedEvent): AnalyticsEnvelope {\n return {\n ...event,\n anonymousId: this.getOrCreateAnonymousId(),\n sessionId: this.sessionId,\n appVersion: this.options.appVersion,\n appType: this.options.appType,\n os: normalizeOs(),\n appLocale: this.appLocale,\n aiModelConfigured: this.isAiModelConfigured(),\n }\n }\n\n private commonProperties(envelope: AnalyticsEnvelope): Record<string, AnalyticsPropertyValue> {\n return {\n session_id: envelope.sessionId,\n app_version: envelope.appVersion,\n app_type: envelope.appType,\n os: envelope.os,\n app_locale: envelope.appLocale,\n ai_model_configured: envelope.aiModelConfigured,\n schema_version: 1,\n }\n }\n\n private async sendToUmami(envelope: AnalyticsEnvelope): Promise<boolean> {\n const umami = this.options.umami\n if (!umami) return false\n try {\n const response = await fetch(umami.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': `ChatLab/${envelope.appVersion} (${envelope.os}; ${envelope.appType})`,\n },\n body: JSON.stringify({\n type: 'event',\n payload: {\n website: umami.websiteId,\n hostname: 'chatlab',\n url: eventPath(envelope),\n language: envelope.appLocale,\n name: envelope.name,\n id: envelope.anonymousId,\n data: {\n ...this.commonProperties(envelope),\n ...envelope.properties,\n },\n },\n }),\n signal: AbortSignal.timeout(5000),\n })\n if (!response.ok) {\n appLogger.warn('analytics', 'Umami rejected analytics event', {\n eventName: envelope.name,\n status: response.status,\n })\n }\n return response.ok\n } catch (error) {\n appLogger.error('analytics', 'Failed to send analytics event to Umami', error)\n return false\n }\n }\n\n getEnabled(): boolean {\n return this.load().enabled\n }\n\n setEnabled(enabled: boolean): void {\n this.updateData((data) => {\n data.enabled = enabled\n }, undefined)\n }\n\n setAppLocale(locale: string): void {\n this.appLocale = normalizeLocale(locale)\n }\n\n async track(eventName: string, props?: Record<string, unknown>): Promise<boolean> {\n if (!this.getEnabled()) return false\n if (props?.app_locale !== undefined) this.setAppLocale(String(props.app_locale))\n const event = normalizeEvent(eventName, props)\n if (!event) return false\n if (!this.options.umami) return false\n\n const envelope = this.buildEnvelope(event)\n const delivered = await this.sendToUmami(envelope)\n appLogger.debug('analytics', delivered ? 'Analytics event delivered' : 'Analytics event was not delivered', {\n eventName: envelope.name,\n })\n return delivered\n }\n\n trackDailyActive(props?: Record<string, unknown>): Promise<void> {\n if (this.dailyActivePromise) {\n const locale = props?.app_locale ?? props?.locale\n if (locale !== undefined) this.setAppLocale(String(locale))\n return this.dailyActivePromise\n }\n\n this.dailyActivePromise = this.trackDailyActiveInternal(props).finally(() => {\n this.dailyActivePromise = null\n })\n return this.dailyActivePromise\n }\n\n private async trackDailyActiveInternal(props?: Record<string, unknown>): Promise<void> {\n const locale = props?.app_locale ?? props?.locale\n if (locale !== undefined) this.setAppLocale(String(locale))\n\n const data = this.load()\n if (!data.enabled) return\n\n if (!this.startupAttempted) {\n this.startupAttempted = true\n await this.track('app_started')\n }\n\n const today = new Date().toISOString().slice(0, 10)\n const isNew = data.firstReportDate === null\n if (data.lastReportDate === today) return\n\n const tracked = await this.track(isNew ? 'app_active_new' : 'app_active')\n if (!tracked) return\n\n this.updateData((persisted) => {\n persisted.firstReportDate ??= today\n persisted.lastReportDate = today\n }, undefined)\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { rebaseChatLabDemoDocuments } from '@openchatlab/parser'\nimport { appLogger } from '../logging/app-logger'\nimport { createChatLabTempDir, removeChatLabTempDir } from '../temp-workspace'\n\nconst DEMO_BASE_URL = 'https://chatlab.fun/assets/demo'\nconst DEMO_FILES = ['demo-group.json', 'demo-private-B-wukong.json'] as const\n\nexport interface DemoImportProgress {\n stage: 'downloading' | 'importing' | 'done' | 'error'\n current: number\n total: number\n message?: string\n}\n\nexport interface DemoImportFileResult {\n success: boolean\n sessionId?: string\n error?: string\n}\n\nexport interface DemoImportResult {\n success: boolean\n groupSessionId?: string\n privateSessionIds?: string[]\n error?: string\n}\n\nexport interface ImportDemoSessionsOptions {\n locale: 'cn' | 'en'\n tempPrefix: string\n importFile: (filePath: string) => Promise<DemoImportFileResult>\n /**\n * Rolls back a completed session. Platform cleanup intentionally keeps its established\n * best-effort semantics for rare OS-level unlink failures and only surfaces errors its API exposes.\n */\n deleteSession: (sessionId: string) => Promise<void> | void\n onProgress?: (progress: DemoImportProgress) => void\n fetchImpl?: typeof fetch\n now?: () => Date\n targetTimeZone?: string\n}\n\n/**\n * Download, rebase and import the official Demo sessions for Node runtimes.\n * Electron and CLI Web provide only their platform-specific import callback.\n */\nexport async function importDemoSessions(options: ImportDemoSessionsOptions): Promise<DemoImportResult> {\n const total = DEMO_FILES.length\n const fetchImpl = options.fetchImpl ?? fetch\n const sessionIds: string[] = []\n let tempDir: string | undefined\n\n try {\n const createdTempDir = createChatLabTempDir('imports', options.tempPrefix)\n tempDir = createdTempDir\n appLogger.info('demo-import', 'Demo import started', {\n locale: options.locale,\n sessionCount: total,\n targetTimeZone: options.targetTimeZone ?? 'runtime-local',\n })\n\n const downloaded: string[] = []\n for (let index = 0; index < total; index++) {\n const filename = DEMO_FILES[index]\n options.onProgress?.({ stage: 'downloading', current: index + 1, total })\n const response = await fetchImpl.call(globalThis, `${DEMO_BASE_URL}/${options.locale}/${filename}`, {\n signal: AbortSignal.timeout(60_000),\n })\n if (!response.ok) throw new Error(`Download demo failed (${filename}): HTTP ${response.status}`)\n\n const content = Buffer.from(await response.arrayBuffer())\n if (content.byteLength < 100) {\n throw new Error(`Downloaded demo file is too small (${filename})`)\n }\n downloaded.push(content.toString('utf8'))\n }\n\n const rebased = rebaseChatLabDemoDocuments(downloaded, options.now?.() ?? new Date(), options.targetTimeZone)\n const localPaths = rebased.documents.map((document, index) => {\n const localPath = path.join(createdTempDir, DEMO_FILES[index])\n fs.writeFileSync(localPath, document, 'utf8')\n return localPath\n })\n\n appLogger.info('demo-import', 'Demo timeline prepared', {\n sessionCount: total,\n offsetSeconds: rebased.offsetSeconds,\n latestTimestamp: rebased.latestTimestamp,\n })\n\n for (let index = 0; index < localPaths.length; index++) {\n options.onProgress?.({ stage: 'importing', current: index + 1, total })\n const result = await options.importFile(localPaths[index])\n if (!result.success || !result.sessionId) {\n throw new Error(result.error || `Failed to import demo: ${DEMO_FILES[index]}`)\n }\n sessionIds.push(result.sessionId)\n }\n\n const [groupSessionId, ...privateSessionIds] = sessionIds\n options.onProgress?.({ stage: 'done', current: total, total })\n appLogger.info('demo-import', 'Demo import completed', { sessionCount: sessionIds.length })\n return { success: true, groupSessionId, privateSessionIds }\n } catch (error) {\n const rollbackFailures: unknown[] = []\n for (const sessionId of sessionIds.toReversed()) {\n try {\n await options.deleteSession(sessionId)\n } catch (rollbackError) {\n rollbackFailures.push(rollbackError)\n appLogger.error('demo-import', `Failed to roll back Demo session ${sessionId}`, rollbackError)\n }\n }\n\n if (sessionIds.length > 0 && rollbackFailures.length === 0) {\n appLogger.info('demo-import', 'Rolled back partially imported Demo sessions', {\n sessionCount: sessionIds.length,\n })\n }\n\n const originalMessage = error instanceof Error ? error.message : String(error)\n const message =\n rollbackFailures.length === 0\n ? originalMessage\n : `${originalMessage} (${rollbackFailures.length} Demo session(s) could not be rolled back.)`\n options.onProgress?.({ stage: 'error', current: 0, total, message })\n appLogger.error('demo-import', 'Demo import failed', error)\n return { success: false, error: message }\n } finally {\n if (tempDir) {\n try {\n removeChatLabTempDir(tempDir, 'imports')\n } catch (error) {\n appLogger.warn('demo-import', 'Failed to clean up Demo temporary directory', error)\n }\n }\n }\n}\n","/**\n * 语义索引模块(Phase 1)\n *\n * 独立于 dormant 的旧 `ai/rag` 模块,按 chunking-decision-final.md 重新实现:\n * 向量存储、parent/child chunker、embedding provider、dense 召回与后台预热。\n */\n\nexport { EmbeddingIndexStore } from './store'\nexport type { LoadSqliteVec } from './store'\nexport {\n EMBEDDING_INDEX_SCHEMA,\n CHUNK_VECTOR_INDEX_TABLE,\n CHUNK_VECTOR_INDEX_INDEXES,\n SEMANTIC_INDEX_SESSION_TABLE,\n vecTableName,\n vecTableSchema,\n} from './schema'\nexport { SemanticIndexStateStore } from './session-state-store'\nexport type {\n SemanticIndexSessionState,\n SemanticIndexStatus,\n SemanticIndexCleanupStatus,\n EnableParams,\n ProgressPatch,\n} from './session-state-store'\nexport type { ChunkRecord, ChunkInsert, ChunkStatus, DenseQueryParams, DenseQueryResult } from './types'\nexport {\n CHUNKER_VERSION,\n STRATEGY_ID,\n DEFAULT_CHUNKER_CONFIG,\n computeChunkerConfigHash,\n computeDbPathHash,\n composeChunkId,\n deriveParentId,\n parseParentBounds,\n} from './chunker-config'\nexport type { ChunkerConfig } from './chunker-config'\nexport { estimateTokens } from './tokens'\nexport {\n SemanticIndexConfigStore,\n defaultSemanticIndexConfig,\n isSemanticIndexConfigured,\n resolveModelId,\n clampSearchMaxResults,\n SEMANTIC_INDEX_CONFIG_VERSION,\n SEARCH_MAX_RESULTS_DEFAULT,\n SEARCH_MAX_RESULTS_MIN,\n SEARCH_MAX_RESULTS_MAX,\n DEFAULT_SEMANTIC_INDEX_MODEL_DOWNLOAD_SOURCE,\n} from './config'\nexport type {\n SemanticIndexConfig,\n SemanticIndexConfigInput,\n SemanticIndexMode,\n SemanticIndexLocalConfig,\n SemanticIndexApiConfig,\n SemanticIndexModelDownloadSource,\n} from './config'\nexport { createEmbedder } from './embedder-factory'\nexport type { EmbedderFactoryDeps } from './embedder-factory'\nexport {\n SemanticIndexService,\n createSemanticIndexService,\n persistSemanticIndexConfig,\n resolveSemanticIndexApiKeySet,\n SEMANTIC_INDEX_AUTH_PROFILE,\n SEMANTIC_INDEX_DB_FILE,\n SEMANTIC_INDEX_CONFIG_FILE,\n} from './service'\nexport type { SemanticIndexRuntime, MaybePromise } from './runtime'\nexport {\n createLocalEmbeddingRuntimeManager,\n LOCAL_EMBEDDING_RUNTIME_PACKAGE,\n LOCAL_EMBEDDING_RUNTIME_VERSION,\n} from './embedding/local-runtime'\nexport type {\n LocalEmbeddingRuntimeConfig,\n LocalEmbeddingRuntimeInstallMode,\n LocalEmbeddingRuntimeManagerOptions,\n LocalEmbeddingRuntimeStatus,\n} from './embedding/local-runtime'\nexport {\n SemanticIndexWorkerClient,\n createSemanticIndexWorkerClient,\n createSemanticIndexWorkerRuntimeClient,\n} from './worker-client'\nexport type {\n SemanticIndexWorkerClientOptions,\n SemanticIndexWorkerRuntimeClientOptions,\n SemanticIndexWorkerTransport,\n SemanticIndexWorkerTransportFactory,\n} from './worker-client'\nexport { createSemanticIndexWorkerThreadTransport } from './worker-thread-transport'\nexport type { SemanticIndexWorkerThreadTransportOptions, SemanticIndexWorkerLike } from './worker-thread-transport'\nexport { StaticPathProvider, snapshotPathProvider } from './static-path-provider'\nexport type { StaticPathProviderSnapshot } from './static-path-provider'\nexport type {\n SemanticIndexServiceOptions,\n SemanticIndexSessionStatus,\n SemanticSearchResult,\n SemanticSearchReason,\n SemanticSearchToolResult,\n SemanticSearchToolSource,\n SemanticSearchToolOptions,\n} from './service'\nexport { runWarmup } from './warmup/runner'\nexport type {\n SemanticMessageSource,\n StopSignal,\n WarmupRunnerOptions,\n WarmupResult,\n WarmupStatus,\n} from './warmup/runner'\nexport { SemanticIndexJobQueue } from './warmup/job-queue'\nexport type { SemanticIndexJob, SemanticIndexJobType, JobContext, JobExecutor } from './warmup/job-queue'\nexport { semanticSearch } from './retrieval/semantic-search'\nexport type {\n SemanticSearchDeps,\n SemanticSearchParams,\n SemanticSearchHit,\n SemanticTimeRangeMs,\n} from './retrieval/semantic-search'\nexport { createChatDbMessageSource } from './chat-db/message-source'\nexport { createChatDbMessageRangeReader } from './chat-db/message-range-reader'\nexport { assembleEvidence, formatEvidenceMessages } from './retrieval/evidence'\nexport type {\n EvidenceMessage,\n MessageRangeReader,\n EvidenceHit,\n EvidenceBudget,\n EvidenceBlock,\n EvidenceResult,\n} from './retrieval/evidence'\nexport { chunkMessages, isSemanticVoid } from './chunker'\nexport type { ChunkMessageInput, ChunkSource, ChunkMessagesInput, ChildChunk, ChunkResult } from './chunker'\nexport * as embedding from './embedding'\n","import path from 'node:path'\nimport type { PathProvider } from '@openchatlab/core'\nimport type { AuthProfile } from '@openchatlab/config'\nimport { resolveApiKey as defaultResolveApiKey } from '@openchatlab/config'\nimport type { SemanticIndexConfig, SemanticIndexConfigInput } from './config'\nimport { isKeylessSemanticIndexApiBaseUrl, SemanticIndexConfigStore } from './config'\nimport {\n SEMANTIC_INDEX_CONFIG_FILE,\n persistSemanticIndexConfig,\n resolveSemanticIndexApiKeySet,\n type SemanticIndexSessionStatus,\n type SemanticSearchResult,\n type SemanticSearchToolOptions,\n type SemanticSearchToolResult,\n} from './service'\nimport type { SemanticIndexRuntime } from './runtime'\nimport type { SemanticIndexModelStatus } from './embedding/types'\nimport type { LocalEmbeddingRuntimeConfig } from './embedding/local-runtime'\nimport type { RuntimeIdentity } from '../data-dir-compat'\nimport { appLogger } from '../logging/app-logger'\nimport { snapshotPathProvider } from './static-path-provider'\nimport { createSemanticIndexWorkerThreadTransport } from './worker-thread-transport'\n\nexport interface SemanticIndexWorkerTransport {\n request<T>(method: string, args: unknown[]): Promise<T>\n close(): void | Promise<void>\n}\n\ntype MaybePromise<T> = T | Promise<T>\n\nexport type SemanticIndexWorkerTransportFactory = (modelDownloadProxyUrl?: string) => SemanticIndexWorkerTransport\n\ninterface WorkerClientTimers {\n setTimeout(callback: () => void, ms: number): unknown\n clearTimeout(timer: unknown): void\n}\n\nexport interface SemanticIndexWorkerClientOptions {\n configStore: SemanticIndexConfigStore\n transportFactory: SemanticIndexWorkerTransportFactory\n idleTimeoutMs?: number\n timers?: WorkerClientTimers\n getModelDownloadProxyUrl?: () => MaybePromise<string | undefined>\n resolveApiKey?: (provider: string, authProfile?: string) => string\n writeAuthProfile?: (name: string, profile: AuthProfile) => void\n}\n\nexport interface SemanticIndexWorkerRuntimeClientOptions {\n pathProvider: PathProvider\n runtime: RuntimeIdentity\n nativeBinding?: string\n sqliteVecLoadablePath?: string\n workerEntryUrl?: string | URL\n idleTimeoutMs?: number\n getModelDownloadProxyUrl?: () => MaybePromise<string | undefined>\n localEmbeddingRuntime?: LocalEmbeddingRuntimeConfig\n resolveApiKey?: (provider: string, authProfile?: string) => string\n writeAuthProfile?: (name: string, profile: AuthProfile) => void\n}\n\nconst DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1000\nconst MODEL_PRELOAD_STATUS_POLL_MS = 2_000\n\nconst defaultTimers: WorkerClientTimers = {\n setTimeout: (callback, ms) => setTimeout(callback, ms),\n clearTimeout: (timer) => clearTimeout(timer as ReturnType<typeof setTimeout>),\n}\n\nexport class SemanticIndexWorkerClient implements SemanticIndexRuntime {\n private transport: SemanticIndexWorkerTransport | null = null\n private pendingRequests = 0\n private idleTimer: unknown = null\n private modelPreloadPollTimer: unknown = null\n private activeBuildSessionIds = new Set<string>()\n private hasUnknownActiveBuild = false\n private hasActiveModelPreload = false\n private activeModelDownloadProxyUrl: string | undefined\n private readonly configStore: SemanticIndexConfigStore\n private readonly transportFactory: SemanticIndexWorkerTransportFactory\n private readonly idleTimeoutMs: number\n private readonly timers: WorkerClientTimers\n private readonly getModelDownloadProxyUrl: () => MaybePromise<string | undefined>\n private readonly resolveApiKey: (provider: string, authProfile?: string) => string\n private readonly writeAuthProfile?: (name: string, profile: AuthProfile) => void\n\n constructor(options: SemanticIndexWorkerClientOptions) {\n this.configStore = options.configStore\n this.transportFactory = options.transportFactory\n this.idleTimeoutMs = options.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS\n this.timers = options.timers ?? defaultTimers\n this.getModelDownloadProxyUrl = options.getModelDownloadProxyUrl ?? (() => undefined)\n this.resolveApiKey = options.resolveApiKey ?? defaultResolveApiKey\n this.writeAuthProfile = options.writeAuthProfile\n }\n\n getConfig(): SemanticIndexConfig {\n return this.configStore.get()\n }\n\n async setConfig(config: SemanticIndexConfigInput, options?: { apiKey?: string }): Promise<SemanticIndexConfig> {\n const saved = persistSemanticIndexConfig(this.configStore, config, {\n apiKey: options?.apiKey,\n writeAuthProfile: this.writeAuthProfile,\n })\n if (!saved.enabled) {\n this.clearActiveBuildTracking()\n }\n if (!saved.enabled || saved.mode !== 'local') this.clearModelPreloadTracking()\n // 本地模式且功能开启时,即使 worker 未运行也需启动它以触发 preload;\n // 其余情况(disabled / api 模式)无需唤醒 worker,直接返回本地保存结果。\n const needsWorker = saved.enabled && saved.mode === 'local' && this.configStore.isConfigured()\n if (!this.transport && !needsWorker) return saved\n if (needsWorker) await this.closeTransportForLocalModelProxyChangeIfNeeded()\n return await this.call<SemanticIndexConfig>('setConfig', [saved])\n }\n\n isConfigured(): boolean {\n return this.configStore.isConfigured()\n }\n\n hasApiKey(): boolean {\n return resolveSemanticIndexApiKeySet(this.configStore.get(), this.resolveApiKey)\n }\n\n async getModelStatus(): Promise<SemanticIndexModelStatus> {\n if (!this.transport && !this.shouldStartLocalModelWorker()) return 'idle'\n const status = await this.call<SemanticIndexModelStatus>('getModelStatus', [], { scheduleIdle: false })\n this.updateModelPreloadStatus(status)\n return status\n }\n\n enable(sessionId: string): Promise<void> {\n return this.call('enable', [sessionId])\n }\n\n remove(sessionId: string): Promise<void> {\n return this.call('remove', [sessionId])\n }\n\n async build(sessionId: string): Promise<void> {\n await this.closeTransportForLocalModelProxyChangeIfNeeded()\n this.activeBuildSessionIds.add(sessionId)\n try {\n await this.call('build', [sessionId])\n } catch (error) {\n this.activeBuildSessionIds.delete(sessionId)\n throw error\n }\n }\n\n pause(sessionId: string): Promise<void> {\n return this.call('pause', [sessionId])\n }\n\n cancel(sessionId: string): Promise<void> {\n return this.call('cancel', [sessionId])\n }\n\n async rebuild(sessionId: string): Promise<void> {\n await this.closeTransportForLocalModelProxyChangeIfNeeded()\n this.activeBuildSessionIds.add(sessionId)\n try {\n await this.call('rebuild', [sessionId])\n } catch (error) {\n this.activeBuildSessionIds.delete(sessionId)\n throw error\n }\n }\n\n async buildAllPending(): Promise<void> {\n await this.closeTransportForLocalModelProxyChangeIfNeeded()\n this.hasUnknownActiveBuild = true\n try {\n await this.call('buildAllPending', [])\n } catch (error) {\n this.hasUnknownActiveBuild = false\n throw error\n }\n }\n\n async listEnabledStatuses(): Promise<SemanticIndexSessionStatus[]> {\n const statuses = await this.callProbe<SemanticIndexSessionStatus[]>('listEnabledStatuses', [], [], {\n scheduleIdle: false,\n })\n this.updateActiveBuildFromCompleteSnapshot(statuses)\n this.scheduleIdleCloseIfNeeded()\n return statuses\n }\n\n async status(sessionId: string): Promise<SemanticIndexSessionStatus | null> {\n const status = await this.callProbe<SemanticIndexSessionStatus | null>('status', [sessionId], null, {\n scheduleIdle: false,\n })\n this.updateActiveBuildFromPartialSnapshot([sessionId], status ? [status] : [])\n this.scheduleIdleCloseIfNeeded()\n return status\n }\n\n async statusForSessions(sessionIds: string[]): Promise<SemanticIndexSessionStatus[]> {\n const statuses = await this.callProbe<SemanticIndexSessionStatus[]>('statusForSessions', [sessionIds], [], {\n scheduleIdle: false,\n })\n this.updateActiveBuildFromPartialSnapshot(sessionIds, statuses)\n this.scheduleIdleCloseIfNeeded()\n return statuses\n }\n\n async canSearch(sessionId: string): Promise<boolean> {\n if (!this.canRunFromLocalConfig()) return false\n return await this.callProbe<boolean>('canSearch', [sessionId], false)\n }\n\n async search(\n sessionId: string,\n query: string,\n options?: { finalTopK?: number; timeRangeMs?: { startTs?: number; endTs?: number } }\n ): Promise<SemanticSearchResult> {\n await this.closeTransportForLocalModelProxyChangeIfNeeded()\n return await this.call('search', [sessionId, query, options])\n }\n\n async searchForTool(\n sessionId: string,\n query: string,\n options?: SemanticSearchToolOptions\n ): Promise<SemanticSearchToolResult> {\n await this.closeTransportForLocalModelProxyChangeIfNeeded()\n return await this.call('searchForTool', [sessionId, query, options])\n }\n\n cleanupUnused(): Promise<{ cleaned: number }> {\n return this.call('cleanupUnused', [])\n }\n\n recover(): Promise<void> {\n return this.call('recover', [])\n }\n\n async close(): Promise<void> {\n this.clearIdleTimer()\n await this.closeTransport()\n }\n\n private async call<T>(method: string, args: unknown[], options?: { scheduleIdle?: boolean }): Promise<T> {\n const transport = await this.ensureTransport()\n this.pendingRequests++\n this.clearIdleTimer()\n try {\n return await transport.request<T>(method, args)\n } finally {\n this.pendingRequests--\n if (options?.scheduleIdle !== false) this.scheduleIdleCloseIfNeeded()\n }\n }\n\n private async callProbe<T>(\n method: string,\n args: unknown[],\n fallback: T,\n options?: { scheduleIdle?: boolean }\n ): Promise<T> {\n try {\n return await this.call<T>(method, args, options)\n } catch {\n await this.closeFailedProbeTransport()\n return fallback\n }\n }\n\n private async ensureTransport(): Promise<SemanticIndexWorkerTransport> {\n if (!this.transport) {\n const proxyUrl = await this.currentModelDownloadProxyUrl()\n if (!this.transport) {\n this.activeModelDownloadProxyUrl = proxyUrl\n this.transport = this.transportFactory(proxyUrl)\n }\n }\n return this.transport\n }\n\n private async currentModelDownloadProxyUrl(): Promise<string | undefined> {\n const proxyUrl = (await this.getModelDownloadProxyUrl())?.trim()\n return proxyUrl || undefined\n }\n\n private async closeTransportForLocalModelProxyChangeIfNeeded(): Promise<void> {\n if (!this.transport) return\n const config = this.configStore.get()\n if (!this.configStore.canRun() || config.mode !== 'local') return\n if (this.hasUnknownActiveBuild || this.activeBuildSessionIds.size > 0) return\n if ((await this.currentModelDownloadProxyUrl()) === this.activeModelDownloadProxyUrl) return\n await this.closeTransport()\n }\n\n private canRunFromLocalConfig(): boolean {\n const config = this.configStore.get()\n if (!this.configStore.canRun()) return false\n if (config.mode !== 'api') return true\n if (isKeylessSemanticIndexApiBaseUrl(config.api?.baseUrl)) return true\n return resolveSemanticIndexApiKeySet(config, this.resolveApiKey)\n }\n\n private shouldStartLocalModelWorker(): boolean {\n const config = this.configStore.get()\n return config.enabled && config.mode === 'local' && this.configStore.isConfigured()\n }\n\n private updateActiveBuildFromCompleteSnapshot(statuses: SemanticIndexSessionStatus[]): void {\n this.hasUnknownActiveBuild = false\n this.activeBuildSessionIds = new Set(\n statuses.filter((status) => this.isActiveBuildStatus(status)).map((status) => status.sessionId)\n )\n }\n\n private updateActiveBuildFromPartialSnapshot(\n requestedSessionIds: string[],\n statuses: SemanticIndexSessionStatus[]\n ): void {\n const bySessionId = new Map(statuses.map((status) => [status.sessionId, status]))\n for (const sessionId of requestedSessionIds) {\n const status = bySessionId.get(sessionId)\n if (status && this.isActiveBuildStatus(status)) this.activeBuildSessionIds.add(sessionId)\n else this.activeBuildSessionIds.delete(sessionId)\n }\n }\n\n private isActiveBuildStatus(status: SemanticIndexSessionStatus): boolean {\n return status.running || status.queued || status.indexStatus === 'running'\n }\n\n private clearActiveBuildTracking(): void {\n this.hasUnknownActiveBuild = false\n this.activeBuildSessionIds.clear()\n }\n\n private updateModelPreloadStatus(status: SemanticIndexModelStatus): void {\n this.hasActiveModelPreload = status === 'installing-runtime' || status === 'downloading-model'\n if (this.hasActiveModelPreload) this.scheduleModelPreloadPoll()\n else {\n this.clearModelPreloadPoll()\n this.scheduleIdleCloseIfNeeded()\n }\n }\n\n private scheduleModelPreloadPoll(): void {\n this.clearModelPreloadPoll()\n if (!this.transport || !this.hasActiveModelPreload) return\n this.modelPreloadPollTimer = this.timers.setTimeout(() => {\n this.modelPreloadPollTimer = null\n void this.pollModelPreloadStatus()\n }, MODEL_PRELOAD_STATUS_POLL_MS)\n }\n\n private async pollModelPreloadStatus(): Promise<void> {\n if (!this.transport || !this.hasActiveModelPreload) return\n try {\n await this.getModelStatus()\n } catch (error) {\n appLogger.error('semantic-index', 'Background model preload status poll failed; closing worker', error)\n await this.closeFailedProbeTransport()\n }\n }\n\n private clearModelPreloadPoll(): void {\n if (this.modelPreloadPollTimer) {\n this.timers.clearTimeout(this.modelPreloadPollTimer)\n this.modelPreloadPollTimer = null\n }\n }\n\n private clearModelPreloadTracking(): void {\n this.hasActiveModelPreload = false\n this.clearModelPreloadPoll()\n }\n\n private scheduleIdleCloseIfNeeded(): void {\n if (\n !this.transport ||\n this.pendingRequests > 0 ||\n this.hasUnknownActiveBuild ||\n this.hasActiveModelPreload ||\n this.activeBuildSessionIds.size > 0\n )\n return\n this.clearIdleTimer()\n this.idleTimer = this.timers.setTimeout(() => {\n void this.closeTransport().catch((err) => {\n console.warn('[semantic-index] idle worker close failed:', err instanceof Error ? err.message : String(err))\n })\n }, this.idleTimeoutMs)\n }\n\n private clearIdleTimer(): void {\n if (this.idleTimer) {\n this.timers.clearTimeout(this.idleTimer)\n this.idleTimer = null\n }\n }\n\n private async closeTransport(): Promise<void> {\n const transport = this.transport\n this.transport = null\n this.activeModelDownloadProxyUrl = undefined\n this.clearModelPreloadTracking()\n this.clearActiveBuildTracking()\n if (transport) await transport.close()\n }\n\n private async closeFailedProbeTransport(): Promise<void> {\n this.clearIdleTimer()\n try {\n await this.closeTransport()\n } catch {\n // 语义索引探针失败只降级为不可用,不能打断普通 AI 对话流程。\n }\n }\n}\n\nexport function createSemanticIndexWorkerClient(options: SemanticIndexWorkerClientOptions): SemanticIndexWorkerClient {\n return new SemanticIndexWorkerClient(options)\n}\n\nexport function createSemanticIndexWorkerRuntimeClient(\n options: SemanticIndexWorkerRuntimeClientOptions\n): SemanticIndexWorkerClient {\n const configStore = new SemanticIndexConfigStore(\n path.join(options.pathProvider.getAiDataDir(), SEMANTIC_INDEX_CONFIG_FILE)\n )\n return createSemanticIndexWorkerClient({\n configStore,\n idleTimeoutMs: options.idleTimeoutMs,\n resolveApiKey: options.resolveApiKey,\n writeAuthProfile: options.writeAuthProfile,\n getModelDownloadProxyUrl: options.getModelDownloadProxyUrl,\n transportFactory: (modelDownloadProxyUrl) =>\n createSemanticIndexWorkerThreadTransport({\n workerEntryUrl: options.workerEntryUrl,\n startup: {\n paths: snapshotPathProvider(options.pathProvider),\n runtime: options.runtime,\n nativeBinding: options.nativeBinding,\n sqliteVecLoadablePath: options.sqliteVecLoadablePath,\n modelDownloadProxyUrl,\n localEmbeddingRuntime: options.localEmbeddingRuntime,\n },\n }),\n })\n}\n","import { Worker } from 'node:worker_threads'\nimport type { WorkerOptions } from 'node:worker_threads'\nimport type { SemanticIndexWorkerTransport } from './worker-client'\nimport type { SemanticIndexWorkerStartupOptions } from './worker-runtime'\n\nexport interface SemanticIndexWorkerLike {\n postMessage(message: unknown): void\n terminate(): Promise<number>\n on(event: 'message', listener: (message: unknown) => void): this\n on(event: 'error', listener: (error: Error) => void): this\n on(event: 'exit', listener: (code: number) => void): this\n}\n\nexport interface SemanticIndexWorkerThreadTransportOptions {\n startup: SemanticIndexWorkerStartupOptions\n workerFactory?: () => SemanticIndexWorkerLike\n workerEntryUrl?: string | URL\n closeTimeoutMs?: number\n}\n\ninterface PendingRequest {\n resolve: (value: unknown) => void\n reject: (error: Error) => void\n}\n\nconst DEFAULT_CLOSE_TIMEOUT_MS = 3_000\n\ntype ModuleWorkerOptions = WorkerOptions & { type: 'module' }\n\nfunction defaultWorkerEntryUrl(): URL {\n return import.meta.url.endsWith('.ts')\n ? new URL('./worker-thread-entry.ts', import.meta.url)\n : new URL('./worker-thread-entry.js', import.meta.url)\n}\n\nfunction normalizeWorkerEntryUrl(entryUrl?: string | URL): URL {\n if (!entryUrl) return defaultWorkerEntryUrl()\n return typeof entryUrl === 'string' ? new URL(entryUrl) : entryUrl\n}\n\nfunction createDefaultWorker(\n startup: SemanticIndexWorkerStartupOptions,\n entryUrlInput?: string | URL\n): SemanticIndexWorkerLike {\n const entryUrl = normalizeWorkerEntryUrl(entryUrlInput)\n if (!entryUrl.href.endsWith('.ts')) {\n return new Worker(entryUrl, { workerData: startup }) as SemanticIndexWorkerLike\n }\n\n const bootstrap = `\n import { register } from 'tsx/esm/api';\n register();\n await import(${JSON.stringify(entryUrl.href)});\n `\n const options: ModuleWorkerOptions = {\n eval: true,\n type: 'module',\n workerData: startup,\n execArgv: [],\n }\n return new Worker(bootstrap, options) as SemanticIndexWorkerLike\n}\n\nexport class SemanticIndexWorkerThreadTransport implements SemanticIndexWorkerTransport {\n private worker: SemanticIndexWorkerLike\n private pending = new Map<string, PendingRequest>()\n private requestId = 0\n private readonly closeTimeoutMs: number\n\n constructor(options: SemanticIndexWorkerThreadTransportOptions) {\n this.closeTimeoutMs = options.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS\n this.worker = options.workerFactory?.() ?? createDefaultWorker(options.startup, options.workerEntryUrl)\n\n this.worker.on('message', (message) => this.handleMessage(message))\n this.worker.on('error', (error) => this.rejectAll(error))\n this.worker.on('exit', (code) => {\n if (code !== 0) this.rejectAll(new Error(`Semantic index worker exited with code ${code}`))\n })\n }\n\n request<T>(method: string, args: unknown[]): Promise<T> {\n const id = `si_${++this.requestId}`\n return new Promise<T>((resolve, reject) => {\n this.pending.set(id, { resolve: resolve as (value: unknown) => void, reject })\n this.worker.postMessage({ id, method, args })\n })\n }\n\n async close(): Promise<void> {\n await this.requestRuntimeClose()\n await this.worker.terminate()\n this.rejectAll(new Error('Semantic index worker closed'))\n }\n\n private async requestRuntimeClose(): Promise<void> {\n let timeout: ReturnType<typeof setTimeout> | null = null\n const timeoutPromise = new Promise<void>((resolve) => {\n timeout = setTimeout(resolve, this.closeTimeoutMs)\n })\n\n try {\n // 先让 worker 内的 service 正常 close,避免 SQLite/vector 资源被直接中断;超时后仍会 terminate。\n await Promise.race([this.request('__close', []).then(() => undefined), timeoutPromise])\n } catch {\n // Worker may already be gone; terminate below still clears local state.\n } finally {\n if (timeout) clearTimeout(timeout)\n }\n }\n\n private handleMessage(message: unknown): void {\n const payload = message as { id?: string; success?: boolean; result?: unknown; error?: string }\n if (!payload.id) return\n const pending = this.pending.get(payload.id)\n if (!pending) return\n this.pending.delete(payload.id)\n if (payload.success) pending.resolve(payload.result)\n else pending.reject(new Error(payload.error ?? 'Semantic index worker request failed'))\n }\n\n private rejectAll(error: Error): void {\n for (const [id, pending] of this.pending.entries()) {\n this.pending.delete(id)\n pending.reject(error)\n }\n }\n}\n\nexport function createSemanticIndexWorkerThreadTransport(\n options: SemanticIndexWorkerThreadTransportOptions\n): SemanticIndexWorkerThreadTransport {\n return new SemanticIndexWorkerThreadTransport(options)\n}\n","/**\n * Embedding provider 模块\n */\n\nexport type { EmbeddingProvider, EmbeddingPooling } from './types'\nexport {\n QWEN3_PROFILE,\n BGE_BASE_PROFILE,\n getLocalProfilesForLocale,\n getLocalProfileByModelId,\n type LocalEmbeddingProfile,\n} from './profiles'\nexport { applyQueryInstruction, clampTextChars } from './text'\nexport { LocalEmbeddingProvider } from './local'\nexport type { LocalPipelineFactory, FeatureExtractFn, LocalEmbeddingProviderOptions } from './local'\nexport { OpenAICompatibleEmbeddingProvider } from './api'\nexport type { OpenAICompatibleConfig, FetchFn } from './api'\n"],"mappings":"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","names":["fs","path","fs","path","fs","path","platform","retainedIndex","path","randomUUID","randomUUID","fs","path","path","resolve","path"]}