chatlab-cli 0.37.1 → 0.37.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-command-YAFRLHMQ.mjs → chat-command-G2EX7VHR.mjs} +24 -12
- package/dist/chat-command-G2EX7VHR.mjs.map +1 -0
- package/dist/{chunk-2PY4XCH3.mjs → chunk-E6LCCPIB.mjs} +2 -2
- package/dist/{chunk-N4SB6QZV.mjs → chunk-EFX66A2O.mjs} +2 -2
- package/dist/{chunk-UP6JIV3S.mjs → chunk-EK5QIJLZ.mjs} +16 -12
- package/dist/chunk-EK5QIJLZ.mjs.map +1 -0
- package/dist/{chunk-JWJREWVN.mjs → chunk-F4HVCFZL.mjs} +27 -3
- package/dist/chunk-F4HVCFZL.mjs.map +1 -0
- package/dist/{chunk-PDQV4RUA.mjs → chunk-FCUUAGGC.mjs} +2 -2
- package/dist/{chunk-GKCIRKOH.mjs → chunk-H46CLFWK.mjs} +4 -4
- package/dist/{chunk-OTYNMDDL.mjs → chunk-HBAQPF6X.mjs} +2118 -1907
- package/dist/chunk-HBAQPF6X.mjs.map +1 -0
- package/dist/{chunk-MMTEGUQA.mjs → chunk-HMVM7VCA.mjs} +3 -3
- package/dist/{chunk-73TJ2S7W.mjs → chunk-L6RJIVLS.mjs} +2 -2
- package/dist/{chunk-ARIBCH47.mjs → chunk-T5H56AZV.mjs} +16 -8
- package/dist/chunk-T5H56AZV.mjs.map +1 -0
- package/dist/{chunk-WDLO7OLX.mjs → chunk-XQ6Z2KNN.mjs} +2 -2
- package/dist/{chunk-FPVRSXQ4.mjs → chunk-YI3EQYEG.mjs} +12 -12
- package/dist/cli.mjs +9 -9
- package/dist/contacts-worker.mjs +2 -2
- package/dist/global-insight-worker.mjs +1 -1
- package/dist/{http-LPFPVTBC.mjs → http-5BRVWAJR.mjs} +12 -12
- package/dist/{import-T4WX2ZJL.mjs → import-IAECQDKC.mjs} +7 -7
- package/dist/index.mjs +12 -12
- package/dist/{mcp-SMF3NWIN.mjs → mcp-XXSQJBGU.mjs} +8 -8
- package/dist/people-relationships-worker.mjs +2 -2
- package/dist/semantic-index-worker.mjs +1 -1
- package/dist/{src-EGLLMTAU.mjs → src-4HLKMQ7S.mjs} +6 -6
- package/dist/{stream-import-2BXJTTCE.mjs → stream-import-PUG42I36.mjs} +7 -7
- package/dist/{worker-runtime-RDLSPXFT.mjs → worker-runtime-X5563TVT.mjs} +5 -5
- package/dist-cli-web/assets/{AISettingsTab-CEhrXlYR.js → AISettingsTab-m_r2fFEj.js} +1 -1
- package/dist-cli-web/assets/{AboutTab-Bbu0SsMM.js → AboutTab-J65UqIuk.js} +1 -1
- package/dist-cli-web/assets/{Alert-510jTN3l.js → Alert-qBIGn_CW.js} +1 -1
- package/dist-cli-web/assets/{ApiSettingsTab-Bi1GRMN4.js → ApiSettingsTab-CxWRJI9j.js} +1 -1
- package/dist-cli-web/assets/{BatchManageTab-DhnqMCSM.js → BatchManageTab-BINNVwm1.js} +1 -1
- package/dist-cli-web/assets/{BufferResource-CKZxnACp.js → BufferResource-C-jLPrHv.js} +1 -1
- package/dist-cli-web/assets/{CanvasRenderer-BeK5POBy.js → CanvasRenderer-kDLW8GSt.js} +1 -1
- package/dist-cli-web/assets/{CardDecoration-RuBA3N2j.js → CardDecoration-CnYxleQM.js} +1 -1
- package/dist-cli-web/assets/{ChatRecordDrawer-BY_-lIEj.js → ChatRecordDrawer-CMg3FEWH.js} +1 -1
- package/dist-cli-web/assets/{ChatRecordWorkspace-7prKd-Tq.js → ChatRecordWorkspace-AfFIMUbZ.js} +1 -1
- package/dist-cli-web/assets/{Checkbox-_eH64bb0.js → Checkbox-D-hAv15R.js} +1 -1
- package/dist-cli-web/assets/{DataDirCleanupNotice-BHaXwlfr.js → DataDirCleanupNotice-P80h2p4l.js} +1 -1
- package/dist-cli-web/assets/{DatePicker.vue_vue_type_script_setup_true_lang-D9Ul_GYz.js → DatePicker.vue_vue_type_script_setup_true_lang-CSp691Uv.js} +1 -1
- package/dist-cli-web/assets/{DebugToolsPanel-ByKItGrS.js → DebugToolsPanel-BK2VbKB0.js} +1 -1
- package/dist-cli-web/assets/{EChart.vue_vue_type_script_setup_true_lang-DubnuUXI.js → EChart.vue_vue_type_script_setup_true_lang-BcE0mE_N.js} +1 -1
- package/dist-cli-web/assets/{EChartBar.vue_vue_type_script_setup_true_lang-DKNCZuFm.js → EChartBar.vue_vue_type_script_setup_true_lang-BypaV5wc.js} +1 -1
- package/dist-cli-web/assets/{EChartLine.vue_vue_type_script_setup_true_lang-Fl7xAOSR.js → EChartLine.vue_vue_type_script_setup_true_lang-D8SyOfWC.js} +1 -1
- package/dist-cli-web/assets/{EChartWordcloud-C6XM4KOX.js → EChartWordcloud-0rihhg03.js} +1 -1
- package/dist-cli-web/assets/{FileDropZone.vue_vue_type_script_setup_true_lang-DYDdRSNE.js → FileDropZone.vue_vue_type_script_setup_true_lang-Dyuzh7Ex.js} +1 -1
- package/dist-cli-web/assets/{Filter-CByj_rCR.js → Filter-rD_jWpbO.js} +1 -1
- package/dist-cli-web/assets/{GlobalTaskBar-BdELjzrs.js → GlobalTaskBar-sXQuGvF-.js} +1 -1
- package/dist-cli-web/assets/{GroupRelationshipGalaxyView-CnzPEgUS.js → GroupRelationshipGalaxyView-BN1L9DFf.js} +1 -1
- package/dist-cli-web/assets/{Label-DCIcxkhU.js → Label-Ce4wl_Ph.js} +1 -1
- package/dist-cli-web/assets/{LoadingState.vue_vue_type_script_setup_true_lang-BBcCt_Qm.js → LoadingState.vue_vue_type_script_setup_true_lang-DmVfwvnD.js} +1 -1
- package/dist-cli-web/assets/{MessageExportModal-DNU16Bs8.js → MessageExportModal-C2IUNPhg.js} +1 -1
- package/dist-cli-web/assets/{PageHeader-CKeZjNNR.js → PageHeader-D5BcYKBs.js} +1 -1
- package/dist-cli-web/assets/{PageTabs.vue_vue_type_script_setup_true_lang-C8M3wNNH.js → PageTabs.vue_vue_type_script_setup_true_lang-DHly2-fe.js} +1 -1
- package/dist-cli-web/assets/{RelationshipGalaxyCanvas-CDhljGyJ.js → RelationshipGalaxyCanvas-CHPqtqQz.js} +3 -3
- package/dist-cli-web/assets/{RelationshipGalaxyThreeCanvas-BP8fsvvf.js → RelationshipGalaxyThreeCanvas-qR4S-9n7.js} +1 -1
- package/dist-cli-web/assets/{RenderTargetSystem-D76QrDT_.js → RenderTargetSystem-BaIFulUj.js} +1 -1
- package/dist-cli-web/assets/{RovingFocusItem-BJMUQ5DJ.js → RovingFocusItem-Bqgmzo42.js} +1 -1
- package/dist-cli-web/assets/{ScreenCaptureModal-DkX4z-M1.js → ScreenCaptureModal-sJqB_hrK.js} +1 -1
- package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-BPt98e6z.js +1 -0
- package/dist-cli-web/assets/{Select-B5oJc5y1.js → Select-BAnN4HMs.js} +1 -1
- package/dist-cli-web/assets/{SettingsModal-BO-QKQ2h.js → SettingsModal-C4ANMlJJ.js} +2 -2
- package/dist-cli-web/assets/{StorageTab-CPPXXaRm.js → StorageTab-BgNQliz4.js} +1 -1
- package/dist-cli-web/assets/{Switch-CDk3LZ4_.js → Switch-DddEvDJa.js} +1 -1
- package/dist-cli-web/assets/{Tabs-DqWTBV8x.js → Tabs-DwjL-ueH.js} +1 -1
- package/dist-cli-web/assets/{Tabs-BMq9wODW.js → Tabs-xVtuBuO0.js} +1 -1
- package/dist-cli-web/assets/{ThemeCard.vue_vue_type_script_setup_true_lang-D2outEOV.js → ThemeCard.vue_vue_type_script_setup_true_lang-CNCVa86b.js} +1 -1
- package/dist-cli-web/assets/{TimeSelect.vue_vue_type_script_setup_true_lang-BcflxP_U.js → TimeSelect.vue_vue_type_script_setup_true_lang-BehUIWki.js} +1 -1
- package/dist-cli-web/assets/{VisuallyHiddenInput-BAFpkxMI.js → VisuallyHiddenInput-ST6JNfSG.js} +1 -1
- package/dist-cli-web/assets/{WebGLRenderer-DjCPvR_O.js → WebGLRenderer-DRraqD4Y.js} +1 -1
- package/dist-cli-web/assets/{WebGPURenderer-C2B_u03z.js → WebGPURenderer-CnzaYARg.js} +1 -1
- package/dist-cli-web/assets/aiChat-CeJy-gG-.js +8 -0
- package/dist-cli-web/assets/{base-F6s0vTrr.js → base-BHbtUviQ.js} +1 -1
- package/dist-cli-web/assets/{browserAll-DiUAZg4L.js → browserAll-DYxkitnx.js} +1 -1
- package/dist-cli-web/assets/{chatMessages-Bd33SSXI.js → chatMessages-Dj1u-tFB.js} +3 -3
- package/dist-cli-web/assets/{cli-web-DoibEdj2.js → cli-web-BtH8nfjA.js} +1 -1
- package/dist-cli-web/assets/{fetch-BEaW1j5H.js → fetch-BJ82mWvv.js} +1 -1
- package/dist-cli-web/assets/{fetch-BeX69kpS.js → fetch-C1Tm66i9.js} +1 -1
- package/dist-cli-web/assets/{fetch-4nh1LaVF.js → fetch-CAEyoWQA.js} +1 -1
- package/dist-cli-web/assets/{fetch-7lUvXbhU.js → fetch-CGnWNSsG.js} +1 -1
- package/dist-cli-web/assets/{fetch-DKBBS9Op.js → fetch-D7hfFyoG.js} +1 -1
- package/dist-cli-web/assets/{fetch-CXM-cjDS.js → fetch-DNmRaRxX.js} +1 -1
- package/dist-cli-web/assets/{fetch-B_YFABxI.js → fetch-DogRrvT6.js} +1 -1
- package/dist-cli-web/assets/{fetch-DBpDMy29.js → fetch-JEEBqR_7.js} +1 -1
- package/dist-cli-web/assets/{fetch-CxVcHNid.js → fetch-T5Gi1TUZ.js} +1 -1
- package/dist-cli-web/assets/{fetch-epFXmPIQ.js → fetch-U9QyidNZ.js} +1 -1
- package/dist-cli-web/assets/{fetch-CXqeAbnY.js → fetch-ejEMWPM2.js} +1 -1
- package/dist-cli-web/assets/{fetch-CRocA-4C.js → fetch-emZXHmoE.js} +1 -1
- package/dist-cli-web/assets/{host-CtSqR_Zm.js → host-BUvwCvZR.js} +1 -1
- package/dist-cli-web/assets/{host-C4rU8pKA.js → host-VTWF81F5.js} +1 -1
- package/dist-cli-web/assets/{index-ekvsNmfe.js → index-B3MCGDwx.js} +1 -1
- package/dist-cli-web/assets/index-BI2Rb_L3.js +2 -0
- package/dist-cli-web/assets/{index-mbLXPIyC.js → index-BLYSew5C.js} +1 -1
- package/dist-cli-web/assets/index-Bs7gk1gf.css +1 -0
- package/dist-cli-web/assets/{index-BgelKQTW.css → index-C75W1B5J.css} +1 -1
- package/dist-cli-web/assets/{index-BvMAw3Zd.js → index-CVRBBnQw.js} +1 -1
- package/dist-cli-web/assets/index-Cza8BzZE.js +137 -0
- package/dist-cli-web/assets/{index-B1oj9KDv.js → index-D9C3dyV8.js} +4 -4
- package/dist-cli-web/assets/{index-_m1mf1jm.js → index-DDt7Tfda.js} +1 -1
- package/dist-cli-web/assets/{index-CuCQ1d9f.js → index-DQFcmWSa.js} +1 -1
- package/dist-cli-web/assets/{index-BFH1j_R9.js → index-DUBl6aBF.js} +1 -1
- package/dist-cli-web/assets/{index-mXe1LssU.js → index-DZK9Njvy.js} +1 -1
- package/dist-cli-web/assets/{index-4DVZ2g0M.js → index-HjrJ3DXO.js} +1 -1
- package/dist-cli-web/assets/index-KpnLSzzX.js +64 -0
- package/dist-cli-web/assets/{index-DlHuILT_.js → index-e6fOnhNS.js} +1 -1
- package/dist-cli-web/assets/{index-D8cHMqV-.js → index-iEQnKg2R.js} +2 -2
- package/dist-cli-web/assets/{people-page-header-BbYSSpsO.js → people-page-header-DWXwFJ8M.js} +1 -1
- package/dist-cli-web/assets/{prompt-C-ofJ7t_.js → prompt-Cepfb-5-.js} +1 -1
- package/dist-cli-web/assets/{semantic-index-config-builder-D3TYVYC-.js → semantic-index-config-builder-hTY6QyCe.js} +1 -1
- package/dist-cli-web/assets/service-BjE0YJaM.js +1 -0
- package/dist-cli-web/assets/service-DQxttlJp.js +1 -0
- package/dist-cli-web/assets/{service-CppETV4a.js → service-DwCmXFtI.js} +1 -1
- package/dist-cli-web/assets/useFormControl-CJyJY8AK.js +1 -0
- package/dist-cli-web/assets/{ActionToolsPanel.vue_vue_type_script_setup_true_lang-IB1yZxCE.js → useInsightTabAnalytics-CplGbsbe.js} +8 -8
- package/dist-cli-web/assets/{useTable-Clk7ecq-.js → useTable-Dmpbk7fZ.js} +1 -1
- package/dist-cli-web/assets/{useToast-B5LaA6c-.js → useToast-Bmgpd3sl.js} +1 -1
- package/dist-cli-web/assets/{webworkerAll-CyA4b4LT.js → webworkerAll-DkPWEyVL.js} +1 -1
- package/dist-cli-web/index.html +1 -1
- package/package.json +1 -1
- package/dist/chat-command-YAFRLHMQ.mjs.map +0 -1
- package/dist/chunk-ARIBCH47.mjs.map +0 -1
- package/dist/chunk-JWJREWVN.mjs.map +0 -1
- package/dist/chunk-OTYNMDDL.mjs.map +0 -1
- package/dist/chunk-UP6JIV3S.mjs.map +0 -1
- package/dist-cli-web/assets/SectionTabs.vue_vue_type_script_setup_true_lang-qFhJO5B0.js +0 -1
- package/dist-cli-web/assets/aiChat--CR4g2M7.js +0 -8
- package/dist-cli-web/assets/index-CIIyg_o9.css +0 -1
- package/dist-cli-web/assets/index-CaYtkONV.js +0 -64
- package/dist-cli-web/assets/index-D3Hyjv4e.js +0 -137
- package/dist-cli-web/assets/index-R4LqAnx9.js +0 -2
- package/dist-cli-web/assets/service-BYOUkk7V.js +0 -1
- package/dist-cli-web/assets/service-tEx-5LUL.js +0 -1
- package/dist-cli-web/assets/useFormControl-CrWi_6Hn.js +0 -1
- /package/dist/{chunk-2PY4XCH3.mjs.map → chunk-E6LCCPIB.mjs.map} +0 -0
- /package/dist/{chunk-N4SB6QZV.mjs.map → chunk-EFX66A2O.mjs.map} +0 -0
- /package/dist/{chunk-PDQV4RUA.mjs.map → chunk-FCUUAGGC.mjs.map} +0 -0
- /package/dist/{chunk-GKCIRKOH.mjs.map → chunk-H46CLFWK.mjs.map} +0 -0
- /package/dist/{chunk-MMTEGUQA.mjs.map → chunk-HMVM7VCA.mjs.map} +0 -0
- /package/dist/{chunk-73TJ2S7W.mjs.map → chunk-L6RJIVLS.mjs.map} +0 -0
- /package/dist/{chunk-WDLO7OLX.mjs.map → chunk-XQ6Z2KNN.mjs.map} +0 -0
- /package/dist/{chunk-FPVRSXQ4.mjs.map → chunk-YI3EQYEG.mjs.map} +0 -0
- /package/dist/{http-LPFPVTBC.mjs.map → http-5BRVWAJR.mjs.map} +0 -0
- /package/dist/{import-T4WX2ZJL.mjs.map → import-IAECQDKC.mjs.map} +0 -0
- /package/dist/{mcp-SMF3NWIN.mjs.map → mcp-XXSQJBGU.mjs.map} +0 -0
- /package/dist/{src-EGLLMTAU.mjs.map → src-4HLKMQ7S.mjs.map} +0 -0
- /package/dist/{stream-import-2BXJTTCE.mjs.map → stream-import-PUG42I36.mjs.map} +0 -0
- /package/dist/{worker-runtime-RDLSPXFT.mjs.map → worker-runtime-X5563TVT.mjs.map} +0 -0
- /package/dist-cli-web/assets/{ActionToolsPanel-DDNXXH8v.css → useInsightTabAnalytics-DDNXXH8v.css} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http/index.ts","../../../packages/http-routes/src/server.ts","../../../packages/http-routes/src/errors.ts","../../../packages/http-routes/src/auth.ts","../src/http/auth.ts","../src/http/server.ts","../src/http/routes/web/index.ts","../../../packages/http-routes/src/import/json-push-handler.ts","../../../packages/http-routes/src/routes/rest/imports.ts","../../../packages/http-routes/src/routes/rest/session-provider.ts","../../../packages/http-routes/src/routes/rest/sessions.ts","../../../packages/http-routes/src/routes/rest/system.ts","../../../packages/http-routes/src/routes/rest/register.ts","../../../packages/http-routes/src/plugins/node.ts","../../../packages/http-routes/src/routes/web/ai-agent-stream.ts","../../../packages/http-routes/src/routes/web/ai-assistants.ts","../../../packages/http-routes/src/routes/web/ai-chats.ts","../../../packages/http-routes/src/routes/web/ai-chat-topics.ts","../../../packages/http-routes/src/routes/web/ai-llm-stream.ts","../../../packages/http-routes/src/routes/web/ai-llm.ts","../../../packages/http-routes/src/routes/web/ai-logs.ts","../../../packages/http-routes/src/routes/web/ai-memories.ts","../../../packages/http-routes/src/routes/web/ai-semantic-index.ts","../../../packages/http-routes/src/routes/web/ai-skills.ts","../../../packages/http-routes/src/routes/web/ai-summaries.ts","../../../packages/http-routes/src/ai/tool-executor.ts","../../../packages/http-routes/src/routes/web/ai-tools.ts","../../../packages/http-routes/src/routes/web/memory-provenance-coordinator.ts","../../../packages/http-routes/src/routes/web/register-ai.ts","../../../packages/http-routes/src/routes/web/analytics.ts","../../../packages/http-routes/src/routes/web/time-filter.ts","../../../packages/http-routes/src/routes/web/analytics-cache.ts","../../../packages/http-routes/src/routes/web/cache.ts","../../../packages/http-routes/src/routes/web/contacts.ts","../../../packages/http-routes/src/routes/web/export.ts","../../../packages/http-routes/src/routes/web/logs.ts","../../../packages/http-routes/src/routes/web/members.ts","../../../packages/http-routes/src/routes/web/navigation-layout.ts","../../../packages/http-routes/src/routes/web/merge.ts","../../../packages/http-routes/src/routes/web/nlp.ts","../../../packages/http-routes/src/routes/web/people-relationships.ts","../../../packages/http-routes/src/routes/web/preferences.ts","../../../packages/http-routes/src/routes/web/session-index.ts","../../../packages/http-routes/src/routes/web/sessions.ts","../../../packages/http-routes/src/routes/web/sql.ts","../../../packages/http-routes/src/routes/web/telemetry.ts","../../../packages/http-routes/src/routes/web/register.ts","../../../packages/http-routes/src/register.ts","../../../packages/http-routes/src/plugins/builtin/annual-summary/index.ts","../../../packages/http-routes/src/plugins/builtin/time-investment/index.ts","../../../packages/http-routes/src/routes/web/automation.ts","../src/http/routes/web/import.ts","../src/http/routes/web/helpers.ts","../src/http/routes/web/cache.ts","../src/http/routes/web/update-check.ts","../src/http/routes/proxy.ts","../../../packages/sync/src/types.ts","../../../packages/sync/src/data-source-manager.ts","../../../packages/sync/src/pull-engine.ts","../../../packages/sync/src/scheduler.ts","../src/sync/adapters.ts","../src/sync/index.ts"],"sourcesContent":["/**\n * ChatLab HTTP API — Server lifecycle manager\n *\n * 独立于 Electron 的 HTTP API 服务入口。\n * 使用 DatabaseManager + @openchatlab/core 直接访问数据。\n */\n\nimport * as fs from 'fs'\nimport * as crypto from 'crypto'\nimport type { FastifyInstance } from 'fastify'\nimport { loadConfig, writeConfigField, MigrationRunner, ALL_MIGRATIONS } from '@openchatlab/config'\nimport type { ChatLabConfig } from '@openchatlab/config'\nimport {\n NodePathProvider,\n DatabaseManager,\n AIChatManager,\n createLlmRuntimeStores,\n applyPendingNodeDataDirMigrationIfNeeded,\n hasPendingElectronDataWarning,\n verifyCliDataPath,\n createSemanticIndexWorkerRuntimeClient,\n initAppLogger,\n appLogger,\n logNativeParserStatus,\n createContactsService,\n createCrossChatAnalysisService,\n createGlobalInsightService,\n createDatabaseManagerAdapter,\n PreferencesManager,\n AIMemoryService,\n} from '@openchatlab/node-runtime'\nimport type { SemanticIndexRuntime } from '@openchatlab/node-runtime'\nimport { createServer } from './server'\nimport { setAuthToken, setRequireAuth } from './auth'\nimport { registerWebRoutes } from './routes/web'\nimport { registerProxyRoutes } from './routes/proxy'\nimport { initServerAiLogger, closeServerAiLogger } from '../ai/logger'\nimport { getAssistantManager, getSkillManagerCore } from '../ai/manager-factory'\nimport { createCliRunAgentStream } from '../ai/agent-stream-runner'\nimport { initSync, cleanupSync } from '../sync'\nimport { resolveCliPath } from '../paths'\nimport { assertCliDataDirCompatible } from '../runtime-compat'\nimport { resolveCliLocalEmbeddingRuntimeConfig } from '../semantic-index/local-runtime'\nimport { prepareUnixSocket } from './port'\n\nlet server: FastifyInstance | null = null\nlet dbManager: DatabaseManager | null = null\nlet aiChatManager: AIChatManager | null = null\nlet aiMemoryService: AIMemoryService | null = null\n\nexport interface HttpServerOptions {\n port?: number\n host?: string\n /** Unix domain socket path. When set, takes precedence over port and host. */\n socket?: string\n token?: string\n /** dist-cli-web/ 目录路径,启用后托管 CLI Web SPA 静态资源 */\n webRoot?: string\n /** When true, /_web/* also requires Bearer token (for server/headless deployments) */\n requireAuth?: boolean\n}\n\nfunction resolveNativeBinding(): string | undefined {\n if (process.versions.electron) return undefined\n const nativePath = resolveCliPath('native/better_sqlite3.node')\n if (fs.existsSync(nativePath)) return nativePath\n return undefined\n}\n\nfunction ensureToken(config: ChatLabConfig): string {\n if (config.api.token) return config.api.token\n\n const token = `clb_${crypto.randomBytes(32).toString('hex')}`\n try {\n writeConfigField('api', 'token', token)\n } catch {\n // best-effort: token still usable for this session\n }\n return token\n}\n\n/**\n * 启动独立 HTTP API 服务\n */\nexport async function startHttpServer(options?: HttpServerOptions): Promise<{\n port?: number\n host?: string\n socket?: string\n token: string\n}> {\n if (server) {\n throw new Error('HTTP server is already running')\n }\n\n let config = loadConfig()\n const port = options?.port ?? config.api.port\n const host = options?.host ?? config.api.host\n const socket = options?.socket\n const token = options?.token ?? ensureToken(config)\n\n if (socket) await prepareUnixSocket(socket)\n\n const pendingMigration = applyPendingNodeDataDirMigrationIfNeeded()\n if (!pendingMigration.skipped) {\n if (pendingMigration.success) {\n console.log('[Migration] Pending data directory migration completed')\n config = loadConfig()\n } else {\n console.error('[Migration] Pending data directory migration failed:', pendingMigration.error)\n }\n }\n\n const userDataDir = config.data.user_data_dir || undefined\n const pathProvider = new NodePathProvider(userDataDir)\n pathProvider.ensureAllDirs()\n const runtime = assertCliDataDirCompatible(pathProvider, 'cli')\n\n if (hasPendingElectronDataWarning() || !verifyCliDataPath(pathProvider.getDatabaseDir())) {\n console.error(\n '\\n' +\n '='.repeat(68) +\n '\\n' +\n ' ChatLab: Electron desktop data not found\\n' +\n '='.repeat(68) +\n '\\n\\n' +\n ' Detected that ChatLab desktop app was installed on this machine,\\n' +\n ' but could not locate your chat databases.\\n\\n' +\n ' This usually means you changed the data directory in desktop settings.\\n\\n' +\n ' To fix this, choose one of:\\n\\n' +\n ' 1. Open ChatLab desktop app — it will auto-migrate your data\\n' +\n ' 2. Set the data directory manually:\\n' +\n ' export CHATLAB_DATA_DIR=\"/path/to/your/data\"\\n' +\n ' 3. Edit ~/.chatlab/config.toml:\\n' +\n ' [data]\\n' +\n ' user_data_dir = \"/path/to/your/data\"\\n\\n' +\n '='.repeat(68) +\n '\\n'\n )\n }\n\n const migrationRunner = new MigrationRunner(ALL_MIGRATIONS, {\n dataDir: pathProvider.getSystemDir(),\n aiDataDir: pathProvider.getAiDataDir(),\n logger: {\n info: (_cat: string, msg: string) => console.log(`[Migration] ${msg}`),\n warn: (_cat: string, msg: string) => console.warn(`[Migration] ${msg}`),\n error: (_cat: string, msg: string, ...args: unknown[]) => console.error(`[Migration] ${msg}`, ...args),\n },\n })\n await migrationRunner.run()\n const nativeBinding = resolveNativeBinding()\n dbManager = new DatabaseManager(pathProvider, { nativeBinding, runtime })\n const sessionAdapter = createDatabaseManagerAdapter(dbManager)\n const contactsService = createContactsService({\n adapter: sessionAdapter,\n pathProvider,\n runtimeIdentity: runtime,\n nativeBinding,\n })\n const preferencesManager = new PreferencesManager(pathProvider.getSystemDir())\n const globalInsightService = createGlobalInsightService({\n adapter: sessionAdapter,\n pathProvider,\n runtimeIdentity: runtime,\n nativeBinding,\n getExcludedSessionIds: () => preferencesManager.load().ownerExcludedSessionIds,\n })\n const crossChatAnalysisService = createCrossChatAnalysisService({\n adapter: sessionAdapter,\n contactsService,\n globalInsightService,\n getExcludedSessionIds: () => preferencesManager.load().ownerExcludedSessionIds,\n })\n\n const aiDataDir = pathProvider.getAiDataDir()\n aiChatManager = new AIChatManager(aiDataDir, { nativeBinding })\n aiMemoryService = new AIMemoryService(aiDataDir, { nativeBinding })\n\n const assistantManager = getAssistantManager(aiDataDir)\n const skillManagerCore = getSkillManagerCore(aiDataDir)\n const llmRuntimeStores = createLlmRuntimeStores(aiDataDir)\n const { llmConfigStore, customProviderStore, customModelStore } = llmRuntimeStores\n\n initAppLogger(pathProvider.getLogsDir())\n initServerAiLogger(pathProvider.getLogsDir())\n appLogger.info('ai-config', 'Shared LLM configuration store initialized', { aiDataDir })\n appLogger.info('temp-workspace', 'Temporary workspace initialized', { root: pathProvider.getTempDir() })\n appLogger.info(\n 'server',\n socket ? `HTTP server starting on Unix socket ${socket}` : `HTTP server starting on ${host}:${port}`\n )\n // 记录 Rust native parser 可用性(导入是否走 Rust 内核),便于按日志排查回退原因\n logNativeParserStatus()\n\n setAuthToken(token)\n setRequireAuth(!!(options?.requireAuth ?? config.api.require_auth))\n\n server = createServer()\n\n const multipart = await import('@fastify/multipart')\n await server.register(multipart.default, {\n limits: { fileSize: 1024 * 1024 * 1024 }, // 1GB\n })\n\n // 语义索引 worker client:启动 HTTP 服务时不拉起 worker;状态/构建/检索按需 lazy start。\n let semanticIndexService: SemanticIndexRuntime | undefined\n try {\n semanticIndexService = createSemanticIndexWorkerRuntimeClient({\n pathProvider,\n runtime,\n nativeBinding,\n localEmbeddingRuntime: resolveCliLocalEmbeddingRuntimeConfig(pathProvider.getAiDataDir()),\n workerEntryUrl: import.meta.url.endsWith('.ts')\n ? undefined\n : new URL('./semantic-index-worker.mjs', import.meta.url),\n })\n server.addHook('onClose', async () => semanticIndexService?.close())\n } catch (err) {\n console.warn('[semantic-index] worker client unavailable:', err instanceof Error ? err.message : String(err))\n semanticIndexService = undefined\n }\n\n registerWebRoutes(server, dbManager, {\n pathProvider,\n nativeBinding,\n runtimeIdentity: runtime,\n contactsService,\n globalInsightService,\n preferencesManager,\n semanticIndexService,\n aiContext: {\n aiDataDir,\n aiChatManager,\n aiMemoryService,\n assistantManager,\n skillManagerCore,\n llmConfigStore,\n customProviderStore,\n customModelStore,\n runAgentStream: createCliRunAgentStream(dbManager, aiChatManager, {\n llmConfigStore,\n semanticIndexService,\n crossChatAnalysisService,\n sessionAdapter,\n memoryService: aiMemoryService,\n }),\n },\n })\n\n initSync(server, dbManager, pathProvider, { port, host, socket, token })\n\n if (options?.webRoot && fs.existsSync(options.webRoot)) {\n // 注册反向代理:将 /_proxy/chatlab.fun/* 转发至 https://chatlab.fun,\n // 行为与 vite dev proxy 一致,解决浏览器 CORS 问题(见 vite.cli-web.config.mts)。\n // 必须在 @fastify/static 之前注册,确保显式路由优先于静态文件/SPA fallback。\n registerProxyRoutes(server)\n const fastifyStatic = await import('@fastify/static')\n await server.register(fastifyStatic.default, {\n root: options.webRoot,\n prefix: '/',\n wildcard: false,\n })\n // SPA fallback: 所有非 API/非静态文件路由返回 index.html\n server.setNotFoundHandler(async (_request, reply) => {\n return reply.sendFile('index.html')\n })\n }\n\n if (socket) {\n await server.listen({ path: socket })\n } else {\n await server.listen({ port, host })\n }\n\n return socket ? { socket, token } : { port, host, token }\n}\n\n/**\n * 停止 HTTP API 服务\n */\nexport async function stopHttpServer(): Promise<void> {\n if (!server) return\n\n try {\n await server.close()\n } finally {\n cleanupSync()\n if (aiChatManager) {\n aiChatManager.close()\n aiChatManager = null\n }\n if (aiMemoryService) {\n aiMemoryService.close()\n aiMemoryService = null\n }\n if (dbManager) {\n dbManager.closeAll()\n dbManager = null\n }\n closeServerAiLogger()\n setRequireAuth(false)\n server = null\n }\n}\n\nexport { createServer } from './server'\nexport { registerWebRoutes } from './routes/web'\n","import Fastify, { type FastifyError, type FastifyInstance, type FastifyReply, type FastifyRequest } from 'fastify'\nimport { ApiError, ApiErrorCode, apiErrorFromUnknown, errorResponse, serverError } from './errors'\n\nexport const DEFAULT_JSON_BODY_LIMIT = 50 * 1024 * 1024\n\nexport interface ApiServerOptions {\n bodyLimit?: number\n authHook?: (request: FastifyRequest, reply: FastifyReply) => void | Promise<void>\n onUnhandledError?: (request: FastifyRequest, error: FastifyError) => void\n}\n\nexport function configureApiErrorHandler(server: FastifyInstance, options: ApiServerOptions = {}): void {\n server.setErrorHandler((error: FastifyError, request, reply) => {\n const apiError = apiErrorFromUnknown(error)\n if (apiError) {\n reply.code(apiError.statusCode).send(errorResponse(apiError))\n return\n }\n\n if (error.statusCode === 413) {\n const bodyError = new ApiError(ApiErrorCode.BODY_TOO_LARGE, 'Request body exceeds 50MB limit')\n reply.code(bodyError.statusCode).send(errorResponse(bodyError))\n return\n }\n\n const statusCode = error.statusCode\n if (statusCode && statusCode >= 400 && statusCode < 600) {\n reply.code(statusCode).send({ success: false, error: { code: 'CLIENT_ERROR', message: error.message } })\n return\n }\n\n options.onUnhandledError?.(request, error)\n const internalError = serverError(error.message)\n reply.code(internalError.statusCode).send(errorResponse(internalError))\n })\n}\n\nexport function createApiServer(options: ApiServerOptions = {}): FastifyInstance {\n const server = Fastify({\n logger: false,\n bodyLimit: options.bodyLimit ?? DEFAULT_JSON_BODY_LIMIT,\n })\n\n if (options.authHook) server.addHook('onRequest', options.authHook)\n configureApiErrorHandler(server, options)\n return server\n}\n","/**\n * ChatLab HTTP API — Error codes and factory functions\n *\n * Platform-agnostic error handling shared by CLI Server and Electron Internal Server.\n */\n\nimport { DataDirCompatibilityError } from '@openchatlab/node-runtime/data-dir-compat'\nimport { ImportInProgressError } from '@openchatlab/node-runtime/src/import/import-lock'\n\nexport enum ApiErrorCode {\n UNAUTHORIZED = 'UNAUTHORIZED',\n SESSION_NOT_FOUND = 'SESSION_NOT_FOUND',\n INVALID_FORMAT = 'INVALID_FORMAT',\n INVALID_PAYLOAD = 'INVALID_PAYLOAD',\n SQL_READONLY_VIOLATION = 'SQL_READONLY_VIOLATION',\n SQL_EXECUTION_ERROR = 'SQL_EXECUTION_ERROR',\n EXPORT_TOO_LARGE = 'EXPORT_TOO_LARGE',\n BODY_TOO_LARGE = 'BODY_TOO_LARGE',\n IMPORT_IN_PROGRESS = 'IMPORT_IN_PROGRESS',\n IDEMPOTENCY_CONFLICT = 'IDEMPOTENCY_CONFLICT',\n IDEMPOTENCY_PENDING = 'IDEMPOTENCY_PENDING',\n IMPORT_FAILED = 'IMPORT_FAILED',\n DATA_DIR_INCOMPATIBLE = 'DATA_DIR_INCOMPATIBLE',\n SERVER_ERROR = 'SERVER_ERROR',\n}\n\nconst HTTP_STATUS: Record<ApiErrorCode, number> = {\n [ApiErrorCode.UNAUTHORIZED]: 401,\n [ApiErrorCode.SESSION_NOT_FOUND]: 404,\n [ApiErrorCode.INVALID_FORMAT]: 400,\n [ApiErrorCode.INVALID_PAYLOAD]: 400,\n [ApiErrorCode.SQL_READONLY_VIOLATION]: 400,\n [ApiErrorCode.SQL_EXECUTION_ERROR]: 400,\n [ApiErrorCode.EXPORT_TOO_LARGE]: 400,\n [ApiErrorCode.BODY_TOO_LARGE]: 413,\n [ApiErrorCode.IMPORT_IN_PROGRESS]: 409,\n [ApiErrorCode.IDEMPOTENCY_CONFLICT]: 409,\n [ApiErrorCode.IDEMPOTENCY_PENDING]: 409,\n [ApiErrorCode.IMPORT_FAILED]: 500,\n [ApiErrorCode.DATA_DIR_INCOMPATIBLE]: 409,\n [ApiErrorCode.SERVER_ERROR]: 500,\n}\n\n// REST response envelope version; independent from the ChatLab file format version.\nconst API_RESPONSE_VERSION = '0.0.2'\n\nexport class ApiError extends Error {\n code: ApiErrorCode\n statusCode: number\n\n constructor(code: ApiErrorCode, message: string) {\n super(message)\n this.name = 'ApiError'\n this.code = code\n this.statusCode = HTTP_STATUS[code]\n }\n}\n\nexport function unauthorized(message = 'Invalid or missing token'): ApiError {\n return new ApiError(ApiErrorCode.UNAUTHORIZED, message)\n}\n\nexport function sessionNotFound(id: string): ApiError {\n return new ApiError(ApiErrorCode.SESSION_NOT_FOUND, `Session not found: ${id}`)\n}\n\nexport function invalidFormat(message: string): ApiError {\n return new ApiError(ApiErrorCode.INVALID_FORMAT, message)\n}\n\nexport function invalidPayload(message: string): ApiError {\n return new ApiError(ApiErrorCode.INVALID_PAYLOAD, message)\n}\n\nexport function sqlReadonlyViolation(): ApiError {\n return new ApiError(ApiErrorCode.SQL_READONLY_VIOLATION, 'Only SELECT queries are allowed')\n}\n\nexport function sqlExecutionError(message: string): ApiError {\n return new ApiError(ApiErrorCode.SQL_EXECUTION_ERROR, message)\n}\n\nexport function exportTooLarge(count: number, limit: number): ApiError {\n return new ApiError(\n ApiErrorCode.EXPORT_TOO_LARGE,\n `Message count ${count} exceeds export limit ${limit}. Use paginated /messages API instead.`\n )\n}\n\nexport function serverError(message = 'Internal server error'): ApiError {\n return new ApiError(ApiErrorCode.SERVER_ERROR, message)\n}\n\nexport function importInProgress(message = 'Another import is already in progress'): ApiError {\n return new ApiError(ApiErrorCode.IMPORT_IN_PROGRESS, message)\n}\n\nexport function idempotencyConflict(): ApiError {\n return new ApiError(ApiErrorCode.IDEMPOTENCY_CONFLICT, 'Same Idempotency-Key with different request body hash')\n}\n\nexport function idempotencyPending(): ApiError {\n return new ApiError(\n ApiErrorCode.IDEMPOTENCY_PENDING,\n 'A request with this Idempotency-Key is still in progress. Please retry later.'\n )\n}\n\nexport function importFailed(message: string): ApiError {\n return new ApiError(ApiErrorCode.IMPORT_FAILED, message)\n}\n\nexport function dataDirIncompatible(message: string): ApiError {\n return new ApiError(ApiErrorCode.DATA_DIR_INCOMPATIBLE, message)\n}\n\nexport function apiErrorFromUnknown(error: unknown): ApiError | null {\n if (error instanceof ApiError) return error\n if (error instanceof ImportInProgressError) return importInProgress()\n const compatibilityError = findDataDirCompatibilityError(error)\n if (compatibilityError) return dataDirIncompatible(compatibilityError.message)\n return null\n}\n\nfunction findDataDirCompatibilityError(error: unknown): DataDirCompatibilityError | null {\n const seen = new Set<unknown>()\n let current = error\n\n while (current instanceof Error && !seen.has(current)) {\n if (current instanceof DataDirCompatibilityError) return current\n seen.add(current)\n current = current.cause\n }\n\n return null\n}\n\nexport function successResponse<T>(data: T, meta?: Record<string, unknown>) {\n return {\n success: true as const,\n data,\n meta: {\n timestamp: Math.floor(Date.now() / 1000),\n version: API_RESPONSE_VERSION,\n ...meta,\n },\n }\n}\n\nexport function errorResponse(error: ApiError) {\n return {\n success: false as const,\n error: {\n code: error.code,\n message: error.message,\n },\n }\n}\n","/**\n * ChatLab HTTP API — Bearer Token authentication hook\n *\n * Shared auth middleware factory for CLI and Electron APIs.\n */\n\nimport type { FastifyRequest, FastifyReply } from 'fastify'\nimport { timingSafeEqual, createHmac, randomBytes } from 'crypto'\nimport { unauthorized, errorResponse } from './errors'\n\nexport interface BearerAuthOptions {\n getToken: () => string | null | undefined\n shouldAuthenticate?: (request: FastifyRequest) => boolean\n allowMissingToken?: boolean\n missingTokenMessage?: string\n invalidTokenMessage?: string\n}\n\nexport function createBearerAuthHook(options: BearerAuthOptions) {\n // Compare via HMAC digests (fixed 32-byte length) to avoid leaking token length.\n const hmacKey = randomBytes(32)\n const safeTokenCompare = (provided: string, expected: string): boolean => {\n const providedHash = createHmac('sha256', hmacKey).update(provided).digest()\n const expectedHash = createHmac('sha256', hmacKey).update(expected).digest()\n return timingSafeEqual(providedHash, expectedHash)\n }\n\n return async function bearerAuthHook(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n if (options.shouldAuthenticate && !options.shouldAuthenticate(request)) return\n\n const expectedToken = options.getToken()\n if (!expectedToken && options.allowMissingToken !== false) return\n\n const authHeader = request.headers.authorization\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n const err = unauthorized(options.missingTokenMessage)\n reply.code(err.statusCode).send(errorResponse(err))\n return\n }\n\n const providedToken = authHeader.slice(7)\n if (!expectedToken || !safeTokenCompare(providedToken, expectedToken)) {\n const err = unauthorized(options.invalidTokenMessage)\n reply.code(err.statusCode).send(errorResponse(err))\n }\n }\n}\n","/** CLI HTTP authentication policy built on the shared Bearer hook. */\n\nimport { createBearerAuthHook } from '@openchatlab/http-routes/auth'\n\nlet cachedToken: string | null = null\nlet requireAuthEnabled = false\n\nexport function setAuthToken(token: string): void {\n cachedToken = token\n}\n\n/** Require Bearer auth for Web UI routes in headless or remote deployments. */\nexport function setRequireAuth(enabled: boolean): void {\n requireAuthEnabled = enabled\n}\n\nexport const authHook = createBearerAuthHook({\n getToken: () => cachedToken,\n shouldAuthenticate: (request) =>\n request.url.startsWith('/api/') || (requireAuthEnabled && request.url.startsWith('/_web/')),\n})\n","/**\n * ChatLab HTTP API — Fastify server factory\n *\n * 从 electron/main/api/server.ts 迁移,完全平台无关。\n */\n\nimport type { FastifyInstance } from 'fastify'\nimport { createApiServer } from '@openchatlab/http-routes/server'\nimport { appLogger } from '@openchatlab/node-runtime'\nimport { authHook } from './auth'\n\nexport function createServer(): FastifyInstance {\n return createApiServer({\n authHook,\n onUnhandledError: (request, error) => {\n appLogger.error('http', `${request.method} ${request.url} -> 500`, error)\n },\n })\n}\n","/**\n * ChatLab Internal Web API — /_web/ routes\n *\n * 供 CLI Web 前端使用的内部 API(无认证、UI 友好的响应格式)。\n * 数据格式直接对齐 QueryAdapter 接口,避免前端二次转换。\n *\n * Route modules:\n * sessions – Session CRUD\n * members – Member management\n * analytics – Stats and advanced analytics\n * sql – SQL Lab and plugin query\n * sessionIndex – Session index generation\n * summaries – LLM summary generation\n * import – File / directory / incremental import + demo\n * merge – Merge parse / conflicts / execute\n * export – Markdown export\n * cache – Storage management + save to downloads + show in folder\n */\n\nimport * as os from 'os'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { PathProvider } from '@openchatlab/core'\nimport type {\n DatabaseManager,\n AIChatManager,\n AIMemoryService,\n AssistantManager,\n SkillManagerCore,\n LLMConfigStore,\n CustomProviderStore,\n CustomModelStore,\n ContactsService,\n GlobalInsightService,\n PreferencesManager,\n PendingDataDirMigration,\n RuntimeIdentity,\n} from '@openchatlab/node-runtime'\nimport {\n createDatabaseManagerAdapter,\n createNodeDataDirSwitch,\n deletePendingDataDirCleanup,\n dismissPendingDataDirCleanupNotice,\n getDefaultNodeUserDataDir,\n getPendingDataDirCleanups,\n getPendingNodeDataDirMigration,\n getChatLabTempScopeDir,\n AnalyticsService,\n MergeSessionCache,\n type SemanticIndexRuntime,\n} from '@openchatlab/node-runtime'\nimport { annualSummaryNodePlugin, registerSharedRoutes, timeInvestmentNodePlugin } from '@openchatlab/http-routes'\nimport type { HttpRouteContext } from '@openchatlab/http-routes'\nimport { registerImportRoutes } from './import'\nimport { openDirectoryPath, showPathInFolder } from './cache'\nimport { getVersion } from '../../../version'\nimport { buildWebUpdateCheckResult } from './update-check'\nimport { getServerAiLogger } from '../../../ai/logger'\n\nexport interface AiContextOptions {\n aiDataDir: string\n aiChatManager: AIChatManager\n aiMemoryService: AIMemoryService\n assistantManager: AssistantManager\n skillManagerCore: SkillManagerCore\n llmConfigStore: LLMConfigStore\n customProviderStore: CustomProviderStore\n customModelStore: CustomModelStore\n runAgentStream?: HttpRouteContext['runAgentStream']\n}\n\nexport function registerWebRoutes(\n server: FastifyInstance,\n dbManager: DatabaseManager,\n options?: {\n pathProvider?: PathProvider\n nativeBinding?: string\n runtimeIdentity?: RuntimeIdentity\n contactsService?: ContactsService\n globalInsightService?: GlobalInsightService\n preferencesManager?: PreferencesManager\n aiContext?: AiContextOptions\n /** 由 server 入口注入的共享语义索引运行时;传入时由调用方管理生命周期 */\n semanticIndexService?: SemanticIndexRuntime\n }\n): void {\n const adapter = createDatabaseManagerAdapter(dbManager)\n\n const mergeCache = options?.pathProvider\n ? new MergeSessionCache(options.pathProvider, { nativeBinding: options.nativeBinding })\n : null\n mergeCache?.cleanupOrphans()\n\n const fallbackPathProvider: PathProvider = {\n getSystemDir: () => path.join(os.homedir(), '.chatlab'),\n getUserDataDir: () => path.join(os.homedir(), '.chatlab', 'data'),\n getDatabaseDir: () => path.join(os.homedir(), '.chatlab', 'data', 'databases'),\n getVectorDir: () => path.join(os.homedir(), '.chatlab', 'data', 'vector'),\n getAiDataDir: () => path.join(os.homedir(), '.chatlab', 'ai'),\n getSettingsDir: () => path.join(os.homedir(), '.chatlab', 'settings'),\n getCacheDir: () => path.join(os.homedir(), '.chatlab', 'cache'),\n getTempDir: () => getChatLabTempScopeDir('runtime'),\n getLogsDir: () => path.join(os.homedir(), '.chatlab', 'logs'),\n getDownloadsDir: () => path.join(os.homedir(), 'Downloads'),\n }\n const resolvedPathProvider = options?.pathProvider ?? fallbackPathProvider\n\n const ai = options?.aiContext\n\n const cliStreamImport = async (dm: typeof dbManager, filePath: string) => {\n const { streamImport } = await import('../../../import/stream-import')\n const result = await streamImport(dm, filePath)\n if (!result.success) {\n const { IMPORT_IN_PROGRESS_ERROR_KEY, ImportInProgressError } = await import('@openchatlab/node-runtime')\n if (result.error === IMPORT_IN_PROGRESS_ERROR_KEY) throw new ImportInProgressError()\n throw new Error(result.error || 'Import failed')\n }\n if (!result.sessionId) throw new Error('Import succeeded but no sessionId returned')\n return { sessionId: result.sessionId }\n }\n\n const defaultUserDataDir = getDefaultNodeUserDataDir()\n const isCustom = path.resolve(resolvedPathProvider.getUserDataDir()) !== path.resolve(defaultUserDataDir)\n\n const semanticIndexService = options?.semanticIndexService\n\n const analyticsService = new AnalyticsService(resolvedPathProvider.getSystemDir(), {\n appVersion: getVersion(),\n appType: 'cli_web',\n getAiModelConfigured: () => ai?.llmConfigStore.hasConfiguredModel() === true,\n })\n\n registerSharedRoutes(\n server,\n {\n dbManager,\n sessionAdapter: adapter,\n pathProvider: resolvedPathProvider,\n runtimeIdentity: options?.runtimeIdentity,\n getVersion,\n nativeBinding: options?.nativeBinding,\n bundledNlpDictDir: process.env.CHATLAB_NLP_DICT_DIR?.trim() || undefined,\n semanticIndexService,\n contactsService: options?.contactsService,\n globalInsightService: options?.globalInsightService,\n preferencesManager: options?.preferencesManager,\n analyticsService,\n getCurrentAiLogPath: () => getServerAiLogger()?.getExistingLogPath() ?? null,\n openDirectory: openDirectoryPath,\n showInFolder: showPathInFolder,\n downloadsDir: resolvedPathProvider.getDownloadsDir(),\n defaultUserDataDir,\n isCustomDataDir: isCustom,\n canSetDataDir: !process.env.CHATLAB_DATA_DIR,\n getPendingDataDirMigration: (): PendingDataDirMigration | null =>\n getPendingNodeDataDirMigration(resolvedPathProvider.getSystemDir()),\n getPendingDataDirCleanups: () => getPendingDataDirCleanups(resolvedPathProvider.getSystemDir()),\n dismissPendingDataDirCleanupNotice: (cleanupId) =>\n dismissPendingDataDirCleanupNotice(resolvedPathProvider.getSystemDir(), cleanupId),\n deletePendingDataDirCleanup: (cleanupId) => {\n return deletePendingDataDirCleanup(\n resolvedPathProvider.getSystemDir(),\n resolvedPathProvider.getUserDataDir(),\n cleanupId\n )\n },\n setDataDir: (dirPath, migrate) =>\n createNodeDataDirSwitch({\n systemDir: resolvedPathProvider.getSystemDir(),\n currentDir: resolvedPathProvider.getUserDataDir(),\n targetDir: dirPath,\n defaultDir: defaultUserDataDir,\n migrate,\n envDataDir: process.env.CHATLAB_DATA_DIR,\n }),\n ...(mergeCache && {\n mergeSessionCache: mergeCache,\n streamImport: cliStreamImport,\n }),\n ...(ai && {\n aiDataDir: ai.aiDataDir,\n aiChatManager: ai.aiChatManager,\n aiMemoryService: ai.aiMemoryService,\n assistantManager: ai.assistantManager,\n skillManagerCore: ai.skillManagerCore,\n llmConfigStore: ai.llmConfigStore,\n customProviderStore: ai.customProviderStore,\n customModelStore: ai.customModelStore,\n runAgentStream: ai.runAgentStream,\n }),\n },\n {\n nodePlugins: [annualSummaryNodePlugin, timeInvestmentNodePlugin],\n ...(ai && { requireAi: true }),\n }\n )\n\n // CLI-specific routes not yet migrated to @openchatlab/http-routes\n registerImportRoutes(server, dbManager)\n\n server.get('/_web/system/check-update', async () => {\n const currentVersion = getVersion()\n try {\n const resp = await fetch('https://chatlab.fun/latest-version', {\n headers: { Accept: 'application/json' },\n signal: AbortSignal.timeout(10_000),\n })\n if (!resp.ok) {\n return { hasUpdate: false, currentVersion, error: `latest-version HTTP ${resp.status}` }\n }\n const data = (await resp.json()) as { version?: string }\n return buildWebUpdateCheckResult({ currentVersion, latestVersion: data.version })\n } catch (err) {\n return {\n hasUpdate: false,\n currentVersion,\n error: err instanceof Error ? err.message : String(err),\n }\n }\n })\n}\n","import {\n hashImportBody,\n ImportIdempotencyCache,\n isValidImportSessionId,\n type PushImportAnalysisOutcome,\n type PushImportOutcome,\n type PushImportPayload,\n type PushImportResult,\n} from '@openchatlab/node-runtime'\nimport {\n apiErrorFromUnknown,\n errorResponse,\n idempotencyConflict,\n idempotencyPending,\n importFailed,\n importInProgress,\n invalidPayload,\n successResponse,\n} from '../errors'\n\nexport type ImportSuccessResponse = ReturnType<typeof successResponse<unknown>>\ntype ImportErrorResponse = ReturnType<typeof errorResponse>\n\nexport interface JsonPushImportRequest {\n sessionId: string\n body: unknown\n contentType: string\n idempotencyKey?: string\n dryRun?: boolean\n}\n\nexport interface JsonPushImportHttpResult {\n statusCode: number\n response: ImportSuccessResponse | ImportErrorResponse\n}\n\nexport interface JsonPushImportHandlerOptions {\n execute: (sessionId: string, payload: PushImportPayload) => Promise<PushImportOutcome>\n analyze?: (sessionId: string, payload: PushImportPayload) => Promise<PushImportAnalysisOutcome>\n idempotencyCache?: ImportIdempotencyCache<ImportSuccessResponse>\n includeDryRunInIdempotencyKey?: boolean\n importInProgressMessage?: string\n acquire?: (sessionId: string) => boolean | Promise<boolean>\n release?: (sessionId: string) => void | Promise<void>\n onSuccess?: (result: PushImportResult) => void | Promise<void>\n onError?: (error: unknown) => void\n}\n\nexport type JsonPushImportHandler = (request: JsonPushImportRequest) => Promise<JsonPushImportHttpResult>\n\nconst INVALID_SESSION_ID_MESSAGE =\n \"sessionId must be 1-128 safe characters, start with [A-Za-z0-9_@-], and not contain '..'\"\n\nexport function buildImportIdempotencyCacheKey(\n idempotencyKey: string | undefined,\n sessionId: string,\n dryRun: boolean,\n includeDryRun: boolean\n): string | null {\n if (!idempotencyKey) return null\n return includeDryRun ? `${idempotencyKey}:${sessionId}:${dryRun}` : `${idempotencyKey}:${sessionId}`\n}\n\nfunction errorResult(error: ReturnType<typeof invalidPayload>): JsonPushImportHttpResult {\n return { statusCode: error.statusCode, response: errorResponse(error) }\n}\n\nfunction analysisResponse(sessionId: string, outcome: Extract<PushImportAnalysisOutcome, { ok: true }>) {\n const analysis = {\n totalInFile: outcome.result.totalInFile,\n newMessageCount: outcome.result.newMessageCount,\n duplicateCount: outcome.result.duplicateCount,\n }\n return successResponse({\n sessionId,\n created: outcome.result.created,\n dryRun: true,\n analysis: outcome.result.created ? { ...analysis, newMemberCount: outcome.result.newMemberCount } : analysis,\n })\n}\n\nexport function createJsonPushImportHandler(options: JsonPushImportHandlerOptions): JsonPushImportHandler {\n const idempotencyCache = options.idempotencyCache ?? new ImportIdempotencyCache<ImportSuccessResponse>()\n\n return async (request) => {\n const contentType = request.contentType.toLowerCase()\n if (!contentType.includes('application/json')) {\n return errorResult(invalidPayload('Content-Type must be application/json (JSONL is not yet supported)'))\n }\n if (!isValidImportSessionId(request.sessionId)) {\n return errorResult(invalidPayload(INVALID_SESSION_ID_MESSAGE))\n }\n\n const dryRun = request.dryRun === true\n if (dryRun && !options.analyze) {\n return errorResult(invalidPayload('X-Dry-Run is not yet supported'))\n }\n\n const cacheKey = buildImportIdempotencyCacheKey(\n request.idempotencyKey,\n request.sessionId,\n dryRun,\n options.includeDryRunInIdempotencyKey === true\n )\n if (cacheKey) {\n const start = idempotencyCache.start(cacheKey, hashImportBody(request.body))\n if (start.status === 'conflict') return errorResult(idempotencyConflict())\n if (start.status === 'pending') return errorResult(idempotencyPending())\n if (start.status === 'success') return { statusCode: 200, response: start.response }\n }\n\n let acquired = false\n try {\n if (options.acquire) {\n acquired = await options.acquire(request.sessionId)\n if (!acquired) {\n if (cacheKey) idempotencyCache.fail(cacheKey)\n return errorResult(importInProgress(options.importInProgressMessage))\n }\n }\n\n const payload = (request.body ?? {}) as PushImportPayload\n if (dryRun) {\n const outcome = await options.analyze!(request.sessionId, payload)\n if (!outcome.ok) {\n if (cacheKey) idempotencyCache.fail(cacheKey)\n const error =\n outcome.reason === 'invalid_payload' ? invalidPayload(outcome.message) : importFailed(outcome.message)\n return errorResult(error)\n }\n\n const response = analysisResponse(request.sessionId, outcome)\n if (cacheKey) idempotencyCache.success(cacheKey, response)\n return { statusCode: 200, response }\n }\n\n const outcome = await options.execute(request.sessionId, payload)\n if (!outcome.ok) {\n if (cacheKey) idempotencyCache.fail(cacheKey)\n const error =\n outcome.reason === 'import_in_progress'\n ? importInProgress(options.importInProgressMessage)\n : outcome.reason === 'invalid_payload'\n ? invalidPayload(outcome.message)\n : importFailed(outcome.message)\n return errorResult(error)\n }\n\n const response = successResponse(outcome.result)\n if (cacheKey) idempotencyCache.success(cacheKey, response)\n try {\n await options.onSuccess?.(outcome.result)\n } catch (error) {\n options.onError?.(error)\n }\n return { statusCode: 200, response }\n } catch (error) {\n if (cacheKey) idempotencyCache.fail(cacheKey)\n options.onError?.(error)\n const apiError = apiErrorFromUnknown(error)\n if (apiError) return errorResult(apiError)\n return errorResult(importFailed(error instanceof Error ? error.message : 'Import process error'))\n } finally {\n if (acquired) {\n try {\n await options.release?.(request.sessionId)\n } catch (error) {\n options.onError?.(error)\n }\n }\n }\n }\n}\n","/**\n * ChatLab HTTP API — Push Import route (/api/v1/imports/*)\n *\n * POST /api/v1/imports/:sessionId\n * Creates a new session or appends messages to an existing one.\n * See docs/cn/standard/chatlab-import.md for protocol spec.\n */\n\nimport type { FastifyInstance } from 'fastify'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport { appLogger, pushImport } from '@openchatlab/node-runtime'\nimport type { PushImportPayload } from '@openchatlab/node-runtime'\nimport { createJsonPushImportHandler } from '../../import/json-push-handler'\n\ntype ImportRouteContext = Pick<RuntimeRouteContext, 'dbManager'>\n\nexport function registerImportRoutes(server: FastifyInstance, ctx: ImportRouteContext): void {\n const handleJsonPushImport = createJsonPushImportHandler({\n execute: (sessionId, payload) => pushImport(ctx.dbManager, sessionId, payload),\n onError: (error) => appLogger.error('http-import', 'Push import request failed', error),\n })\n\n server.post<{ Params: { sessionId: string }; Body: PushImportPayload }>(\n '/api/v1/imports/:sessionId',\n async (request, reply) => {\n const idempotencyKey = request.headers['idempotency-key']\n const result = await handleJsonPushImport({\n sessionId: request.params.sessionId,\n body: request.body,\n contentType: request.headers['content-type'] || '',\n idempotencyKey: typeof idempotencyKey === 'string' ? idempotencyKey : undefined,\n dryRun: request.headers['x-dry-run'] === 'true',\n })\n return reply.code(result.statusCode).send(result.response)\n }\n )\n}\n","/** Data access contract for the public REST session routes. */\nimport {\n executeReadonlySql,\n getLastPlatformMessageId,\n getMemberActivity,\n getMembersWithAliases,\n getMessageTypeStats,\n getSessionInfo,\n getSessionMeta,\n getSessionOverview,\n queryMessages,\n} from '@openchatlab/core'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\n\ntype Awaitable<T> = T | Promise<T>\n\nexport interface RestSessionSummary {\n id: string\n name: string\n platform: string\n type: string\n groupId?: string\n messageCount: number\n memberCount: number\n firstTimestamp: number | null\n lastTimestamp: number | null\n importedAt?: number\n}\n\nexport interface RestSessionDetail extends RestSessionSummary {\n lastPlatformMessageId: string | null\n importedAt: number\n}\n\nexport interface RestMessageQuery {\n keyword?: string\n startTime?: number\n endTime?: number\n senderId?: number\n limit: number\n offset: number\n}\n\nexport interface RestMessagePage {\n messages: unknown[]\n total: number\n totalPages?: number\n}\n\nexport interface RestSessionOverview {\n messageCount: number\n memberCount: number\n timeRange: { start: number; end: number }\n messageTypeDistribution: Record<string, number>\n topMembers: Array<{\n platformId: string\n name: string\n messageCount: number\n percentage: number\n }>\n}\n\nexport interface RestSessionMember {\n id: number\n platformId: string\n name: string\n messageCount: number\n accountName?: string | null\n groupNickname?: string | null\n aliases?: string[]\n avatar?: string | null\n lastMessageTs?: number | null\n}\n\nexport type RestSessionMemberInput = Omit<RestSessionMember, 'name'> & { name?: string | null }\n\nexport function normalizeRestSessionMember(member: RestSessionMemberInput): RestSessionMember {\n return {\n ...member,\n name: member.name || member.groupNickname || member.accountName || member.platformId,\n }\n}\n\nexport interface RestExportMember {\n platformId: string\n accountName?: string | null\n groupNickname?: string | null\n aliases?: string[]\n}\n\nexport interface RestExportMessage {\n senderPlatformId: string\n senderName?: string | null\n timestamp: number\n type: number\n content?: string | null\n}\n\nexport interface RestSessionExportData {\n members: RestExportMember[]\n messages: RestExportMessage[]\n}\n\nexport interface RestSessionProvider {\n countSessions(): Awaitable<number>\n listSessions(): Awaitable<RestSessionSummary[]>\n getSession(sessionId: string): Awaitable<RestSessionDetail | null>\n queryMessages(sessionId: string, query: RestMessageQuery): Awaitable<RestMessagePage | null>\n getMembers(sessionId: string): Awaitable<RestSessionMember[] | null>\n getOverview(sessionId: string): Awaitable<RestSessionOverview | null>\n executeReadonlySql(sessionId: string, sql: string): Awaitable<unknown | null>\n getExportData(sessionId: string, limit: number): Awaitable<RestSessionExportData | null>\n}\n\nfunction getSummary(dbManager: DatabaseManager, sessionId: string): RestSessionSummary | null {\n const db = dbManager.open(sessionId)\n if (!db) return null\n const info = getSessionInfo(db)\n if (!info) return null\n\n return {\n id: sessionId,\n name: info.name,\n platform: info.platform,\n type: info.type,\n groupId: info.groupId || undefined,\n messageCount: info.messageCount,\n memberCount: info.memberCount,\n firstTimestamp: info.firstMessageTs,\n lastTimestamp: info.lastMessageTs,\n importedAt: info.importedAt,\n }\n}\n\nfunction getDetail(dbManager: DatabaseManager, sessionId: string): RestSessionDetail | null {\n const summary = getSummary(dbManager, sessionId)\n if (!summary) return null\n const db = dbManager.open(sessionId)\n if (!db) return null\n\n return {\n ...summary,\n lastPlatformMessageId: getLastPlatformMessageId(db),\n importedAt: summary.importedAt ?? 0,\n }\n}\n\nexport function createDatabaseRestSessionProvider(dbManager: DatabaseManager): RestSessionProvider {\n return {\n countSessions: () => dbManager.listSessionIds().length,\n listSessions: () =>\n dbManager\n .listSessionIds()\n .map((sessionId) => getSummary(dbManager, sessionId))\n .filter((session): session is RestSessionSummary => session !== null),\n getSession: (sessionId) => getDetail(dbManager, sessionId),\n queryMessages: (sessionId, query) => {\n const db = dbManager.open(sessionId)\n if (!db) return null\n return queryMessages(db, {\n keyword: query.keyword,\n startTs: query.startTime,\n endTs: query.endTime,\n senderId: query.senderId,\n limit: query.limit,\n offset: query.offset,\n })\n },\n getMembers: (sessionId) => {\n const db = dbManager.open(sessionId)\n return db ? getMembersWithAliases(db).map(normalizeRestSessionMember) : null\n },\n getOverview: (sessionId) => {\n const db = dbManager.open(sessionId)\n if (!db) return null\n\n const overview = getSessionOverview(db)\n const memberActivity = getMemberActivity(db)\n const typeDistribution = getMessageTypeStats(db)\n const messageTypeDistribution: Record<string, number> = {}\n for (const item of typeDistribution) {\n messageTypeDistribution[String(item.type)] = item.count\n }\n\n return {\n messageCount: overview.totalMessages,\n memberCount: overview.totalMembers,\n timeRange: {\n start: overview.firstMessageTs ?? 0,\n end: overview.lastMessageTs ?? 0,\n },\n messageTypeDistribution,\n topMembers: memberActivity.slice(0, 10).map((member) => ({\n platformId: member.platformId,\n name: member.name,\n messageCount: member.messageCount,\n percentage: member.percentage,\n })),\n }\n },\n executeReadonlySql: (sessionId, sql) => {\n const db = dbManager.open(sessionId)\n return db ? executeReadonlySql(db, sql) : null\n },\n getExportData: (sessionId, limit) => {\n const db = dbManager.open(sessionId)\n if (!db) return null\n const session = getDetail(dbManager, sessionId)\n const meta = getSessionMeta(db)\n if (!session || !meta) return null\n\n const members = getMembersWithAliases(db)\n const messages = queryMessages(db, { limit, offset: 0 }).messages\n\n return {\n members,\n messages,\n }\n },\n }\n}\n","/**\n * ChatLab HTTP API — REST Session routes (/api/v1/sessions/*)\n *\n * Public REST API for external tools, scripts, and integrations.\n * Uses an injected provider so Electron can keep database work in its Worker.\n */\n\nimport type { FastifyInstance } from 'fastify'\nimport { CHATLAB_FORMAT_VERSION } from '@openchatlab/shared-types'\nimport {\n successResponse,\n errorResponse,\n sessionNotFound,\n exportTooLarge,\n sqlExecutionError,\n ApiError,\n} from '../../errors'\nimport type { RestSessionProvider } from './session-provider'\n\nconst EXPORT_MESSAGE_LIMIT = 100_000\n\nexport function registerRestSessionRoutes(server: FastifyInstance, provider: RestSessionProvider): void {\n server.get('/api/v1/sessions', async () => {\n return successResponse(await provider.listSessions())\n })\n\n server.get<{ Params: { id: string } }>('/api/v1/sessions/:id', async (request) => {\n const session = await provider.getSession(request.params.id)\n if (!session) throw sessionNotFound(request.params.id)\n return successResponse(session)\n })\n\n server.get<{\n Params: { id: string }\n Querystring: {\n page?: string\n limit?: string\n startTime?: string\n endTime?: string\n keyword?: string\n senderId?: string\n }\n }>('/api/v1/sessions/:id/messages', async (request) => {\n const { id } = request.params\n\n const page = Math.max(1, parseInt(request.query.page || '1', 10) || 1)\n const limit = Math.min(1000, Math.max(1, parseInt(request.query.limit || '100', 10) || 100))\n const offset = (page - 1) * limit\n\n const { startTime, endTime, keyword, senderId } = request.query\n\n const result = await provider.queryMessages(id, {\n keyword: keyword || undefined,\n startTime: startTime ? parseInt(startTime, 10) : undefined,\n endTime: endTime ? parseInt(endTime, 10) : undefined,\n senderId: senderId ? parseInt(senderId, 10) : undefined,\n limit,\n offset,\n })\n if (!result) throw sessionNotFound(id)\n\n return successResponse({\n messages: result.messages,\n total: result.total,\n page,\n limit,\n totalPages: result.totalPages ?? Math.ceil(result.total / limit),\n })\n })\n\n server.get<{ Params: { id: string } }>('/api/v1/sessions/:id/members', async (request) => {\n const members = await provider.getMembers(request.params.id)\n if (!members) throw sessionNotFound(request.params.id)\n return successResponse(members)\n })\n\n server.get<{ Params: { id: string } }>('/api/v1/sessions/:id/stats/overview', async (request) => {\n const overview = await provider.getOverview(request.params.id)\n if (!overview) throw sessionNotFound(request.params.id)\n return successResponse(overview)\n })\n\n server.post<{ Params: { id: string }; Body: { sql: string } }>('/api/v1/sessions/:id/sql', async (request, reply) => {\n const { id } = request.params\n\n const { sql } = request.body || {}\n if (!sql || typeof sql !== 'string') {\n const err = sqlExecutionError('Missing sql parameter')\n return reply.code(err.statusCode).send(errorResponse(err))\n }\n\n try {\n const result = await provider.executeReadonlySql(id, sql)\n if (result === null) {\n const err = sessionNotFound(id)\n return reply.code(err.statusCode).send(errorResponse(err))\n }\n return successResponse(result)\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'SQL execution error'\n if (message.includes('SELECT') || message.includes('只读') || message.includes('readonly')) {\n const apiErr = new ApiError('SQL_READONLY_VIOLATION' as ApiError['code'], message)\n apiErr.statusCode = 400\n return reply.code(400).send(errorResponse(apiErr))\n }\n const apiErr = sqlExecutionError(message)\n return reply.code(apiErr.statusCode).send(errorResponse(apiErr))\n }\n })\n\n server.get<{ Params: { id: string } }>('/api/v1/sessions/:id/export', async (request, reply) => {\n const { id } = request.params\n const session = await provider.getSession(id)\n if (!session) throw sessionNotFound(id)\n\n if (session.messageCount > EXPORT_MESSAGE_LIMIT) {\n const err = exportTooLarge(session.messageCount, EXPORT_MESSAGE_LIMIT)\n return reply.code(err.statusCode).send(errorResponse(err))\n }\n\n const exportData = await provider.getExportData(id, EXPORT_MESSAGE_LIMIT)\n if (!exportData) throw sessionNotFound(id)\n\n const chatLabFormat = {\n chatlab: {\n version: CHATLAB_FORMAT_VERSION,\n exportedAt: Math.floor(Date.now() / 1000),\n generator: 'ChatLab API',\n },\n meta: {\n name: session.name,\n platform: session.platform,\n type: session.type,\n groupId: session.groupId || undefined,\n },\n members: exportData.members.map((m) => ({\n platformId: m.platformId,\n accountName: m.accountName || m.platformId,\n groupNickname: m.groupNickname || undefined,\n aliases: Array.isArray(m.aliases) && m.aliases.length > 0 ? m.aliases : undefined,\n })),\n messages: exportData.messages.map((msg) => ({\n sender: msg.senderPlatformId,\n accountName: msg.senderName || undefined,\n timestamp: msg.timestamp,\n type: msg.type,\n content: msg.content || null,\n })),\n }\n\n return successResponse(chatLabFormat)\n })\n}\n","/**\n * ChatLab HTTP API — System routes\n *\n * GET /api/v1/status Service status\n * GET /api/v1/schema ChatLab Format JSON Schema\n */\n\nimport type { FastifyInstance } from 'fastify'\nimport { CHATLAB_FORMAT_VERSION } from '@openchatlab/shared-types'\nimport { successResponse } from '../../errors'\n\nexport interface SystemRouteContext {\n getVersion: () => string\n countSessions: () => number | Promise<number>\n}\n\nexport function registerSystemRoutes(server: FastifyInstance, ctx: SystemRouteContext): void {\n server.get('/api/v1/status', async () => {\n let sessionCount = 0\n try {\n sessionCount = await ctx.countSessions()\n } catch {\n // ignore\n }\n\n return successResponse({\n name: 'ChatLab API',\n version: ctx.getVersion(),\n uptime: Math.floor(process.uptime()),\n sessionCount,\n })\n })\n\n server.get('/api/v1/schema', async () => {\n return successResponse({\n format: 'ChatLab Format',\n version: CHATLAB_FORMAT_VERSION,\n spec: {\n chatlab: {\n type: 'object',\n required: ['version'],\n properties: {\n version: { type: 'string' },\n exportedAt: { type: 'number' },\n generator: { type: 'string' },\n },\n },\n meta: {\n type: 'object',\n required: ['name', 'platform', 'type'],\n properties: {\n name: { type: 'string' },\n platform: {\n type: 'string',\n enum: ['qq', 'wechat', 'telegram', 'discord', 'line', 'whatsapp', 'instagram', 'unknown'],\n },\n type: { type: 'string', enum: ['group', 'private'] },\n groupId: { type: 'string' },\n },\n },\n members: {\n type: 'array',\n items: {\n type: 'object',\n required: ['platformId', 'accountName'],\n properties: {\n platformId: { type: 'string' },\n accountName: { type: 'string' },\n groupNickname: { type: 'string' },\n avatar: { type: 'string' },\n },\n },\n },\n messages: {\n type: 'array',\n items: {\n type: 'object',\n required: ['sender', 'timestamp', 'type'],\n properties: {\n platformMessageId: { type: 'string' },\n sender: { type: 'string' },\n accountName: { type: 'string' },\n groupNickname: { type: 'string' },\n timestamp: { type: 'number' },\n type: { type: 'number' },\n content: { type: ['string', 'null'] },\n replyToMessageId: { type: 'string' },\n },\n },\n },\n },\n })\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { RestRouteContext } from '../../context/rest'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport { registerImportRoutes } from './imports'\nimport { createDatabaseRestSessionProvider } from './session-provider'\nimport { registerRestSessionRoutes } from './sessions'\nimport { registerSystemRoutes } from './system'\n\nexport type RestRoutesContext = Pick<RuntimeRouteContext, 'dbManager' | 'getVersion'> & RestRouteContext\n\n/** Register the public REST API under /api/v1. */\nexport function registerRestRoutes(server: FastifyInstance, ctx: RestRoutesContext): void {\n const sessionProvider = ctx.restSessionProvider ?? createDatabaseRestSessionProvider(ctx.dbManager)\n\n registerSystemRoutes(server, {\n getVersion: ctx.getVersion,\n countSessions: sessionProvider.countSessions,\n })\n registerRestSessionRoutes(server, sessionProvider)\n registerImportRoutes(server, ctx)\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { RuntimeRouteContext } from '../context/runtime'\nimport type { ServiceRouteContext } from '../context/services'\n\nexport type NodePluginContext = Pick<\n RuntimeRouteContext,\n 'sessionAdapter' | 'pathProvider' | 'runtimeIdentity' | 'nativeBinding'\n> &\n ServiceRouteContext\n\n/**\n * Static, trusted Node-side plugin facet.\n *\n * Route registration happens only during server startup. Fastify owns the\n * resulting route and service lifecycle until the server closes.\n */\nexport interface NodePluginDescriptor {\n readonly id: string\n registerHttpRoutes(server: FastifyInstance, context: NodePluginContext): void\n}\n\nexport function registerNodePlugins(\n server: FastifyInstance,\n context: NodePluginContext,\n plugins: readonly NodePluginDescriptor[]\n): void {\n for (const plugin of plugins) plugin.registerHttpRoutes(server, context)\n}\n","import type { FastifyInstance } from 'fastify'\nimport { randomUUID } from 'node:crypto'\nimport type { AgentStreamRequest, AiRouteContext } from '../../context/ai'\nimport { chatTopicWorkCoordinator } from '@openchatlab/node-runtime'\nimport type { MemoryProvenanceCoordinator } from './memory-provenance-coordinator'\n\nconst activeAgentAborts = new Map<string, AbortController>()\n\ntype AiAgentStreamRouteContext = Pick<AiRouteContext, 'runAgentStream' | 'aiChatManager'>\n\nexport function registerAiAgentStreamRoutes(\n server: FastifyInstance,\n ctx: AiAgentStreamRouteContext,\n memoryProvenanceCoordinator?: MemoryProvenanceCoordinator\n): void {\n if (!ctx.runAgentStream) return\n\n const runAgentStream = ctx.runAgentStream\n\n server.post<{ Body: AgentStreamRequest }>('/_web/ai/agent/stream', async (request, reply) => {\n const requestId = `req_${randomUUID()}`\n const abortController = new AbortController()\n activeAgentAborts.set(requestId, abortController)\n memoryProvenanceCoordinator?.begin(requestId, request.body.aiChatId)\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'X-Request-Id': requestId,\n })\n\n let emittedDone = false\n\n const safeSendSSE = (event: string, data: unknown) => {\n if (reply.raw.writableEnded || reply.raw.destroyed) return\n reply.raw.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`)\n }\n\n const safeEnd = () => {\n if (reply.raw.writableEnded || reply.raw.destroyed) return\n reply.raw.end()\n }\n\n safeSendSSE('meta', { requestId })\n const releaseInteractiveWork = chatTopicWorkCoordinator.beginInteractiveWork()\n\n reply.raw.on('close', () => {\n if (!abortController.signal.aborted) {\n abortController.abort()\n }\n activeAgentAborts.delete(requestId)\n })\n\n try {\n await runAgentStream(\n request.body,\n (chunk) => {\n if (chunk.type === 'done') emittedDone = true\n if (chunk.type === 'memory_change' && chunk.memoryId) {\n memoryProvenanceCoordinator?.record(requestId, chunk.memoryId)\n safeSendSSE(chunk.type, { ...chunk, provenanceToken: requestId })\n return\n }\n safeSendSSE(chunk.type, chunk)\n },\n abortController.signal\n )\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n safeSendSSE('error', { type: 'error', error: { name: 'ServerError', message: msg } })\n } finally {\n const expectedParentMessageId = ctx.aiChatManager?.getAIChat(request.body.aiChatId)?.activeMessageId ?? null\n memoryProvenanceCoordinator?.complete(requestId, expectedParentMessageId)\n releaseInteractiveWork()\n if (!emittedDone) safeSendSSE('done', { type: 'done', isFinished: true })\n activeAgentAborts.delete(requestId)\n safeEnd()\n }\n })\n\n server.post<{\n Body: { requestId: string }\n }>('/_web/ai/agent/abort', async (request) => {\n const { requestId } = request.body\n const controller = activeAgentAborts.get(requestId)\n if (controller) {\n controller.abort()\n activeAgentAborts.delete(requestId)\n return { success: true }\n }\n return { success: false }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { AssistantConfig } from '@openchatlab/node-runtime'\nimport { BUILTIN_TOOL_CATALOG } from '@openchatlab/core'\n\ntype AiAssistantRouteContext = Pick<AiRouteContext, 'assistantManager'>\n\nexport function registerAiAssistantRoutes(server: FastifyInstance, ctx: AiAssistantRouteContext): void {\n // Tool catalog is static data — always available regardless of AI context\n server.get('/_web/ai/tools/catalog', async () => {\n return BUILTIN_TOOL_CATALOG\n })\n\n const mgr = ctx.assistantManager\n if (!mgr) return\n\n server.get('/_web/ai/assistants', async () => {\n return mgr.getAllAssistants()\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/assistants/:id/upgrade-status', async (request) => {\n return mgr.getAssistantUpgradeInfo(request.params.id)\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/assistants/:id', async (request, reply) => {\n const config = mgr.getAssistantConfig(request.params.id)\n if (!config) return reply.code(404).send({ error: 'Not found' })\n return config\n })\n\n server.post<{\n Body: Omit<AssistantConfig, 'id'>\n }>('/_web/ai/assistants', async (request) => {\n return mgr.createAssistant(request.body)\n })\n\n server.put<{\n Params: { id: string }\n Body: Partial<AssistantConfig>\n }>('/_web/ai/assistants/:id', async (request, reply) => {\n const result = mgr.updateAssistant(request.params.id, request.body)\n if (!result.success) return reply.code(404).send(result)\n return result\n })\n\n server.delete<{ Params: { id: string } }>('/_web/ai/assistants/:id', async (request, reply) => {\n const result = mgr.deleteAssistant(request.params.id)\n if (!result.success) return reply.code(400).send(result)\n return result\n })\n\n server.post<{ Params: { id: string } }>('/_web/ai/assistants/:id/reset', async (request, reply) => {\n const result = mgr.resetAssistant(request.params.id)\n if (!result.success) return reply.code(400).send(result)\n return result\n })\n\n server.post<{\n Params: { id: string }\n Body: { backupName?: unknown }\n }>('/_web/ai/assistants/:id/upgrade', async (request, reply) => {\n if (typeof request.body?.backupName !== 'string') {\n return reply.code(400).send({ success: false, error: 'backupName must be a string' })\n }\n const result = mgr.upgradeAssistantWithBackup(request.params.id, request.body.backupName)\n if (!result.success) return reply.code(400).send(result)\n return result\n })\n\n server.post<{ Body: { rawMd: string } }>('/_web/ai/assistants/import', async (request) => {\n return mgr.importAssistantFromMd(request.body.rawMd)\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport { countMessagesTokens } from '@openchatlab/node-runtime'\nimport type { AIEntityRef, ContentBlock, TokenUsageData } from '@openchatlab/node-runtime'\n\ntype AiChatRouteContext = Pick<AiRouteContext, 'aiChatManager'>\n\nexport function registerAiChatRoutes(server: FastifyInstance, ctx: AiChatRouteContext): void {\n const cm = ctx.aiChatManager\n if (!cm) return\n\n // ==================== AI Chat CRUD ====================\n\n server.post<{\n Body: { sessionId: string; title?: string; assistantId: string }\n }>('/_web/ai/chats', async (request) => {\n const { sessionId, title, assistantId } = request.body\n return cm.createAIChat(sessionId, title, assistantId)\n })\n\n server.get<{\n Querystring: { sessionId: string }\n }>('/_web/ai/chats', async (request) => {\n const { sessionId } = request.query\n if (!sessionId) return []\n return cm.getAIChats(sessionId)\n })\n\n server.post<{\n Body: { title?: string; assistantId: string }\n }>('/_web/ai/global-chats', async (request) => {\n const { title, assistantId } = request.body\n return cm.createGlobalAIChat(title, assistantId)\n })\n\n server.get('/_web/ai/global-chats', async () => {\n return cm.getGlobalAIChats()\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/chats/:id', async (request, reply) => {\n const conv = cm.getAIChat(request.params.id)\n if (!conv) return reply.code(404).send({ error: 'AI chat not found' })\n return conv\n })\n\n server.put<{\n Params: { id: string }\n Body: { title: string }\n }>('/_web/ai/chats/:id/title', async (request) => {\n return cm.updateAIChatTitle(request.params.id, request.body.title)\n })\n\n server.delete<{ Params: { id: string } }>('/_web/ai/chats/:id', async (request) => {\n return cm.deleteAIChat(request.params.id)\n })\n\n // ==================== Message CRUD ====================\n\n server.post<{\n Params: { id: string }\n Body: {\n userMessage: { content: string; entityRefs?: AIEntityRef[] }\n assistantMessage: {\n content: string\n contentBlocks?: ContentBlock[]\n tokenUsage?: TokenUsageData\n }\n }\n }>('/_web/ai/chats/:id/message-pair', async (request) => {\n return cm.addMessagePair(request.params.id, request.body.userMessage, request.body.assistantMessage)\n })\n\n server.post<{\n Params: { id: string }\n Body: {\n userMessageId: string\n userContent: string\n assistantMessage: {\n content: string\n contentBlocks?: ContentBlock[]\n tokenUsage?: TokenUsageData\n }\n }\n }>('/_web/ai/chats/:id/replace-latest-message-round', async (request) => {\n return cm.replaceLatestMessageRound(request.params.id, request.body)\n })\n\n server.post<{\n Params: { id: string }\n Body: {\n role: 'user' | 'assistant' | 'summary'\n content: string\n dataKeywords?: string[]\n dataMessageCount?: number\n contentBlocks?: unknown[]\n tokenUsage?: {\n promptTokens: number\n completionTokens: number\n totalTokens: number\n cacheReadTokens?: number\n cacheWriteTokens?: number\n }\n entityRefs?: AIEntityRef[]\n }\n }>('/_web/ai/chats/:id/messages', async (request) => {\n const { role, content, dataKeywords, dataMessageCount, contentBlocks, tokenUsage, entityRefs } = request.body\n return cm.addMessage(\n request.params.id,\n role,\n content,\n dataKeywords,\n dataMessageCount,\n contentBlocks as any,\n tokenUsage,\n entityRefs\n )\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/chats/:id/messages', async (request) => {\n return cm.getMessages(request.params.id)\n })\n\n server.post<{\n Params: { id: string; messageId: string }\n }>('/_web/ai/chats/:id/messages/:messageId/delete-from', async (request, reply) => {\n const { id, messageId } = request.params\n if (!id || typeof id !== 'string' || !messageId || typeof messageId !== 'string') {\n return reply.code(400).send({ error: 'aiChatId and messageId are required' })\n }\n cm.deleteMessagesFrom(id, messageId)\n return { success: true }\n })\n\n server.post<{\n Params: { id: string }\n Body: { upToMessageId: string; title?: string }\n }>('/_web/ai/chats/:id/fork', async (request, reply) => {\n const { upToMessageId, title } = request.body\n if (!upToMessageId || typeof upToMessageId !== 'string') {\n return reply.code(400).send({ error: 'upToMessageId is required' })\n }\n return cm.forkAIChat(request.params.id, upToMessageId, title)\n })\n\n server.put<{\n Params: { messageId: string }\n Body: { content: string; entityRefs?: AIEntityRef[] }\n }>('/_web/ai/messages/:messageId/content', async (request, reply) => {\n const { content, entityRefs } = request.body\n if (!content || typeof content !== 'string') {\n return reply.code(400).send({ error: 'content is required' })\n }\n cm.updateMessageContent(request.params.messageId, content, entityRefs)\n return { success: true }\n })\n\n server.post<{\n Params: { id: string; messageId: string }\n }>('/_web/ai/chats/:id/messages/:messageId/delete-relink', async (request, reply) => {\n const { id, messageId } = request.params\n if (!id || !messageId) {\n return reply.code(400).send({ error: 'aiChatId and messageId are required' })\n }\n cm.deleteAndRelinkMessage(id, messageId)\n return { success: true }\n })\n\n server.post<{\n Params: { id: string }\n Body: {\n afterMessageId: string\n role: 'user' | 'assistant' | 'summary'\n content: string\n contentBlocks?: unknown[]\n tokenUsage?: {\n promptTokens: number\n completionTokens: number\n totalTokens: number\n cacheReadTokens?: number\n cacheWriteTokens?: number\n }\n entityRefs?: AIEntityRef[]\n }\n }>('/_web/ai/chats/:id/messages/insert-after', async (request, reply) => {\n const { afterMessageId, role, content, contentBlocks, tokenUsage, entityRefs } = request.body\n if (!afterMessageId || typeof afterMessageId !== 'string') {\n return reply.code(400).send({ error: 'afterMessageId is required' })\n }\n return cm.insertMessageAfter(\n request.params.id,\n afterMessageId,\n role,\n content,\n contentBlocks as any,\n tokenUsage,\n entityRefs\n )\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/chats/:id/token-usage', async (request) => {\n return cm.getAIChatTokenUsage(request.params.id)\n })\n\n // ==================== Debug ====================\n\n server.get('/_web/ai/debug/schema', async () => {\n return cm.getAiSchema()\n })\n\n server.post<{\n Body: { sql: string }\n }>('/_web/ai/debug/execute-sql', async (request, reply) => {\n const { sql } = request.body\n if (!sql || typeof sql !== 'string') {\n return reply.code(400).send({ error: 'sql is required' })\n }\n try {\n return cm.executeAiSQL(sql)\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e)\n return reply.code(400).send({ error: msg })\n }\n })\n\n server.post('/_web/ai/debug/clear-debug-context', async () => {\n const cleared = cm.clearAllDebugContext()\n return { success: true, cleared }\n })\n\n server.get<{\n Params: { id: string }\n }>('/_web/ai/chats/:id/estimate-tokens', async (request) => {\n const history = cm.getHistoryForAgent(request.params.id)\n const tokens = countMessagesTokens(history.map((m) => ({ role: m.role, content: m.content })))\n return { success: true, tokens, messageCount: history.length }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport {\n assertValidTopicDayKey,\n createChatTopicModelClient,\n createChatTopicService,\n type ChatTopicService,\n} from '@openchatlab/node-runtime'\nimport type { CreateChatTopicsRequest } from '@openchatlab/shared-types'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { RuntimeRouteContext } from '../../context/runtime'\n\ntype ChatTopicRouteContext = Pick<\n RuntimeRouteContext,\n 'sessionAdapter' | 'pathProvider' | 'runtimeIdentity' | 'nativeBinding'\n> &\n Pick<AiRouteContext, 'llmConfigStore'>\n\nexport function registerAiChatTopicRoutes(server: FastifyInstance, ctx: ChatTopicRouteContext): void {\n let service: ChatTopicService | null = null\n const getService = () => {\n if (!ctx.runtimeIdentity) throw new Error('Chat topic routes require a runtime identity')\n service ??= createChatTopicService({\n runtime: ctx.sessionAdapter,\n pathProvider: ctx.pathProvider,\n runtimeIdentity: ctx.runtimeIdentity,\n nativeBinding: ctx.nativeBinding,\n getModelClient() {\n const config = ctx.llmConfigStore?.getFastModelConfig()\n return config ? createChatTopicModelClient(config) : null\n },\n })\n return service\n }\n\n server.addHook('onClose', async () => {\n service?.close()\n })\n\n server.post<{ Params: { id: string }; Body: CreateChatTopicsRequest }>(\n '/_web/sessions/:id/topics/preflight',\n async (request) => getService().preflight(request.params.id, requireCreateRequest(request.body))\n )\n\n server.post<{ Params: { id: string }; Body: CreateChatTopicsRequest }>(\n '/_web/sessions/:id/topics/runs',\n async (request, reply) => {\n const run = getService().start(request.params.id, requireCreateRequest(request.body))\n return reply.code(run.status === 'completed' ? 200 : 202).send(run)\n }\n )\n\n server.post<{\n Params: { id: string; dayKey: string }\n Body: { timezone: string; locale?: string }\n }>('/_web/sessions/:id/topics/days/:dayKey/generate', async (request, reply) => {\n const run = getService().generateDay(\n request.params.id,\n request.params.dayKey,\n requireTimezone(request.body?.timezone),\n request.body?.locale\n )\n return reply.code(run.status === 'completed' ? 200 : 202).send(run)\n })\n\n server.get<{ Params: { id: string } }>('/_web/sessions/:id/topics/runs/latest', async (request) =>\n getService().getLatestRun(request.params.id)\n )\n\n server.get<{ Params: { id: string; runId: string } }>(\n '/_web/sessions/:id/topics/runs/:runId',\n async (request, reply) => {\n const run = getService().getRun(request.params.id, request.params.runId)\n return run ?? reply.code(404).send({ error: 'Chat topic run not found' })\n }\n )\n\n for (const action of ['pause', 'resume', 'cancel'] as const) {\n server.post<{ Params: { id: string; runId: string } }>(\n `/_web/sessions/:id/topics/runs/:runId/${action}`,\n async (request) => getService()[action](request.params.id, request.params.runId)\n )\n }\n\n server.get<{\n Params: { id: string; dayKey: string }\n Querystring: { timezone: string }\n }>('/_web/sessions/:id/topics/days/:dayKey', async (request) =>\n getService().getDay(request.params.id, request.params.dayKey, requireTimezone(request.query.timezone))\n )\n\n server.delete<{ Params: { id: string; dayKey: string } }>(\n '/_web/sessions/:id/topics/days/:dayKey',\n async (request) => ({ success: getService().deleteDay(request.params.id, request.params.dayKey) })\n )\n}\n\nfunction requireCreateRequest(value: CreateChatTopicsRequest | undefined): CreateChatTopicsRequest {\n if (!value || !['today', 'year', 'custom', 'all'].includes(value.rangeKind)) {\n throw Object.assign(new Error('Invalid chat topic range'), { statusCode: 400 })\n }\n const timezone = requireTimezone(value.timezone)\n if (value.rangeKind === 'custom') {\n if (typeof value.startDay !== 'string' || value.startDay.trim() === '') {\n throw Object.assign(new Error('A start day is required for a custom topic range'), { statusCode: 400 })\n }\n assertValidTopicDayKey(value.startDay)\n return { ...value, timezone, startDay: value.startDay }\n }\n return { rangeKind: value.rangeKind, timezone, locale: value.locale }\n}\n\nfunction requireTimezone(value: unknown): string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw Object.assign(new Error('Timezone is required'), { statusCode: 400 })\n }\n return value\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport { buildPiModel, runSimpleLlmStream } from '@openchatlab/node-runtime'\n\ntype AiLlmStreamRouteContext = Pick<AiRouteContext, 'llmConfigStore'>\n\nexport function registerAiLlmStreamRoutes(server: FastifyInstance, ctx: AiLlmStreamRouteContext): void {\n const store = ctx.llmConfigStore\n if (!store) return\n\n server.post<{\n Body: {\n messages: Array<{ role: string; content: string }>\n options?: { temperature?: number; maxTokens?: number }\n }\n }>('/_web/ai/llm/chat-stream', async (request, reply) => {\n const { messages, options } = request.body\n\n const llmConfig = store.getDefaultAssistantConfig()\n if (!llmConfig) {\n return reply.code(400).send({ success: false, error: 'LLM service not configured' })\n }\n\n const piModel = buildPiModel(llmConfig)\n const abortController = new AbortController()\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n reply.raw.on('close', () => {\n if (!abortController.signal.aborted) abortController.abort()\n })\n\n const sendChunk = (data: unknown) => {\n if (reply.raw.writableEnded || reply.raw.destroyed) return\n reply.raw.write(`event: chunk\\ndata: ${JSON.stringify(data)}\\n\\n`)\n }\n\n try {\n await runSimpleLlmStream({\n messages,\n apiKey: llmConfig.apiKey,\n piModel,\n temperature: options?.temperature,\n maxTokens: options?.maxTokens,\n onChunk: sendChunk,\n abortSignal: abortController.signal,\n })\n } catch (error) {\n if (abortController.signal.aborted) return\n const msg = error instanceof Error ? error.message : String(error)\n sendChunk({ content: '', isFinished: true, finishReason: 'error', error: msg })\n } finally {\n if (!reply.raw.writableEnded && !reply.raw.destroyed) reply.raw.end()\n }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport { BUILTIN_PROVIDERS, BUILTIN_MODELS, getBuiltinModelsByProvider } from '@openchatlab/core'\nimport {\n validateApiKey,\n fetchRemoteModels,\n getDefaultRulesForLocale,\n mergeRulesForLocale,\n} from '@openchatlab/node-runtime'\n\n// ==================== API key display masking ====================\n\nfunction hasRealApiKey(apiKey: string): boolean {\n return !!apiKey && apiKey !== 'sk-no-key-required'\n}\n\nfunction toConfigDisplay(config: Record<string, unknown>): Record<string, unknown> {\n const { apiKey: _raw, ...rest } = config\n return { ...rest, apiKey: '', apiKeySet: hasRealApiKey(String(_raw || '')) }\n}\n\n// ==================== Route registration ====================\n\ntype AiLlmRouteContext = Pick<\n AiRouteContext,\n 'llmConfigStore' | 'aiDataDir' | 'customProviderStore' | 'customModelStore'\n>\n\nexport function registerAiLlmRoutes(server: FastifyInstance, ctx: AiLlmRouteContext): void {\n const store = ctx.llmConfigStore\n const aiDataDir = ctx.aiDataDir\n if (!store || !aiDataDir) return\n\n // ---------- Config CRUD ----------\n\n server.get('/_web/ai/llm/has-config', async () => {\n return store.hasActiveConfig()\n })\n\n server.get('/_web/ai/llm/configs', async () => {\n const data = store.loadStore()\n return {\n configs: data.configs.map((c) => toConfigDisplay(c as unknown as Record<string, unknown>)),\n defaultAssistant: data.defaultAssistant,\n fastModel: data.fastModel,\n }\n })\n\n server.post<{\n Body: {\n name: string\n provider: string\n apiKey: string\n model?: string\n baseUrl?: string\n maxTokens?: number\n apiFormat?: string\n customModels?: Array<{ id: string; name: string }>\n }\n }>('/_web/ai/llm/configs', async (request) => {\n const result = store.addConfig(request.body)\n if (result.success && result.config) {\n return { ...result, config: toConfigDisplay(result.config as unknown as Record<string, unknown>) }\n }\n return result\n })\n\n server.put<{\n Params: { id: string }\n Body: {\n name?: string\n provider?: string\n apiKey?: string\n model?: string\n baseUrl?: string\n maxTokens?: number\n apiFormat?: string\n customModels?: Array<{ id: string; name: string }>\n }\n }>('/_web/ai/llm/configs/:id', async (request) => {\n return store.updateConfig(request.params.id, request.body)\n })\n\n server.delete<{ Params: { id: string } }>('/_web/ai/llm/configs/:id', async (request) => {\n return store.deleteConfig(request.params.id)\n })\n\n server.get('/_web/ai/llm/default-assistant-slot', async () => {\n return store.getDefaultAssistantSlot()\n })\n\n server.put<{\n Body: { configId: string; modelId: string }\n }>('/_web/ai/llm/default-assistant-slot', async (request) => {\n return store.setDefaultAssistantModel(request.body.configId, request.body.modelId)\n })\n\n server.get('/_web/ai/llm/fast-model-slot', async () => {\n return store.getFastModelSlot()\n })\n\n server.put<{\n Body: { configId: string; modelId: string } | null\n }>('/_web/ai/llm/fast-model-slot', async (request) => {\n return store.setFastModel(request.body)\n })\n\n // ---------- Provider Registry & Model Catalog ----------\n\n server.get('/_web/ai/llm/providers', async () => {\n return BUILTIN_PROVIDERS.map((p) => {\n const models = getBuiltinModelsByProvider(p.id)\n return {\n id: p.id,\n name: p.name,\n defaultBaseUrl: p.defaultBaseUrl,\n models: models\n .filter((m) => !m.capabilities.includes('embedding') && !m.capabilities.includes('ranking'))\n .map((m) => ({ id: m.id, name: m.name, description: m.description })),\n }\n })\n })\n\n server.get('/_web/ai/llm/provider-registry', async () => {\n const custom = ctx.customProviderStore?.getAll() ?? []\n return [...BUILTIN_PROVIDERS, ...custom]\n })\n\n server.get('/_web/ai/llm/model-catalog', async () => {\n const custom = ctx.customModelStore?.getAll() ?? []\n return [...BUILTIN_MODELS, ...custom]\n })\n\n // ---------- Custom Provider CRUD ----------\n\n server.post<{\n Body: {\n name: string\n kind: string\n defaultBaseUrl: string\n supportsCustomModels?: boolean\n modelIds?: string[]\n website?: string\n consoleUrl?: string\n }\n }>('/_web/ai/llm/custom-providers', async (request, reply) => {\n if (!ctx.customProviderStore)\n return reply.code(501).send({ success: false, error: 'Custom providers not available' })\n return ctx.customProviderStore.add(request.body)\n })\n\n server.put<{\n Params: { id: string }\n Body: Record<string, unknown>\n }>('/_web/ai/llm/custom-providers/:id', async (request, reply) => {\n if (!ctx.customProviderStore)\n return reply.code(501).send({ success: false, error: 'Custom providers not available' })\n const result = ctx.customProviderStore.update(request.params.id, request.body as any)\n if (!result.success) return reply.code(404).send(result)\n return result\n })\n\n server.delete<{ Params: { id: string } }>('/_web/ai/llm/custom-providers/:id', async (request, reply) => {\n if (!ctx.customProviderStore)\n return reply.code(501).send({ success: false, error: 'Custom providers not available' })\n const result = ctx.customProviderStore.delete(request.params.id)\n if (!result.success) return reply.code(404).send(result)\n return result\n })\n\n // ---------- Custom Model CRUD ----------\n\n server.post<{\n Body: {\n id: string\n providerId: string\n name: string\n description?: string\n contextWindow?: number\n capabilities?: string[]\n recommendedFor?: string[]\n status?: string\n }\n }>('/_web/ai/llm/custom-models', async (request, reply) => {\n if (!ctx.customModelStore) return reply.code(501).send({ success: false, error: 'Custom models not available' })\n const result = ctx.customModelStore.add(request.body)\n if (!result.success) return reply.code(409).send(result)\n return result\n })\n\n server.put<{\n Params: { providerId: string; modelId: string }\n Body: Record<string, unknown>\n }>('/_web/ai/llm/custom-models/:providerId/:modelId', async (request, reply) => {\n if (!ctx.customModelStore) return reply.code(501).send({ success: false, error: 'Custom models not available' })\n const result = ctx.customModelStore.update(request.params.providerId, request.params.modelId, request.body as any)\n if (!result.success) return reply.code(404).send(result)\n return result\n })\n\n server.delete<{\n Params: { providerId: string; modelId: string }\n }>('/_web/ai/llm/custom-models/:providerId/:modelId', async (request, reply) => {\n if (!ctx.customModelStore) return reply.code(501).send({ success: false, error: 'Custom models not available' })\n const result = ctx.customModelStore.delete(request.params.providerId, request.params.modelId)\n if (!result.success) return reply.code(404).send(result)\n return result\n })\n\n // ---------- Remote API ----------\n\n server.post<{\n Body: { provider: string; apiKey: string; baseUrl?: string; model?: string; apiFormat?: string; configId?: string }\n }>('/_web/ai/llm/validate-key', async (request) => {\n const { provider, apiKey, baseUrl, model, apiFormat, configId } = request.body\n const resolvedKey = apiKey?.trim() ? apiKey : configId ? store.getConfigById(configId)?.apiKey || '' : ''\n return validateApiKey(provider, resolvedKey, baseUrl, model, apiFormat)\n })\n\n server.post<{\n Body: { provider: string; apiKey: string; baseUrl?: string; apiFormat?: string; configId?: string }\n }>('/_web/ai/llm/remote-models', async (request) => {\n const { provider, apiKey, baseUrl, apiFormat, configId } = request.body\n const resolvedKey = apiKey?.trim() ? apiKey : configId ? store.getConfigById(configId)?.apiKey || '' : ''\n return fetchRemoteModels(provider, resolvedKey, baseUrl, apiFormat)\n })\n\n // ---------- Desensitize Rules ----------\n\n server.get<{\n Querystring: { locale?: string }\n }>('/_web/ai/desensitize-rules/defaults', async (request) => {\n return getDefaultRulesForLocale(request.query.locale ?? 'zh-CN')\n })\n\n server.post<{\n Body: { existingRules: unknown[]; locale: string; overrides?: Record<string, boolean> }\n }>('/_web/ai/desensitize-rules/merge', async (request) => {\n return mergeRulesForLocale(request.body.existingRules as any[], request.body.locale, request.body.overrides ?? {})\n })\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { StorageRouteContext } from '../../context/storage'\n\ntype AiLogRouteContext = Pick<RuntimeRouteContext, 'pathProvider'> &\n Pick<AiRouteContext, 'getCurrentAiLogPath'> &\n Pick<StorageRouteContext, 'showInFolder'>\n\nfunction findLatestAiLogPath(logsDir: string): string | null {\n const aiLogDir = path.join(logsDir, 'ai')\n if (!fs.existsSync(aiLogDir)) return null\n\n const latest = fs\n .readdirSync(aiLogDir)\n .filter((name) => name.startsWith('ai_') && name.endsWith('.log'))\n .map((name) => {\n const filePath = path.join(aiLogDir, name)\n const stat = fs.statSync(filePath)\n return { path: filePath, mtimeMs: stat.mtimeMs }\n })\n .sort((a, b) => b.mtimeMs - a.mtimeMs)[0]\n\n return latest?.path ?? null\n}\n\nfunction resolveAiLogPath(ctx: AiLogRouteContext): string | null {\n const currentPath = ctx.getCurrentAiLogPath?.()\n if (currentPath && fs.existsSync(currentPath)) return currentPath\n return findLatestAiLogPath(ctx.pathProvider.getLogsDir())\n}\n\nfunction isLoopbackAddress(address?: string): boolean {\n if (!address) return true\n const normalized = address.replace(/^::ffff:/, '')\n return (\n normalized === 'localhost' ||\n normalized === '::1' ||\n normalized === '0:0:0:0:0:0:0:1' ||\n normalized.startsWith('127.')\n )\n}\n\nexport function registerAiLogRoutes(server: FastifyInstance, ctx: AiLogRouteContext): void {\n server.post('/_web/ai/logs/show', async (request, reply) => {\n if (!ctx.showInFolder) return reply.code(501).send({ success: false, error: 'Not supported' })\n if (!isLoopbackAddress(request.ip)) {\n return { success: false, error: 'Opening AI logs is only supported on this device' }\n }\n\n const logPath = resolveAiLogPath(ctx)\n if (!logPath) return { success: false, error: 'No AI log files found' }\n\n try {\n await ctx.showInFolder(logPath)\n return { success: true, path: logPath }\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) }\n }\n })\n}\n","import type { FastifyInstance, FastifyReply } from 'fastify'\nimport type { AIMemoryScope, AIMemoryScopeType, LinkAIMemorySourcesInput } from '@openchatlab/shared-types'\nimport {\n linkAIMemorySources,\n listAIMemoriesWithSourceStatus,\n resolveAIMemorySourceStatus,\n} from '@openchatlab/node-runtime'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { MemoryProvenanceCoordinator } from './memory-provenance-coordinator'\n\ntype AiMemoryRouteContext = Pick<AiRouteContext, 'aiMemoryService' | 'aiChatManager'>\n\ninterface MemoryScopeInput {\n scopeType?: string\n scopeId?: string | null\n}\n\nfunction parseScope(input: MemoryScopeInput): AIMemoryScope {\n const scopeType = input.scopeType\n if (scopeType !== 'global' && scopeType !== 'self' && scopeType !== 'contact' && scopeType !== 'group') {\n throw new Error('scopeType must be global, self, contact, or group')\n }\n\n return {\n scopeType: scopeType as AIMemoryScopeType,\n scopeId: typeof input.scopeId === 'string' ? input.scopeId : null,\n }\n}\n\nfunction sendBadRequest(reply: FastifyReply, error: unknown) {\n return reply.code(400).send({ error: error instanceof Error ? error.message : String(error) })\n}\n\nexport function registerAiMemoryRoutes(\n server: FastifyInstance,\n ctx: AiMemoryRouteContext,\n memoryProvenanceCoordinator?: MemoryProvenanceCoordinator\n): void {\n const memoryService = ctx.aiMemoryService\n if (!memoryService) return\n const aiChatManager = ctx.aiChatManager\n const withSourceStatus = (entry: ReturnType<typeof memoryService.create>) => ({\n ...entry,\n sourceStatus: aiChatManager\n ? resolveAIMemorySourceStatus(entry, aiChatManager)\n : entry.sourceAIChatId\n ? ('unavailable' as const)\n : ('none' as const),\n })\n\n server.get<{\n Querystring: MemoryScopeInput\n }>('/_web/ai/memories', async (request, reply) => {\n try {\n const { scopeType, scopeId } = request.query\n if (!scopeType) {\n if (scopeId != null) throw new Error('scopeType is required when scopeId is provided')\n return aiChatManager\n ? listAIMemoriesWithSourceStatus(memoryService, aiChatManager)\n : memoryService.list().map((entry) => ({\n ...entry,\n sourceStatus: entry.sourceAIChatId ? ('unavailable' as const) : ('none' as const),\n }))\n }\n const scope = parseScope({ scopeType, scopeId })\n return aiChatManager\n ? listAIMemoriesWithSourceStatus(memoryService, aiChatManager, scope)\n : memoryService.list(scope).map((entry) => ({\n ...entry,\n sourceStatus: entry.sourceAIChatId ? ('unavailable' as const) : ('none' as const),\n }))\n } catch (error) {\n return sendBadRequest(reply, error)\n }\n })\n\n server.post<{\n Body: Partial<LinkAIMemorySourcesInput>\n }>('/_web/ai/memories/link-sources', async (request, reply) => {\n if (!aiChatManager) {\n return reply.code(503).send({ error: 'AI conversation storage is unavailable' })\n }\n try {\n const body = request.body ?? {}\n const input = {\n provenanceToken: body.provenanceToken ?? '',\n aiChatId: body.aiChatId ?? '',\n userMessageId: body.userMessageId ?? '',\n assistantMessageId: body.assistantMessageId ?? '',\n memoryIds: body.memoryIds ?? [],\n }\n if (!memoryProvenanceCoordinator) throw new Error('Memory provenance coordination is unavailable')\n const provenance = memoryProvenanceCoordinator.validate(input.provenanceToken, input.aiChatId, input.memoryIds)\n const result = linkAIMemorySources(memoryService, aiChatManager, input, provenance)\n memoryProvenanceCoordinator.consume(input.provenanceToken)\n return result\n } catch (error) {\n return sendBadRequest(reply, error)\n }\n })\n\n server.post<{\n Body: MemoryScopeInput & { content?: string; sourceType?: string }\n }>('/_web/ai/memories', async (request, reply) => {\n try {\n const scope = parseScope(request.body ?? {})\n return withSourceStatus(\n memoryService.create({\n ...scope,\n content: request.body?.content ?? '',\n sourceType: 'user',\n sourceAIChatId: null,\n sourceMessageId: null,\n })\n )\n } catch (error) {\n return sendBadRequest(reply, error)\n }\n })\n\n server.put<{\n Params: { id: string }\n Body: { content?: string; sourceType?: string }\n }>('/_web/ai/memories/:id', async (request, reply) => {\n if (!memoryService.get(request.params.id)) {\n return reply.code(404).send({ error: 'AI memory not found' })\n }\n try {\n return withSourceStatus(\n memoryService.update(request.params.id, {\n content: request.body?.content ?? '',\n sourceType: 'user',\n sourceAIChatId: null,\n sourceMessageId: null,\n })\n )\n } catch (error) {\n return sendBadRequest(reply, error)\n }\n })\n\n server.delete<{\n Params: { id: string }\n }>('/_web/ai/memories/:id', async (request, reply) => {\n if (!memoryService.forget(request.params.id)) {\n return reply.code(404).send({ error: 'AI memory not found' })\n }\n return { success: true }\n })\n\n server.post<{\n Body: MemoryScopeInput & { all?: boolean }\n }>('/_web/ai/memories/clear', async (request, reply) => {\n const { all, scopeType, scopeId } = request.body ?? {}\n if (all === true) {\n if (scopeType || scopeId != null) {\n return reply.code(400).send({ error: 'all cannot be combined with a scope' })\n }\n return { success: true, cleared: memoryService.clear() }\n }\n if (!scopeType) {\n return reply.code(400).send({ error: 'A scope or all: true is required' })\n }\n try {\n return { success: true, cleared: memoryService.clear(parseScope({ scopeType, scopeId })) }\n } catch (error) {\n return sendBadRequest(reply, error)\n }\n })\n}\n","/**\n * 语义索引共享 Web 路由(Electron Internal API 与 CLI Web 复用)\n *\n * 入参以 sessionId 暴露,不暴露 db_path_hash。service 缺失时整组路由优雅跳过。\n * AI pipeline 直接调用 SemanticIndexService,不经过这些 HTTP 路由。\n */\n\nimport path from 'node:path'\nimport type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { SemanticIndexConfig } from '@openchatlab/node-runtime'\nimport {\n SemanticIndexConfigStore,\n SEMANTIC_INDEX_CONFIG_FILE,\n isSemanticIndexConfigured,\n persistSemanticIndexConfig,\n resolveSemanticIndexApiKeySet,\n} from '@openchatlab/node-runtime'\n\ntype SemanticIndexRouteContext = Pick<\n AiRouteContext,\n 'semanticIndexService' | 'aiDataDir' | 'resolveApiKey' | 'writeAuthProfile'\n>\n\nexport function registerSemanticIndexRoutes(server: FastifyInstance, ctx: SemanticIndexRouteContext): void {\n const service = ctx.semanticIndexService\n\n // When the vector service is unavailable (e.g. sqlite-vec failed to load), register config\n // routes backed by the config-only store so the settings UI can still read/write configuration.\n if (!service) {\n if (ctx.aiDataDir) {\n const configStore = new SemanticIndexConfigStore(path.join(ctx.aiDataDir, SEMANTIC_INDEX_CONFIG_FILE))\n const configResponse = (config: SemanticIndexConfig) => ({\n config,\n apiKeySet: resolveSemanticIndexApiKeySet(config, ctx.resolveApiKey),\n configured: isSemanticIndexConfigured(config),\n })\n server.get('/_web/ai/semantic-index/config', async () => ({\n ...configResponse(configStore.get()),\n modelStatus: 'idle' as const,\n }))\n // 向量库不可用时仍允许写配置与 API Key(key 落 auth-profiles,不依赖向量库),\n // 否则 API 模式在降级期无法保存 key,恢复后会出现\"已配置但无法检索\"。\n server.put<{ Body: { config: SemanticIndexConfig; apiKey?: string } }>(\n '/_web/ai/semantic-index/config',\n async (request) => {\n const config = persistSemanticIndexConfig(configStore, request.body.config, {\n apiKey: request.body.apiKey,\n writeAuthProfile: ctx.writeAuthProfile,\n })\n return { ...configResponse(config), modelStatus: 'idle' as const }\n }\n )\n }\n server.get('/_web/ai/semantic-index/enabled', async () => ({ sessions: [] }))\n server.get('/_web/ai/semantic-index/status', async () => ({ status: null }))\n server.post('/_web/ai/semantic-index/status', async () => ({ sessions: [] }))\n return\n }\n\n server.get('/_web/ai/semantic-index/config', async () => {\n return {\n config: await service.getConfig(),\n apiKeySet: await service.hasApiKey(),\n configured: await service.isConfigured(),\n modelStatus: await service.getModelStatus(),\n }\n })\n\n server.put<{ Body: { config: SemanticIndexConfig; apiKey?: string } }>(\n '/_web/ai/semantic-index/config',\n async (request) => {\n const config = await service.setConfig(request.body.config, { apiKey: request.body.apiKey })\n return {\n config,\n apiKeySet: await service.hasApiKey(),\n configured: await service.isConfigured(),\n modelStatus: await service.getModelStatus(),\n }\n }\n )\n\n server.get('/_web/ai/semantic-index/enabled', async () => {\n return { sessions: await service.listEnabledStatuses() }\n })\n\n server.get<{ Querystring: { sessionId: string } }>('/_web/ai/semantic-index/status', async (request) => {\n return { status: await service.status(request.query.sessionId) }\n })\n\n server.post<{ Body: { sessionIds: string[] } }>('/_web/ai/semantic-index/status', async (request) => {\n return { sessions: await service.statusForSessions(request.body.sessionIds ?? []) }\n })\n\n const sessionAction = (path: string, action: (sessionId: string) => void | Promise<void>): void => {\n server.post<{ Body: { sessionId: string } }>(path, async (request, reply) => {\n const { sessionId } = request.body\n if (!sessionId) return reply.code(400).send({ error: 'sessionId is required' })\n await action(sessionId)\n return { status: await service.status(sessionId) }\n })\n }\n\n sessionAction('/_web/ai/semantic-index/enable', (id) => service.enable(id))\n sessionAction('/_web/ai/semantic-index/remove', (id) => service.remove(id))\n sessionAction('/_web/ai/semantic-index/build', (id) => service.build(id))\n sessionAction('/_web/ai/semantic-index/pause', (id) => service.pause(id))\n sessionAction('/_web/ai/semantic-index/cancel', (id) => service.cancel(id))\n sessionAction('/_web/ai/semantic-index/rebuild', (id) => service.rebuild(id))\n\n server.post('/_web/ai/semantic-index/build-pending', async () => {\n await service.buildAllPending()\n return { sessions: await service.listEnabledStatuses() }\n })\n\n server.post('/_web/ai/semantic-index/cleanup', async () => {\n return await service.cleanupUnused()\n })\n\n server.post<{ Body: { sessionId: string; query: string; finalTopK?: number } }>(\n '/_web/ai/semantic-index/search',\n async (request, reply) => {\n const { sessionId, query, finalTopK } = request.body\n if (!sessionId || !query) return reply.code(400).send({ error: 'sessionId and query are required' })\n return service.search(sessionId, query, { finalTopK })\n }\n )\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\n\ntype AiSkillRouteContext = Pick<AiRouteContext, 'skillManagerCore'>\n\nexport function registerAiSkillRoutes(server: FastifyInstance, ctx: AiSkillRouteContext): void {\n const mgr = ctx.skillManagerCore\n if (!mgr) return\n\n server.get('/_web/ai/skills', async () => {\n return mgr.getAllSkills()\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/skills/:id', async (request, reply) => {\n const config = mgr.getSkillConfig(request.params.id)\n if (!config) return reply.code(404).send({ error: 'Not found' })\n return config\n })\n\n server.post<{ Body: { rawMd: string } }>('/_web/ai/skills', async (request) => {\n return mgr.createSkill(request.body.rawMd)\n })\n\n server.put<{\n Params: { id: string }\n Body: { rawMd: string }\n }>('/_web/ai/skills/:id', async (request, reply) => {\n const result = mgr.updateSkill(request.params.id, request.body.rawMd)\n if (!result.success) return reply.code(404).send(result)\n return result\n })\n\n server.delete<{ Params: { id: string } }>('/_web/ai/skills/:id', async (request, reply) => {\n const result = mgr.deleteSkill(request.params.id)\n if (!result.success) return reply.code(400).send(result)\n return result\n })\n\n server.post<{ Body: { rawMd: string } }>('/_web/ai/skills/import', async (request) => {\n return mgr.importSkillFromMd(request.body.rawMd)\n })\n\n server.get('/_web/ai/skills/builtin-catalog', async () => {\n return mgr.getBuiltinCatalog()\n })\n\n server.post<{ Body: { builtinId: string } }>('/_web/ai/skills/import-builtin', async (request, reply) => {\n const result = mgr.importSkill(request.body.builtinId)\n if (!result.success) return reply.code(400).send(result)\n return result\n })\n\n server.post<{ Params: { id: string } }>('/_web/ai/skills/:id/reimport', async (request, reply) => {\n const result = mgr.reimportSkill(request.params.id)\n if (!result.success) return reply.code(400).send(result)\n return result\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport { summaryService, buildPiModel } from '@openchatlab/node-runtime'\nimport type { SummaryServiceDeps, LlmConfig, PiModelConfig } from '@openchatlab/node-runtime'\n\ntype AiSummaryRouteContext = Pick<RuntimeRouteContext, 'sessionAdapter'> & Pick<AiRouteContext, 'llmConfigStore'>\n\nfunction createSummaryDeps(ctx: AiSummaryRouteContext): SummaryServiceDeps | null {\n const store = ctx.llmConfigStore\n if (!store) return null\n return {\n getLlmConfig(): LlmConfig | null {\n const config = store.getDefaultAssistantConfig()\n if (!config) return null\n return config\n },\n buildPiModel(config: LlmConfig) {\n return buildPiModel(config as unknown as PiModelConfig)\n },\n }\n}\n\nexport function registerAiSummaryRoutes(server: FastifyInstance, ctx: AiSummaryRouteContext): void {\n const deps = createSummaryDeps(ctx)\n if (!deps) return\n\n const { sessionAdapter: adapter } = ctx\n\n server.post<{\n Params: { id: string }\n Body: { segmentId: number; locale?: string; forceRegenerate?: boolean; strategy?: 'brief' | 'standard' }\n }>('/_web/sessions/:id/summaries/generate', async (request, reply) => {\n const { segmentId, locale, forceRegenerate, strategy } = request.body\n const result = await summaryService.generateSummary(adapter, request.params.id, segmentId, deps, {\n locale,\n forceRegenerate,\n strategy,\n })\n if ('error' in result && !result.success) {\n return reply.code(400).send({ error: result.error })\n }\n return result\n })\n\n server.post<{\n Params: { id: string }\n Body: { locale?: string; forceRegenerate?: boolean }\n }>('/_web/sessions/:id/summaries/generate-all', async (request, reply) => {\n const { locale, forceRegenerate } = request.body\n const result = await summaryService.generateAllSummaries(adapter, request.params.id, deps, {\n locale,\n forceRegenerate,\n })\n if (result.error) {\n return reply.code(400).send({ error: result.error })\n }\n return result\n })\n\n server.post<{\n Params: { id: string }\n Body: { segmentIds: number[] }\n }>('/_web/sessions/:id/summaries/check-can-generate', async (request) => {\n const { segmentIds } = request.body\n return summaryService.checkCanGenerate(adapter, request.params.id, segmentIds)\n })\n}\n","/**\n * 平台无关的 AI 工具执行核心\n *\n * 从注册表查找工具、在注入的上下文上执行,并统一处理取消、超大结果截断与错误映射。\n * 不依赖 Electron / Worker,便于单测验证上下文注入(尤其是 semanticIndexService)。\n */\n\nimport { stripAvatarFields } from '@openchatlab/core'\nimport { AGENT_TOOL_REGISTRY } from '@openchatlab/tools'\nimport type { ToolDataProvider, ToolExecutionContext, SemanticSearchToolService } from '@openchatlab/tools'\nimport type { AiToolExecuteRequest, AiToolExecuteResult } from '../context/ai'\n\nconst MAX_RESULT_CHARS = 500_000\n\n/** 工具执行依赖:由平台注入。注入 semanticIndexService 后,手动执行也能命中语义检索工具。 */\nexport interface AiToolExecutionDeps {\n db?: ToolExecutionContext['db']\n dataProvider?: ToolDataProvider\n semanticIndexService?: SemanticSearchToolService\n segmentText?: ToolExecutionContext['segmentText']\n translateTemplate?: ToolExecutionContext['translateTemplate']\n}\n\n/** 在注入的上下文上执行注册表工具,处理取消、超大结果截断与错误映射。 */\nexport async function executeRegistryTool(\n params: AiToolExecuteRequest,\n deps: AiToolExecutionDeps\n): Promise<AiToolExecuteResult> {\n const { toolName, params: toolParams, abortSignal } = params\n const entry = AGENT_TOOL_REGISTRY.find((tool) => tool.name === toolName)\n if (!entry) {\n return { success: false, error: `Tool not found: ${toolName}` }\n }\n\n try {\n if (abortSignal.aborted) return { success: false, error: 'cancelled' }\n const execCtx: ToolExecutionContext = {\n sessionId: params.sessionId,\n abortSignal,\n db: deps.db,\n dataProvider: deps.dataProvider,\n semanticIndexService: deps.semanticIndexService,\n segmentText: deps.segmentText,\n translateTemplate: deps.translateTemplate,\n }\n\n const startTime = Date.now()\n const result = await entry.handler(toolParams, execCtx)\n const elapsed = Date.now() - startTime\n if (abortSignal.aborted) return { success: false, error: 'cancelled' }\n\n let details = (result.data as Record<string, unknown> | undefined) ?? undefined\n let truncated = false\n\n if (details) {\n stripAvatarFields(details)\n const raw = JSON.stringify(details)\n if (raw.length > MAX_RESULT_CHARS) {\n truncated = true\n details = { _truncated: true, _originalSize: raw.length, _preview: raw.slice(0, MAX_RESULT_CHARS) }\n }\n }\n\n return {\n success: true,\n elapsed,\n content: [{ type: 'text', text: result.content }],\n details,\n truncated,\n }\n } catch (error) {\n if (abortSignal.aborted) {\n return { success: false, error: 'cancelled' }\n }\n return { success: false, error: error instanceof Error ? error.message : String(error) }\n }\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport { appLogger } from '@openchatlab/node-runtime'\nimport { AGENT_TOOL_REGISTRY, CoreDataProvider } from '@openchatlab/tools'\nimport { executeRegistryTool } from '../../ai/tool-executor'\n\nconst activeToolTests = new Map<string, AbortController>()\n\ninterface AiToolRouteContext extends Pick<AiRouteContext, 'executeAiTool'> {\n dbManager: Pick<DatabaseManager, 'open'>\n}\n\nexport function registerAiToolRoutes(server: FastifyInstance, ctx: AiToolRouteContext): void {\n server.get('/_web/ai/tools/full-catalog', async () => {\n return AGENT_TOOL_REGISTRY.map((tool) => ({\n name: tool.name,\n category: tool.category ?? 'core',\n description: tool.description,\n parameters: tool.inputSchema ?? {},\n }))\n })\n\n server.post<{\n Body: {\n testId: string\n toolName: string\n params: Record<string, unknown>\n sessionId: string\n }\n }>('/_web/ai/tools/execute', async (request, reply) => {\n const { testId, toolName, params, sessionId } = request.body\n\n const entry = AGENT_TOOL_REGISTRY.find((t) => t.name === toolName)\n if (!entry) {\n return reply.code(404).send({ success: false, error: `Tool not found: ${toolName}` })\n }\n\n const abortController = new AbortController()\n activeToolTests.set(testId, abortController)\n\n try {\n if (ctx.executeAiTool) {\n return await ctx.executeAiTool({ testId, toolName, params, sessionId, abortSignal: abortController.signal })\n }\n\n const db = ctx.dbManager.open(sessionId)\n if (!db) {\n return reply.code(404).send({ success: false, error: `Session not found: ${sessionId}` })\n }\n\n const result = await executeRegistryTool(\n { testId, toolName, params, sessionId, abortSignal: abortController.signal },\n {\n db,\n dataProvider: new CoreDataProvider(db),\n }\n )\n if (!result.success && result.error !== 'cancelled') {\n appLogger.error('ai-tools', `Failed to execute tool ${toolName}`, { error: result.error })\n }\n return result\n } catch (error) {\n if (abortController.signal.aborted) {\n return { success: false, error: 'cancelled' }\n }\n appLogger.error('ai-tools', `Failed to execute tool ${toolName}`, error)\n return { success: false, error: String(error) }\n } finally {\n activeToolTests.delete(testId)\n }\n })\n\n server.post<{ Body: { testId: string } }>('/_web/ai/tools/cancel', async (request) => {\n const { testId } = request.body\n const controller = activeToolTests.get(testId)\n if (controller) {\n controller.abort()\n activeToolTests.delete(testId)\n return { success: true }\n }\n return { success: false }\n })\n}\n","interface PendingMemoryProvenance {\n aiChatId: string\n expectedParentMessageId: string | null\n memoryIds: Set<string>\n completed: boolean\n}\n\nexport class MemoryProvenanceCoordinator {\n private readonly pending = new Map<string, PendingMemoryProvenance>()\n\n begin(token: string, aiChatId: string): void {\n this.pending.set(token, {\n aiChatId,\n expectedParentMessageId: null,\n memoryIds: new Set(),\n completed: false,\n })\n }\n\n record(token: string, memoryId: string): void {\n const changeSet = this.pending.get(token)\n if (!changeSet || changeSet.completed) return\n changeSet.memoryIds.add(memoryId)\n }\n\n complete(token: string, expectedParentMessageId: string | null): void {\n const changeSet = this.pending.get(token)\n if (!changeSet) return\n if (changeSet.memoryIds.size === 0) {\n this.pending.delete(token)\n return\n }\n changeSet.expectedParentMessageId = expectedParentMessageId\n changeSet.completed = true\n }\n\n validate(token: string, aiChatId: string, memoryIds: string[]): { expectedParentMessageId: string | null } {\n const changeSet = this.pending.get(token)\n if (!changeSet || !changeSet.completed || changeSet.aiChatId !== aiChatId) {\n throw new Error('Memory provenance token is invalid')\n }\n\n const requestedIds = new Set(memoryIds)\n if (\n requestedIds.size !== changeSet.memoryIds.size ||\n [...requestedIds].some((memoryId) => !changeSet.memoryIds.has(memoryId))\n ) {\n throw new Error('Memory IDs do not match the agent turn change set')\n }\n return { expectedParentMessageId: changeSet.expectedParentMessageId }\n }\n\n consume(token: string): void {\n this.pending.delete(token)\n }\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { StorageRouteContext } from '../../context/storage'\nimport { registerAiAgentStreamRoutes } from './ai-agent-stream'\nimport { registerAiAssistantRoutes } from './ai-assistants'\nimport { registerAiChatRoutes } from './ai-chats'\nimport { registerAiChatTopicRoutes } from './ai-chat-topics'\nimport { registerAiLlmStreamRoutes } from './ai-llm-stream'\nimport { registerAiLlmRoutes } from './ai-llm'\nimport { registerAiLogRoutes } from './ai-logs'\nimport { registerAiMemoryRoutes } from './ai-memories'\nimport { registerSemanticIndexRoutes } from './ai-semantic-index'\nimport { registerAiSkillRoutes } from './ai-skills'\nimport { registerAiSummaryRoutes } from './ai-summaries'\nimport { registerAiToolRoutes } from './ai-tools'\nimport { MemoryProvenanceCoordinator } from './memory-provenance-coordinator'\n\nexport type AiRoutesContext = AiRouteContext &\n Pick<RuntimeRouteContext, 'dbManager' | 'sessionAdapter' | 'pathProvider' | 'runtimeIdentity' | 'nativeBinding'> &\n Pick<StorageRouteContext, 'showInFolder'>\n\nexport interface AiRouteOptions {\n /** When true, core AI routes throw on missing dependencies instead of silently skipping. */\n requireAi?: boolean\n}\n\nconst REQUIRED_AI_DEPENDENCIES = [\n 'aiDataDir',\n 'aiChatManager',\n 'aiMemoryService',\n 'assistantManager',\n 'skillManagerCore',\n 'llmConfigStore',\n 'customProviderStore',\n 'customModelStore',\n 'runAgentStream',\n] as const satisfies ReadonlyArray<keyof AiRouteContext>\n\nfunction assertRequiredAiContext(ctx: AiRouteContext): void {\n const missing = REQUIRED_AI_DEPENDENCIES.filter((key) => !ctx[key])\n if (missing.length > 0) {\n throw new Error(`[http-routes] requireAi is set but missing AI dependencies: ${missing.join(', ')}`)\n }\n}\n\n/** Register all AI-related Web routes while preserving optional-feature behavior. */\nexport function registerAiRoutes(server: FastifyInstance, ctx: AiRoutesContext, options?: AiRouteOptions): void {\n if (options?.requireAi) assertRequiredAiContext(ctx)\n const memoryProvenanceCoordinator = new MemoryProvenanceCoordinator()\n\n registerAiAssistantRoutes(server, ctx)\n registerAiSkillRoutes(server, ctx)\n registerAiLlmRoutes(server, ctx)\n registerAiLlmStreamRoutes(server, ctx)\n registerAiAgentStreamRoutes(server, ctx, memoryProvenanceCoordinator)\n registerAiToolRoutes(server, ctx)\n registerAiChatRoutes(server, ctx)\n registerAiMemoryRoutes(server, ctx, memoryProvenanceCoordinator)\n registerAiChatTopicRoutes(server, ctx)\n registerAiSummaryRoutes(server, ctx)\n registerAiLogRoutes(server, ctx)\n registerSemanticIndexRoutes(server, ctx)\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { PathProvider } from '@openchatlab/core'\nimport type { SessionRuntimeAdapter } from '@openchatlab/node-runtime'\nimport { createJiebaNlpProvider } from '@openchatlab/node-runtime'\nimport {\n getTimeRange,\n getAvailableYears,\n getMemberActivity,\n getHourlyActivity,\n getDailyActivity,\n getWeekdayActivity,\n getMessageTypeStats,\n getMonthlyActivity,\n getYearlyActivity,\n getMessageLengthDistribution,\n getTextStats,\n getLongMessageCount,\n getMemberMonthlyTrend,\n getTextLengthPercentiles,\n getRelationshipStats,\n getJourneyStats,\n getCatchphraseAnalysis,\n getMentionAnalysis,\n getGroupRelationshipGalaxy,\n GROUP_RELATIONSHIP_GALAXY_ALGORITHM_VERSION,\n getLaughAnalysis,\n getClusterGraph,\n getLanguagePreferenceAnalysis,\n getDragonKingAnalysis,\n getDivingAnalysis,\n getCheckInAnalysis,\n getMemeBattleAnalysis,\n getNightOwlAnalysis,\n getRepeatAnalysis,\n} from '@openchatlab/core'\nimport type { ClusterGraphOptions } from '@openchatlab/core'\nimport { parseTimeFilter } from './time-filter'\nimport { withAnalyticsCache, type AnalyticsCacheContext } from './analytics-cache'\n\ntype FilteredQuery = { startTs?: string; endTs?: string; memberId?: string }\ntype KeywordAnalysisBody = { keywords?: string[] }\n\ntype AnalyticsRouteContext = AnalyticsCacheContext & {\n pathProvider: Pick<PathProvider, 'getCacheDir' | 'getSystemDir'>\n sessionAdapter: Pick<SessionRuntimeAdapter, 'getDbPath' | 'ensureReadonly'>\n}\n\nexport function registerAnalyticsRoutes(server: FastifyInstance, ctx: AnalyticsRouteContext): void {\n const { sessionAdapter: adapter } = ctx\n\n /** Cache-first wrapper bound to this context; `params` must capture all inputs that affect the result. */\n const cached = <T>(\n name: string,\n sessionId: string,\n params: Record<string, unknown>,\n compute: () => T,\n options?: { dailyInvalidate?: boolean; extraVersion?: string }\n ): T => withAnalyticsCache(ctx, sessionId, `analytics.${name}`, params, compute, options)\n\n server.get<{ Params: { id: string } }>('/_web/sessions/:id/years', async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getAvailableYears(db)\n })\n\n server.get<{ Params: { id: string } }>('/_web/sessions/:id/time-range', async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getTimeRange(db)\n })\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/member-activity',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('member-activity', id, { ...filter }, () => getMemberActivity(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/hourly',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('hourly', id, { ...filter }, () => getHourlyActivity(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/daily',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('daily', id, { ...filter }, () => getDailyActivity(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/weekday',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('weekday', id, { ...filter }, () => getWeekdayActivity(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/message-types',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('message-types', id, { ...filter }, () => getMessageTypeStats(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/relationship',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('relationship', id, { ...filter }, () => getRelationshipStats(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/journey',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('journey', id, { ...filter }, () => getJourneyStats(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/catchphrase',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('catchphrase', id, { ...filter }, () => getCatchphraseAnalysis(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/mention',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('mention', id, { ...filter }, () => getMentionAnalysis(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/relationship-galaxy',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached(\n 'relationship-galaxy',\n id,\n { ...filter },\n () => getGroupRelationshipGalaxy(adapter.ensureReadonly(id), filter),\n { extraVersion: GROUP_RELATIONSHIP_GALAXY_ALGORITHM_VERSION }\n )\n }\n )\n\n server.post<{ Params: { id: string }; Querystring: FilteredQuery; Body: KeywordAnalysisBody }>(\n '/_web/sessions/:id/analytics/laugh',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n const keywords = Array.isArray(request.body?.keywords) ? request.body.keywords : []\n // Keywords are edited interactively, so this endpoint intentionally bypasses the persistent analytics cache.\n return getLaughAnalysis(adapter.ensureReadonly(id), filter, keywords)\n }\n )\n\n server.get<{\n Params: { id: string }\n Querystring: FilteredQuery & { topEdges?: string; lookAhead?: string; decaySeconds?: string }\n }>('/_web/sessions/:id/analytics/cluster', async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n // 仅收集显式传入的参数,避免 undefined 覆盖核心算法默认值\n const options: ClusterGraphOptions = {}\n if (request.query.topEdges) options.topEdges = parseInt(request.query.topEdges, 10)\n if (request.query.lookAhead) options.lookAhead = parseInt(request.query.lookAhead, 10)\n if (request.query.decaySeconds) options.decaySeconds = parseInt(request.query.decaySeconds, 10)\n const hasOptions = Object.keys(options).length > 0\n return cached('cluster', id, { ...filter, ...options }, () =>\n getClusterGraph(adapter.ensureReadonly(id), filter, hasOptions ? options : undefined)\n )\n })\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery & { locale?: string } }>(\n '/_web/sessions/:id/analytics/language-preference',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n const locale = request.query.locale || 'zh-CN'\n const zhDictPath = path.join(ctx.pathProvider.getSystemDir(), 'nlp', 'zh-CN.dict')\n let zhDictVersion: string\n try {\n const st = fs.statSync(zhDictPath)\n zhDictVersion = `${Math.floor(st.mtimeMs)}:${st.size}`\n } catch {\n zhDictVersion = '-'\n }\n return cached(\n 'language-preference',\n id,\n { ...filter, locale },\n () =>\n getLanguagePreferenceAnalysis(adapter.ensureReadonly(id), {\n locale,\n timeFilter: filter,\n nlpProvider: createJiebaNlpProvider(),\n }),\n { extraVersion: `dict:${zhDictVersion}` }\n )\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/monthly-activity',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('monthly-activity', id, { ...filter }, () => getMonthlyActivity(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/yearly-activity',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('yearly-activity', id, { ...filter }, () => getYearlyActivity(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/message-length-distribution',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('message-length-distribution', id, { ...filter }, () =>\n getMessageLengthDistribution(adapter.ensureReadonly(id), filter)\n )\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/text-stats',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('text-stats', id, { ...filter }, () => getTextStats(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery & { minLength?: string } }>(\n '/_web/sessions/:id/analytics/long-message-count',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n const minLength = request.query.minLength ? parseInt(request.query.minLength, 10) : undefined\n return cached('long-message-count', id, { ...filter, minLength }, () =>\n getLongMessageCount(adapter.ensureReadonly(id), filter, minLength)\n )\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/member-monthly-trend',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('member-monthly-trend', id, { ...filter }, () =>\n getMemberMonthlyTrend(adapter.ensureReadonly(id), filter)\n )\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/text-length-percentiles',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('text-length-percentiles', id, { ...filter }, () =>\n getTextLengthPercentiles(adapter.ensureReadonly(id), filter)\n )\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/dragon-king',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('dragon-king', id, { ...filter }, () => getDragonKingAnalysis(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/diving',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('diving', id, { ...filter }, () => getDivingAnalysis(adapter.ensureReadonly(id), filter), {\n dailyInvalidate: true,\n })\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/check-in',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('check-in', id, { ...filter }, () => getCheckInAnalysis(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/meme-battle',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('meme-battle', id, { ...filter }, () => getMemeBattleAnalysis(adapter.ensureReadonly(id), filter))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/night-owl',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('night-owl', id, { ...filter }, () => getNightOwlAnalysis(adapter.ensureReadonly(id), filter), {\n dailyInvalidate: true,\n })\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/repeat',\n async (request) => {\n const id = request.params.id\n const filter = parseTimeFilter(request.query)\n return cached('repeat', id, { ...filter }, () => getRepeatAnalysis(adapter.ensureReadonly(id), filter), {\n extraVersion: 'originator-id-v1',\n })\n }\n )\n}\n","/**\n * Time-filter query parsing for Web analytics routes.\n */\n\nimport type { TimeFilter } from '@openchatlab/shared-types'\n\nexport function parseTimeFilter(query: Record<string, string | undefined>): TimeFilter | undefined {\n const { startTs, endTs, memberId } = query\n if (!startTs && !endTs && !memberId) return undefined\n const filter: TimeFilter = {}\n if (startTs) filter.startTs = parseInt(startTs, 10)\n if (endTs) filter.endTs = parseInt(endTs, 10)\n if (memberId) filter.memberId = parseInt(memberId, 10)\n return filter\n}\n","/**\n * Shared analytics result caching for HTTP route handlers.\n *\n * Wraps expensive analytics / NLP computations with the platform-agnostic\n * analytics cache (cacheDir/query/{sessionId}.cache.json). Used by both CLI Web\n * (`clb web`) and the Electron internal server so the two share one cache\n * implementation. Validity is keyed to the product version plus the session DB\n * file fingerprint, so any release that changes query logic, and any import /\n * incremental import / member edit, transparently invalidates entries.\n */\n\nimport * as path from 'path'\nimport { getDbFileVersion, getOrComputeAnalysisCache } from '@openchatlab/node-runtime'\nimport type { PathProvider } from '@openchatlab/core'\nimport type { SessionRuntimeAdapter } from '@openchatlab/node-runtime'\n\nexport interface AnalyticsCacheContext {\n pathProvider: Pick<PathProvider, 'getCacheDir'>\n sessionAdapter: Pick<SessionRuntimeAdapter, 'getDbPath'>\n getVersion: () => string\n}\n\n/** Deterministic stringify: sorts object keys recursively and drops `undefined`. */\nfunction canonical(value: unknown): string {\n if (value === undefined) return 'null'\n if (value === null || typeof value !== 'object') return JSON.stringify(value)\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`\n const obj = value as Record<string, unknown>\n const keys = Object.keys(obj)\n .filter((k) => obj[k] !== undefined)\n .sort()\n return `{${keys.map((k) => `${JSON.stringify(k)}:${canonical(obj[k])}`).join(',')}}`\n}\n\n/**\n * Build a stable cache key from a namespace (endpoint id) and its params.\n * Key order does not matter and `undefined` params are ignored, so equivalent\n * requests map to the same key.\n */\nexport function buildAnalyticsCacheKey(namespace: string, params: Record<string, unknown>): string {\n return `${namespace}:${canonical(params)}`\n}\n\n/**\n * Cache-first wrapper for an analytics computation bound to a session.\n * Returns the cached result when the DB file is unchanged; otherwise computes,\n * persists (tagged with the current DB fingerprint) and returns it.\n *\n * Pass `options.dailyInvalidate: true` for endpoints whose results depend on\n * the current date (e.g. daysSinceLastMessage, currentStreak). This appends\n * today's date to the version string so the cache is refreshed each day even\n * when the DB file has not changed.\n *\n * Pass `options.extraVersion` to append an arbitrary fingerprint to the version\n * (e.g. an external file's mtime/size) so the cache is invalidated whenever\n * that resource changes independently of the DB or app version.\n */\nexport function withAnalyticsCache<T>(\n ctx: AnalyticsCacheContext,\n sessionId: string,\n namespace: string,\n params: Record<string, unknown>,\n compute: () => T,\n options?: { dailyInvalidate?: boolean; extraVersion?: string }\n): T {\n const queryCacheDir = path.join(ctx.pathProvider.getCacheDir(), 'query')\n const dateStr = options?.dailyInvalidate ? `|date:${new Date().toISOString().split('T')[0]}` : ''\n const extraStr = options?.extraVersion ? `|${options.extraVersion}` : ''\n const version = `${ctx.getVersion()}|${getDbFileVersion(ctx.sessionAdapter.getDbPath(sessionId))}${dateStr}${extraStr}`\n const key = buildAnalyticsCacheKey(namespace, params)\n return getOrComputeAnalysisCache(sessionId, key, queryCacheDir, version, compute)\n}\n","import * as fs from 'fs'\nimport * as fsp from 'fs/promises'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { StorageRouteContext } from '../../context/storage'\n\nasync function getDirSize(dirPath: string): Promise<number> {\n let totalSize = 0\n try {\n if (!fs.existsSync(dirPath)) return 0\n const files = await fsp.readdir(dirPath, { withFileTypes: true })\n for (const file of files) {\n const filePath = path.join(dirPath, file.name)\n if (file.isDirectory()) {\n totalSize += await getDirSize(filePath)\n } else {\n const stat = await fsp.stat(filePath)\n totalSize += stat.size\n }\n }\n } catch {\n /* directory inaccessible */\n }\n return totalSize\n}\n\nasync function getFileCount(dirPath: string): Promise<number> {\n let count = 0\n try {\n if (!fs.existsSync(dirPath)) return 0\n const files = await fsp.readdir(dirPath, { withFileTypes: true })\n for (const file of files) {\n const filePath = path.join(dirPath, file.name)\n if (file.isDirectory()) {\n count += await getFileCount(filePath)\n } else {\n count++\n }\n }\n } catch {\n /* directory inaccessible */\n }\n return count\n}\n\nfunction hasChatLabDatabases(dirPath: string): boolean {\n try {\n const markerPath = path.join(dirPath, '.chatlab')\n const dbDir = path.join(dirPath, 'databases')\n if (!fs.existsSync(markerPath) || !fs.existsSync(dbDir)) return false\n return fs.readdirSync(dbDir).some((file) => file.endsWith('.db'))\n } catch {\n return false\n }\n}\n\ntype CacheRouteContext = Pick<RuntimeRouteContext, 'pathProvider'> & StorageRouteContext\n\nexport function registerCacheRoutes(server: FastifyInstance, ctx: CacheRouteContext): void {\n const pp = ctx.pathProvider\n const downloadsDir = ctx.downloadsDir ?? pp.getDownloadsDir()\n\n server.get('/_web/cache/info', async () => {\n const directories = [\n {\n id: 'databases',\n name: 'settings.storage.cache.databases.name',\n description: 'settings.storage.cache.databases.description',\n path: pp.getDatabaseDir(),\n scope: 'user-data',\n rootPath: pp.getUserDataDir(),\n icon: 'i-heroicons-circle-stack',\n canClear: false,\n },\n {\n id: 'ai',\n name: 'settings.storage.cache.ai.name',\n description: 'settings.storage.cache.ai.description',\n path: pp.getAiDataDir(),\n scope: 'system-data',\n rootPath: pp.getSystemDir(),\n icon: 'i-heroicons-sparkles',\n canClear: false,\n },\n {\n id: 'cache',\n name: 'settings.storage.cache.statsCache.name',\n description: 'settings.storage.cache.statsCache.description',\n path: pp.getCacheDir(),\n scope: 'system-data',\n rootPath: pp.getSystemDir(),\n icon: 'i-heroicons-bolt',\n canClear: true,\n },\n {\n id: 'logs',\n name: 'settings.storage.cache.logs.name',\n description: 'settings.storage.cache.logs.description',\n path: pp.getLogsDir(),\n scope: 'system-data',\n rootPath: pp.getSystemDir(),\n icon: 'i-heroicons-document-text',\n canClear: true,\n },\n ]\n\n const results = await Promise.all(\n directories.map(async (dir) => {\n const [size, fileCount] = await Promise.all([getDirSize(dir.path), getFileCount(dir.path)])\n return { ...dir, size, fileCount, exists: fs.existsSync(dir.path) }\n })\n )\n\n return {\n baseDir: pp.getSystemDir(),\n directories: results,\n totalSize: results.reduce((sum, d) => sum + d.size, 0),\n }\n })\n\n server.post<{ Body: { cacheId: string } }>('/_web/cache/clear', async (request) => {\n const { cacheId } = request.body\n const allowedDirs: Record<string, string> = {\n cache: pp.getCacheDir(),\n logs: pp.getLogsDir(),\n }\n const dirPath = allowedDirs[cacheId]\n if (!dirPath) return { success: false, error: 'Not allowed to clear this directory' }\n\n if (!fs.existsSync(dirPath)) return { success: true }\n\n const files = await fsp.readdir(dirPath)\n for (const file of files) {\n const filePath = path.join(dirPath, file)\n const stat = await fsp.stat(filePath)\n if (stat.isDirectory()) {\n await fsp.rm(filePath, { recursive: true })\n } else {\n await fsp.unlink(filePath)\n }\n }\n return { success: true }\n })\n\n server.get('/_web/cache/data-dir', async () => {\n const pending = ctx.getPendingDataDirMigration?.()\n const pendingCleanups = await Promise.all(\n (ctx.getPendingDataDirCleanups?.() ?? []).map(async (cleanup) => ({\n ...cleanup,\n exists: fs.existsSync(cleanup.sourceDir),\n size: await getDirSize(cleanup.sourceDir),\n }))\n )\n return {\n path: pp.getUserDataDir(),\n defaultPath: ctx.defaultUserDataDir,\n isCustom: ctx.isCustomDataDir ?? false,\n canSetDataDir: ctx.canSetDataDir ?? Boolean(ctx.setDataDir),\n managedScope: 'chat-databases',\n managedDescription: 'settings.storage.dataLocation.managedDescription',\n hasLegacyDataAtDefaultDir:\n Boolean(ctx.defaultUserDataDir) &&\n path.resolve(pp.getUserDataDir()) !== path.resolve(ctx.defaultUserDataDir ?? '') &&\n hasChatLabDatabases(ctx.defaultUserDataDir ?? ''),\n pendingCleanups,\n pendingMigration: pending\n ? {\n from: pending.from,\n to: pending.to,\n createdAt: pending.createdAt,\n }\n : undefined,\n }\n })\n\n server.post<{ Body: { path?: string | null; migrate?: boolean } }>('/_web/cache/data-dir', async (request, reply) => {\n if (!ctx.setDataDir) {\n return reply.code(501).send({ success: false, error: 'Data directory changes are not supported' })\n }\n\n const targetPath = typeof request.body?.path === 'string' ? request.body.path : null\n const migrate = request.body?.migrate !== false\n return ctx.setDataDir(targetPath, migrate)\n })\n\n server.post<{ Body: { cleanupId?: string } }>('/_web/cache/data-dir/cleanup/open', async (request, reply) => {\n if (!ctx.openDirectory || !ctx.getPendingDataDirCleanups) {\n return reply.code(501).send({ success: false, error: 'Opening old data directories is not supported' })\n }\n\n const cleanup = ctx.getPendingDataDirCleanups().find((entry) => entry.id === request.body?.cleanupId)\n if (!cleanup) return reply.code(404).send({ success: false, error: 'Pending cleanup not found' })\n\n await ctx.openDirectory(cleanup.sourceDir)\n return { success: true }\n })\n\n server.post<{ Body: { cleanupId?: string } }>('/_web/cache/data-dir/cleanup/dismiss', async (request, reply) => {\n if (!ctx.dismissPendingDataDirCleanupNotice) {\n return reply.code(501).send({ success: false, error: 'Cleanup notices are not supported' })\n }\n\n const cleanupId = request.body?.cleanupId\n if (!cleanupId || !ctx.dismissPendingDataDirCleanupNotice(cleanupId)) {\n return reply.code(404).send({ success: false, error: 'Pending cleanup not found' })\n }\n return { success: true }\n })\n\n server.post<{ Body: { cleanupId?: string } }>('/_web/cache/data-dir/cleanup/delete', async (request, reply) => {\n if (!ctx.deletePendingDataDirCleanup) {\n return reply.code(501).send({ success: false, error: 'Manual data directory cleanup is not supported' })\n }\n\n const cleanupId = request.body?.cleanupId\n if (!cleanupId) return reply.code(400).send({ success: false, error: 'cleanupId is required' })\n\n const result = ctx.deletePendingDataDirCleanup(cleanupId)\n if (!result.success) return reply.code(400).send(result)\n return result\n })\n\n server.get('/_web/cache/latest-import-log', async () => {\n const importLogDir = path.join(pp.getLogsDir(), 'import')\n if (!fs.existsSync(importLogDir)) {\n return { success: false, error: 'Log directory not found' }\n }\n\n const files = await fsp.readdir(importLogDir)\n const logFiles = files.filter((f) => f.startsWith('import_') && f.endsWith('.log'))\n if (logFiles.length === 0) {\n return { success: false, error: 'No import logs found' }\n }\n\n const fileStats = await Promise.all(\n logFiles.map(async (f) => {\n const filePath = path.join(importLogDir, f)\n const stat = await fsp.stat(filePath)\n return { name: f, path: filePath, mtime: stat.mtime.getTime() }\n })\n )\n fileStats.sort((a, b) => b.mtime - a.mtime)\n\n return { success: true, path: fileStats[0].path, name: fileStats[0].name }\n })\n\n server.post<{ Body: { filename: string; dataUrl: string } }>('/_web/cache/save-to-downloads', async (request) => {\n const { filename, dataUrl } = request.body\n if (!filename || !dataUrl) {\n return { success: false, error: 'filename and dataUrl are required' }\n }\n\n let buffer: Buffer\n if (dataUrl.includes(';base64,')) {\n const base64Data = dataUrl.split(';base64,')[1]\n buffer = Buffer.from(base64Data, 'base64')\n } else if (dataUrl.includes('charset=utf-8,')) {\n const textData = dataUrl.split('charset=utf-8,')[1]\n buffer = Buffer.from(decodeURIComponent(textData), 'utf-8')\n } else {\n const base64Data = dataUrl.replace(/^data:[^,]+,/, '')\n buffer = Buffer.from(base64Data, 'base64')\n }\n\n if (!fs.existsSync(downloadsDir)) {\n fs.mkdirSync(downloadsDir, { recursive: true })\n }\n\n const filePath = path.join(downloadsDir, filename)\n fs.writeFileSync(filePath, buffer)\n\n return { success: true, filePath }\n })\n\n // Shell operations — require platform-specific callbacks\n\n server.post<{ Body: { cacheId: string } }>('/_web/cache/open-dir', async (request, reply) => {\n if (!ctx.openDirectory) return reply.code(501).send({ success: false, error: 'Not supported' })\n\n const { cacheId } = request.body\n const dirPaths: Record<string, string> = {\n base: pp.getSystemDir(),\n userData: pp.getUserDataDir(),\n databases: pp.getDatabaseDir(),\n cache: pp.getCacheDir(),\n ai: pp.getAiDataDir(),\n logs: pp.getLogsDir(),\n downloads: downloadsDir,\n }\n const dirPath = dirPaths[cacheId]\n if (!dirPath) return { success: false, error: 'Unknown directory' }\n\n if (!fs.existsSync(dirPath)) {\n await fsp.mkdir(dirPath, { recursive: true })\n }\n\n try {\n await ctx.openDirectory(dirPath)\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) }\n }\n return { success: true }\n })\n\n server.post<{ Body: { filePath: string } }>('/_web/cache/show-in-folder', async (request, reply) => {\n if (!ctx.showInFolder) return reply.code(501).send({ success: false, error: 'Not supported' })\n\n const { filePath } = request.body\n if (!filePath) return { success: false, error: 'filePath is required' }\n\n try {\n await ctx.showInFolder(filePath)\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) }\n }\n return { success: true }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport { createContactsService } from '@openchatlab/node-runtime'\nimport { CONTACTS_TIME_RANGE_PRESETS, type ContactPool, type ContactsTimeRangePreset } from '@openchatlab/shared-types'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { ServiceRouteContext } from '../../context/services'\n\ntype ContactsQuery = {\n acceptStale?: string\n timeRange?: string\n pool?: string\n page?: string\n pageSize?: string\n q?: string\n}\n\ntype ContactsRouteContext = Pick<\n RuntimeRouteContext,\n 'sessionAdapter' | 'pathProvider' | 'runtimeIdentity' | 'nativeBinding'\n> &\n Pick<ServiceRouteContext, 'contactsService'>\n\nexport function registerContactsRoutes(server: FastifyInstance, ctx: ContactsRouteContext): void {\n const service =\n ctx.contactsService ??\n createContactsService({\n adapter: ctx.sessionAdapter,\n pathProvider: ctx.pathProvider,\n runtimeIdentity: ctx.runtimeIdentity,\n nativeBinding: ctx.nativeBinding,\n })\n server.addHook('onClose', async () => {\n await service.close()\n })\n\n server.get<{ Querystring: ContactsQuery }>('/_web/contacts', async (request) => {\n return service.getContactsPage({\n acceptStale: isTruthy(request.query.acceptStale),\n timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),\n pool: parseContactPool(request.query.pool),\n page: parsePositiveInteger(request.query.page),\n pageSize: parsePositiveInteger(request.query.pageSize),\n query: request.query.q,\n })\n })\n\n server.post<{ Querystring: ContactsQuery }>('/_web/contacts/recompute', async (request) => {\n return service.startRecompute({\n timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),\n pool: parseContactPool(request.query.pool),\n page: parsePositiveInteger(request.query.page),\n pageSize: parsePositiveInteger(request.query.pageSize),\n query: request.query.q,\n })\n })\n\n server.get<{ Params: { key: string }; Querystring: ContactsQuery }>('/_web/contacts/:key/detail', async (request) => {\n return service.getContactDetail(request.params.key, {\n acceptStale: isTruthy(request.query.acceptStale),\n timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),\n })\n })\n\n server.put<{ Params: { key: string }; Querystring: ContactsQuery }>(\n '/_web/contacts/:key/mark-friend',\n async (request) => {\n return service.markContactAsFriend(request.params.key, {\n timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),\n })\n }\n )\n\n server.delete<{ Params: { key: string }; Querystring: ContactsQuery }>(\n '/_web/contacts/:key/mark-friend',\n async (request) => {\n return service.unmarkContactAsFriend(request.params.key, {\n timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),\n })\n }\n )\n}\n\nfunction isTruthy(value: string | undefined): boolean {\n return value === '1' || value === 'true' || value === 'yes'\n}\n\nfunction parseContactsTimeRangePreset(value: string | undefined): ContactsTimeRangePreset {\n return CONTACTS_TIME_RANGE_PRESETS.includes(value as ContactsTimeRangePreset)\n ? (value as ContactsTimeRangePreset)\n : '1y'\n}\n\nfunction parseContactPool(value: string | undefined): ContactPool | undefined {\n return value === 'friend' || value === 'non_friend' ? value : undefined\n}\n\nfunction parsePositiveInteger(value: string | undefined): number | undefined {\n if (!value) return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed)) return undefined\n return Math.max(1, Math.trunc(parsed))\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport { exportService } from '@openchatlab/node-runtime'\nimport type { ExportFormat } from '@openchatlab/node-runtime'\n\ntype ExportRouteContext = Pick<RuntimeRouteContext, 'sessionAdapter'>\n\nexport function registerExportRoutes(server: FastifyInstance, ctx: ExportRouteContext): void {\n const { sessionAdapter: adapter } = ctx\n\n server.post<{\n Params: { id: string }\n Body: {\n sessionName: string\n format?: ExportFormat\n timeFilter?: { startTs: number; endTs: number }\n }\n }>('/_web/sessions/:id/export', async (request, reply) => {\n const { id } = request.params\n const body = request.body as any\n const sessionName = body?.sessionName || id\n const format: ExportFormat = body?.format || 'txt'\n\n const result = exportService.exportFormatted(adapter, {\n sessionId: id,\n sessionName,\n format,\n timeFilter: body.timeFilter,\n })\n\n if (!result.success) {\n return reply.code(result.totalMessages === 0 ? 404 : 500).send({ error: result.error })\n }\n\n reply.header('Content-Type', result.mimeType)\n reply.header('Content-Disposition', `attachment; filename=\"${encodeURIComponent(result.filename)}\"`)\n return reply.send(result.content)\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport { appLogger } from '@openchatlab/node-runtime'\n\ninterface LogReportBody {\n level?: 'error' | 'warn'\n message: string\n stack?: string\n url?: string\n}\n\n/**\n * Front-end error report sink. The browser can't write files, so uncaught\n * front-end errors are POSTed here and appended to logs/app.log (scope 'web').\n */\nexport function registerLogRoutes(server: FastifyInstance): void {\n server.post<{ Body: LogReportBody }>('/_web/logs/report', async (req, reply) => {\n const { level, message, stack, url } = req.body ?? ({} as LogReportBody)\n if (!message) return reply.code(400).send({ error: 'message required' })\n\n const detail = [url ? `url=${url}` : null, stack ? `\\n${stack}` : null].filter(Boolean).join(' ')\n if (level === 'warn') appLogger.warn('web', message, detail || undefined)\n else appLogger.error('web', message, detail || undefined)\n return { ok: true }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport { appLogger, memberService } from '@openchatlab/node-runtime'\nimport { apiErrorFromUnknown } from '../../errors'\n\ntype MemberRouteContext = Pick<RuntimeRouteContext, 'sessionAdapter' | 'pathProvider'>\n\nexport function registerMemberRoutes(server: FastifyInstance, ctx: MemberRouteContext): void {\n const { sessionAdapter: adapter } = ctx\n const cacheDir = ctx.pathProvider.getCacheDir()\n\n server.get<{ Params: { id: string } }>('/_web/sessions/:id/members', async (request) => {\n return memberService.getMembers(adapter, request.params.id)\n })\n\n server.get<{\n Params: { id: string }\n Querystring: { page?: string; pageSize?: string; search?: string; sortOrder?: string }\n }>('/_web/sessions/:id/members/paginated', async (request) => {\n return memberService.getMembersPaginated(adapter, request.params.id, {\n page: parseInt(request.query.page || '1', 10),\n pageSize: parseInt(request.query.pageSize || '20', 10),\n search: request.query.search,\n sortOrder: request.query.sortOrder === 'asc' ? 'asc' : 'desc',\n })\n })\n\n server.patch<{ Params: { id: string; memberId: string }; Body: { aliases: string[] } }>(\n '/_web/sessions/:id/members/:memberId/aliases',\n async (request) => {\n const memberId = parseInt(request.params.memberId, 10)\n memberService.updateMemberAliases(adapter, request.params.id, memberId, request.body.aliases)\n return { success: true }\n }\n )\n\n server.delete<{ Params: { id: string; memberId: string } }>(\n '/_web/sessions/:id/members/:memberId',\n async (request) => {\n const memberId = parseInt(request.params.memberId, 10)\n memberService.deleteMember(adapter, request.params.id, memberId, cacheDir)\n return { success: true }\n }\n )\n\n server.post<{ Params: { id: string }; Body: { memberIds?: unknown } }>(\n '/_web/sessions/:id/members/batch-delete',\n async (request, reply) => {\n const memberIds = request.body?.memberIds\n if (\n !Array.isArray(memberIds) ||\n memberIds.length === 0 ||\n memberIds.some((memberId) => !Number.isSafeInteger(memberId) || Number(memberId) <= 0)\n ) {\n return reply.code(400).send({\n success: false,\n error: 'memberIds must contain at least one positive integer',\n })\n }\n\n const uniqueMemberIds = Array.from(new Set(memberIds as number[]))\n try {\n const success = memberService.deleteMembers(adapter, request.params.id, uniqueMemberIds, cacheDir)\n if (!success) {\n throw new Error('Member deletion transaction returned no result')\n }\n } catch (error) {\n if (apiErrorFromUnknown(error) || isHttpClientError(error)) throw error\n appLogger.error('members', 'Batch member deletion failed', error)\n return reply.code(500).send({ success: false, error: 'Failed to delete selected members' })\n }\n\n appLogger.info('members', 'Batch member deletion completed', {\n sessionId: request.params.id,\n memberCount: uniqueMemberIds.length,\n })\n return { success: true, deletedCount: uniqueMemberIds.length }\n }\n )\n\n server.post<{ Params: { id: string }; Body: { memberId1: number; memberId2: number } }>(\n '/_web/sessions/:id/members/merge',\n async (request) => {\n const { memberId1, memberId2 } = request.body\n memberService.mergeMembers(adapter, request.params.id, memberId1, memberId2, cacheDir)\n return { success: true }\n }\n )\n\n server.get<{ Params: { id: string; memberId: string } }>(\n '/_web/sessions/:id/members/:memberId/history',\n async (request) => {\n const memberId = parseInt(request.params.memberId, 10)\n return memberService.getMemberNameHistory(adapter, request.params.id, memberId)\n }\n )\n}\n\nfunction isHttpClientError(error: unknown): error is Error & { statusCode: number } {\n return (\n error instanceof Error &&\n 'statusCode' in error &&\n typeof error.statusCode === 'number' &&\n error.statusCode >= 400 &&\n error.statusCode < 500\n )\n}\n","import type { FastifyInstance } from 'fastify'\nimport { createNavigationLayoutService, NavigationLayoutValidationError } from '@openchatlab/node-runtime'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { ServiceRouteContext } from '../../context/services'\n\ntype NavigationLayoutRouteContext = Pick<RuntimeRouteContext, 'pathProvider'> &\n Pick<ServiceRouteContext, 'navigationLayoutService'>\n\nexport function registerNavigationLayoutRoutes(server: FastifyInstance, context: NavigationLayoutRouteContext): void {\n const service = context.navigationLayoutService ?? createNavigationLayoutService(context.pathProvider.getSystemDir())\n\n server.get('/_web/navigation-layout', async () => service.load())\n\n server.put<{ Body: unknown }>('/_web/navigation-layout', async (request, reply) => {\n try {\n const layout = service.save(request.body)\n return { status: 'saved' as const, layout }\n } catch (error) {\n if (error instanceof NavigationLayoutValidationError) {\n return reply.code(400).send({ error: 'INVALID_NAVIGATION_LAYOUT' })\n }\n throw error\n }\n })\n\n server.delete('/_web/navigation-layout', async () => {\n service.reset()\n return { status: 'missing' as const, layout: null }\n })\n}\n","/**\n * Merge routes — shared across CLI, Electron, and CLI Web.\n *\n * Parse supports dual-mode:\n * - multipart/form-data → file upload (web/CLI)\n * - application/json { filePath } → local disk path (Electron)\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { MergeRouteContext } from '../../context/merge'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport {\n streamParseFileInfo,\n checkConflictsFromSources,\n buildMergedOutput,\n serializeChatLabToJsonl,\n exportSessionToJson,\n TempDbReader,\n TempDbWriter,\n createChatLabTempDir,\n} from '@openchatlab/node-runtime'\nimport type { MergerDataSource } from '@openchatlab/node-runtime'\nimport { sessionNotFound } from '../../errors'\n\ntype MergeRoutesContext = Pick<RuntimeRouteContext, 'dbManager'> & MergeRouteContext\n\nfunction ensureDb(ctx: MergeRoutesContext, sessionId: string) {\n const db = ctx.dbManager.open(sessionId)\n if (!db) throw sessionNotFound(sessionId)\n return db\n}\n\nexport function registerMergeRoutes(server: FastifyInstance, ctx: MergeRoutesContext): void {\n const { dbManager, mergeSessionCache: mergeCache, streamImport } = ctx\n if (!mergeCache) return\n\n // ── parse (dual-mode) ──────────────────────────────────────────────\n\n server.post('/_web/merge/parse', async (request, reply) => {\n const contentType = request.headers['content-type'] || ''\n let filePath: string\n let cleanupFile = false\n let cleanupDir: string | undefined\n\n if (contentType.includes('multipart/form-data')) {\n const data = await (request as any).file()\n if (!data) return reply.code(400).send({ error: 'No file uploaded' })\n\n const tmpDir = createChatLabTempDir('merge', 'upload-')\n const tmpPath = path.join(tmpDir, data.filename || 'upload')\n const chunks: Buffer[] = []\n for await (const chunk of data.file) {\n chunks.push(chunk)\n }\n fs.writeFileSync(tmpPath, Buffer.concat(chunks))\n filePath = tmpPath\n cleanupFile = true\n cleanupDir = tmpDir\n } else {\n const body = request.body as { filePath?: string }\n if (!body?.filePath) return reply.code(400).send({ error: 'Missing filePath in body' })\n if (!fs.existsSync(body.filePath)) return reply.code(400).send({ error: 'File not found' })\n filePath = body.filePath\n }\n\n try {\n const result = await streamParseFileInfo(filePath, {\n createTempDatabase(sourceFilePath: string) {\n return mergeCache.createTempDatabase(path.basename(sourceFilePath))\n },\n onProgress() {\n /* HTTP parse has no progress stream */\n },\n })\n\n const filename = path.basename(filePath)\n const handle = mergeCache.store(filename, result.tempDbPath)\n\n return {\n handle,\n name: result.name,\n format: result.format,\n platform: result.platform,\n messageCount: result.messageCount,\n memberCount: result.memberCount,\n fileSize: result.fileSize,\n }\n } finally {\n if (cleanupFile) {\n try {\n fs.unlinkSync(filePath)\n } catch {\n /* ignore */\n }\n }\n if (cleanupDir) {\n try {\n fs.rmdirSync(cleanupDir)\n } catch {\n /* ignore */\n }\n }\n }\n })\n\n // ── conflicts ──────────────────────────────────────────────────────\n\n server.post<{ Body: { handles: string[] } }>('/_web/merge/conflicts', async (request, reply) => {\n const { handles } = request.body as { handles?: string[] }\n if (!handles || !Array.isArray(handles) || handles.length === 0) {\n return reply.code(400).send({ error: 'Missing or empty handles array' })\n }\n\n const readers: TempDbReader[] = []\n try {\n const dataSources: Array<{ source: MergerDataSource; filename: string }> = []\n for (const handle of handles) {\n const entry = mergeCache.openReader(handle)\n if (!entry) return reply.code(404).send({ error: `Handle not found: ${handle}` })\n readers.push(entry.reader)\n dataSources.push({ source: entry.reader.toDataSource(), filename: entry.filename })\n }\n return checkConflictsFromSources(dataSources)\n } finally {\n for (const r of readers) r.close()\n }\n })\n\n // ── execute ────────────────────────────────────────────────────────\n\n server.post<{\n Body: {\n handles: string[]\n outputName: string\n format?: 'json' | 'jsonl'\n andImport?: boolean\n sessionGapThreshold?: number\n }\n }>('/_web/merge/execute', async (request, reply) => {\n const { handles, outputName, format = 'json', andImport, sessionGapThreshold } = request.body\n if (!handles || !Array.isArray(handles) || handles.length === 0) {\n return reply.code(400).send({ error: 'Missing handles' })\n }\n if (!outputName) {\n return reply.code(400).send({ error: 'Missing outputName' })\n }\n\n const readers: TempDbReader[] = []\n try {\n const dataSources: Array<{ source: MergerDataSource; filename: string }> = []\n for (const handle of handles) {\n const entry = mergeCache.openReader(handle)\n if (!entry) return reply.code(404).send({ error: `Handle not found: ${handle}` })\n readers.push(entry.reader)\n dataSources.push({ source: entry.reader.toDataSource(), filename: entry.filename })\n }\n\n const merged = buildMergedOutput(dataSources, outputName)\n\n let sessionId: string | undefined\n if (andImport) {\n if (!streamImport) {\n return reply.code(501).send({ error: 'Import not available on this server' })\n }\n const jsonData = JSON.stringify(merged.chatLabData)\n const tmpDir = createChatLabTempDir('merge', 'import-')\n const safeName = path.basename(outputName).replace(/[/\\\\?%*:|\"<>]/g, '_') || 'merged'\n const tmpPath = path.join(tmpDir, `${safeName}.json`)\n fs.writeFileSync(tmpPath, jsonData, 'utf-8')\n\n try {\n const importResult = await streamImport(dbManager, tmpPath, { sessionGapThreshold })\n sessionId = importResult.sessionId\n } finally {\n try {\n fs.unlinkSync(tmpPath)\n } catch {\n /* ignore */\n }\n try {\n fs.rmdirSync(tmpDir)\n } catch {\n /* ignore */\n }\n }\n }\n\n for (const handle of handles) {\n mergeCache.delete(handle)\n }\n\n if (format === 'jsonl') {\n const lines: string[] = []\n for (const line of serializeChatLabToJsonl(merged.chatLabData)) {\n lines.push(line)\n }\n return { success: true, sessionId, data: lines.join('\\n') }\n }\n\n return { success: true, sessionId, data: merged.chatLabData }\n } finally {\n for (const r of readers) r.close()\n }\n })\n\n // ── clear ──────────────────────────────────────────────────────────\n\n server.post<{ Body: { handle?: string } }>('/_web/merge/clear', async (request) => {\n const { handle } = (request.body as any) || {}\n if (handle) {\n mergeCache.delete(handle)\n } else {\n mergeCache.clear()\n }\n return { success: true }\n })\n\n // ── export sessions for merge ──────────────────────────────────────\n\n server.post<{\n Body: { sessionIds: string[] }\n }>('/_web/sessions/export-for-merge', async (request, reply) => {\n const { sessionIds } = request.body as { sessionIds?: string[] }\n if (!sessionIds || !Array.isArray(sessionIds) || sessionIds.length === 0) {\n return reply.code(400).send({ error: 'Missing sessionIds' })\n }\n\n const handles: Array<{ sessionId: string; handle: string }> = []\n for (const sid of sessionIds) {\n const db = ensureDb(ctx, sid)\n const exported = exportSessionToJson(db)\n const { db: tempDb, tempDbPath } = mergeCache.createTempDatabase(exported.meta.name)\n\n const writer = new TempDbWriter(tempDb)\n writer.writeMeta({\n name: exported.meta.name,\n platform: exported.meta.platform,\n type: exported.meta.type,\n groupId: exported.meta.groupId,\n groupAvatar: exported.meta.groupAvatar,\n ownerId: exported.meta.ownerId,\n })\n writer.writeMembers(\n exported.members.map((m) => ({\n platformId: m.platformId,\n accountName: m.accountName,\n groupNickname: m.groupNickname,\n avatar: m.avatar,\n }))\n )\n writer.writeMessages(\n exported.messages.map((msg) => ({\n platformMessageId: msg.platformMessageId,\n senderPlatformId: msg.sender,\n senderAccountName: msg.accountName,\n senderGroupNickname: msg.groupNickname,\n timestamp: msg.timestamp,\n type: msg.type,\n content: msg.content,\n replyToMessageId: msg.replyToMessageId,\n }))\n )\n writer.finish()\n\n const handle = mergeCache.store(exported.meta.name, tempDbPath)\n handles.push({ sessionId: sid, handle })\n }\n\n return { success: true, handles }\n })\n}\n","/**\n * NLP Web API — /_web/nlp/ routes\n *\n * Word frequency, POS tags, dictionary management.\n * Business logic from @openchatlab/core and @openchatlab/node-runtime.\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { PathProvider } from '@openchatlab/core'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport { withAnalyticsCache, type AnalyticsCacheContext } from './analytics-cache'\nimport type { WordFrequencyParams, SupportedLocale } from '@openchatlab/core'\nimport { POS_TAG_DEFINITIONS } from '@openchatlab/core'\nimport {\n initNlpDir,\n computeWordFrequency,\n segmentText,\n getDictList,\n isDictDownloaded,\n downloadDict,\n deleteDict,\n ensureDefaultDict,\n} from '@openchatlab/node-runtime'\n\ntype NlpRouteContext = AnalyticsCacheContext & {\n pathProvider: Pick<PathProvider, 'getCacheDir' | 'getSystemDir'>\n dbManager: Pick<DatabaseManager, 'open'>\n bundledNlpDictDir?: string\n}\n\nexport function registerNlpRoutes(server: FastifyInstance, ctx: NlpRouteContext): void {\n const nlpDir = path.join(ctx.pathProvider.getSystemDir(), 'nlp')\n initNlpDir(nlpDir)\n ensureDefaultDict(nlpDir, ctx.bundledNlpDictDir).catch((err) =>\n console.warn('[NLP] Initialize zh-CN dict failed:', err)\n )\n\n server.get('/_web/nlp/pos-tags', async () => {\n return POS_TAG_DEFINITIONS\n })\n\n server.get('/_web/nlp/dicts', async () => {\n return getDictList(nlpDir)\n })\n\n server.get<{ Params: { id: string } }>('/_web/nlp/dicts/:id/status', async (request) => {\n return isDictDownloaded(nlpDir, request.params.id)\n })\n\n server.post<{ Params: { id: string } }>('/_web/nlp/dicts/:id/download', async (request) => {\n return downloadDict(nlpDir, request.params.id)\n })\n\n server.delete<{ Params: { id: string } }>('/_web/nlp/dicts/:id', async (request) => {\n return deleteDict(nlpDir, request.params.id)\n })\n\n server.post<{ Body: WordFrequencyParams }>('/_web/nlp/word-frequency', async (request) => {\n const params = request.body\n const db = ctx.dbManager.open(params.sessionId)\n if (!db) {\n throw Object.assign(new Error(`Session not found: ${params.sessionId}`), { statusCode: 404 })\n }\n const { sessionId, ...keyParams } = params\n const effectiveDictId = !params.dictType || params.dictType === 'default' ? 'zh-CN' : String(params.dictType)\n const dictFilePath = path.join(nlpDir, `${effectiveDictId}.dict`)\n let dictVersion: string\n try {\n const st = fs.statSync(dictFilePath)\n dictVersion = `${Math.floor(st.mtimeMs)}:${st.size}`\n } catch {\n dictVersion = '-'\n }\n return withAnalyticsCache(ctx, sessionId, 'nlp.word-frequency', keyParams, () => computeWordFrequency(db, params), {\n extraVersion: `dict:${dictVersion}`,\n })\n })\n\n server.post<{ Body: { text: string; locale: SupportedLocale; minLength?: number } }>(\n '/_web/nlp/segment',\n async (request) => {\n const { text, locale, minLength } = request.body\n return segmentText(text, locale, minLength)\n }\n )\n}\n","import type { FastifyInstance } from 'fastify'\nimport {\n CONTACTS_TIME_RANGE_PRESETS,\n type ContactsTimeRangePreset,\n type PeopleRelationshipsGraphScope,\n} from '@openchatlab/shared-types'\nimport { createPeopleRelationshipsService } from '@openchatlab/node-runtime'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { ServiceRouteContext } from '../../context/services'\n\ntype PeopleRelationshipsQuery = {\n acceptStale?: string\n timeRange?: string\n scope?: string\n q?: string\n}\n\ntype PeopleRelationshipsRouteContext = Pick<\n RuntimeRouteContext,\n 'sessionAdapter' | 'pathProvider' | 'runtimeIdentity' | 'nativeBinding'\n> &\n Pick<ServiceRouteContext, 'peopleRelationshipsService'>\n\nexport function registerPeopleRelationshipsRoutes(server: FastifyInstance, ctx: PeopleRelationshipsRouteContext): void {\n const service =\n ctx.peopleRelationshipsService ??\n createPeopleRelationshipsService({\n adapter: ctx.sessionAdapter,\n pathProvider: ctx.pathProvider,\n runtimeIdentity: ctx.runtimeIdentity,\n nativeBinding: ctx.nativeBinding,\n })\n server.addHook('onClose', async () => {\n await service.close()\n })\n\n server.get<{ Querystring: PeopleRelationshipsQuery }>('/_web/people/relationships', async (request) => {\n return service.getGraph({\n acceptStale: isTruthy(request.query.acceptStale),\n timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),\n graphScope: parsePeopleRelationshipsGraphScope(request.query.scope),\n query: request.query.q,\n })\n })\n\n server.post<{ Querystring: PeopleRelationshipsQuery }>('/_web/people/relationships/recompute', async (request) => {\n return service.startRecompute({\n timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),\n graphScope: parsePeopleRelationshipsGraphScope(request.query.scope),\n query: request.query.q,\n })\n })\n\n server.get<{ Params: { key: string }; Querystring: PeopleRelationshipsQuery }>(\n '/_web/people/relationships/:key/neighborhood',\n async (request) => {\n return service.getNeighborhood(request.params.key, {\n acceptStale: isTruthy(request.query.acceptStale),\n timeRangePreset: parseContactsTimeRangePreset(request.query.timeRange),\n graphScope: parsePeopleRelationshipsGraphScope(request.query.scope),\n })\n }\n )\n}\n\nfunction isTruthy(value: string | undefined): boolean {\n return value === '1' || value === 'true' || value === 'yes'\n}\n\nfunction parseContactsTimeRangePreset(value: string | undefined): ContactsTimeRangePreset {\n return CONTACTS_TIME_RANGE_PRESETS.includes(value as ContactsTimeRangePreset)\n ? (value as ContactsTimeRangePreset)\n : '1y'\n}\n\nfunction parsePeopleRelationshipsGraphScope(value: string | undefined): PeopleRelationshipsGraphScope {\n return value === 'close' || value === 'friends' ? value : 'panorama'\n}\n","/**\n * Preferences HTTP routes — /_web/preferences/*\n *\n * Read/write preferences.json and config.toml [ui] section for Web UI.\n */\n\nimport type { FastifyInstance } from 'fastify'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { ServiceRouteContext } from '../../context/services'\nimport { PreferencesManager, type Preferences } from '@openchatlab/node-runtime'\nimport { loadConfig, writeConfigField, type UiConfig } from '@openchatlab/config'\n\ntype PreferencesRouteContext = Pick<RuntimeRouteContext, 'pathProvider'> &\n Pick<ServiceRouteContext, 'preferencesManager'>\n\nexport function registerPreferencesRoutes(server: FastifyInstance, ctx: PreferencesRouteContext): void {\n const prefManager = ctx.preferencesManager ?? new PreferencesManager(ctx.pathProvider.getSystemDir())\n\n server.get('/_web/preferences', async () => {\n return prefManager.load()\n })\n\n server.get('/_web/preferences/bootstrap', async () => {\n const config = loadConfig()\n return {\n locale: config.locale.lang,\n uiConfig: config.ui,\n }\n })\n\n server.patch<{ Body: Partial<Preferences> }>('/_web/preferences', async (request) => {\n return prefManager.save(request.body)\n })\n\n server.get('/_web/preferences/ui-config', async () => {\n const config = loadConfig()\n return config.ui\n })\n\n server.patch<{ Body: Partial<UiConfig> }>('/_web/preferences/ui-config', async (request) => {\n try {\n for (const [key, value] of Object.entries(request.body)) {\n if (value !== undefined) {\n writeConfigField('ui', key, value as string | number)\n }\n }\n return { success: true }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) }\n }\n })\n\n server.get('/_web/preferences/locale', async () => {\n const config = loadConfig()\n return { lang: config.locale.lang }\n })\n\n server.patch<{ Body: { lang: string } }>('/_web/preferences/locale', async (request) => {\n try {\n writeConfigField('locale', 'lang', request.body.lang)\n return { success: true }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) }\n }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport { sessionIndexService } from '@openchatlab/node-runtime'\n\ntype SessionIndexRouteContext = Pick<RuntimeRouteContext, 'sessionAdapter'>\n\nexport function registerSessionIndexRoutes(server: FastifyInstance, ctx: SessionIndexRouteContext): void {\n const { sessionAdapter: adapter } = ctx\n\n server.get('/_web/sessions/index-stats', async () => {\n return sessionIndexService.getAllIndexStats(adapter)\n })\n\n server.post<{\n Params: { id: string }\n Body: { gapThreshold?: number }\n }>('/_web/sessions/:id/generate-index', async (request) => {\n const gapThreshold = (request.body as any)?.gapThreshold ?? 1800\n const sessionCount = sessionIndexService.generateIndex(adapter, request.params.id, gapThreshold)\n return { sessionCount }\n })\n\n server.post<{\n Params: { id: string }\n Body: { gapThreshold?: number }\n }>('/_web/sessions/:id/generate-incremental-index', async (request) => {\n const gapThreshold = (request.body as any)?.gapThreshold ?? 1800\n const sessionCount = sessionIndexService.generateIncrementalIndex(adapter, request.params.id, gapThreshold)\n return { sessionCount }\n })\n\n server.post<{ Params: { id: string } }>('/_web/sessions/:id/clear-index', async (request) => {\n sessionIndexService.clearIndex(adapter, request.params.id)\n return { success: true }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { ServiceRouteContext } from '../../context/services'\nimport {\n chatTopicWorkCoordinator,\n sessionService,\n ownerProfileService,\n PreferencesManager,\n} from '@openchatlab/node-runtime'\n\ntype SessionRouteContext = Pick<RuntimeRouteContext, 'sessionAdapter' | 'pathProvider' | 'beforeDeleteSession'> &\n Pick<ServiceRouteContext, 'preferencesManager'> &\n Pick<AiRouteContext, 'aiChatManager'>\n\nexport function registerSessionRoutes(server: FastifyInstance, ctx: SessionRouteContext): void {\n const { sessionAdapter: adapter } = ctx\n const cacheDir = ctx.pathProvider.getCacheDir()\n\n // Lazy: only owner-profile routes need preferences.json access\n let preferencesInstance: PreferencesManager | null = null\n const preferences = () => {\n preferencesInstance ??= ctx.preferencesManager ?? new PreferencesManager(ctx.pathProvider.getSystemDir())\n return preferencesInstance\n }\n\n server.get('/_web/sessions', async () => {\n const aiChatCounts = ctx.aiChatManager?.getAIChatCountsBySession()\n const excludedSessionIds = new Set(preferences().load().ownerExcludedSessionIds)\n return sessionService.listAnalysisSessions(adapter, {\n resolveOverview: (db, sessionId) => sessionService.resolveValidatedSessionOverview(db, sessionId, cacheDir),\n enrichSession: (dto) => ({\n ...dto,\n aiConversationCount: aiChatCounts?.get(dto.id) ?? 0,\n ownerExcluded: excludedSessionIds.has(dto.id),\n }),\n })\n })\n\n server.get<{ Params: { id: string } }>('/_web/sessions/:id', async (request) => {\n const excludedSessionIds = new Set(preferences().load().ownerExcludedSessionIds)\n const session = sessionService.getAnalysisSession(adapter, request.params.id, {\n resolveOverview: (db, sessionId) => sessionService.resolveValidatedSessionOverview(db, sessionId, cacheDir),\n enrichSession: (dto) => ({ ...dto, ownerExcluded: excludedSessionIds.has(dto.id) }),\n })\n if (!session) {\n throw Object.assign(new Error(`Session not found: ${request.params.id}`), { statusCode: 404 })\n }\n if (ctx.aiChatManager) {\n session.aiConversationCount = ctx.aiChatManager.getAIChats(request.params.id).length\n }\n return session\n })\n\n server.delete<{ Params: { id: string } }>('/_web/sessions/:id', async (request, reply) => {\n const { id } = request.params\n await chatTopicWorkCoordinator.prepareSessionDelete(id)\n await ctx.beforeDeleteSession?.(id)\n const deleted = sessionService.deleteSession(adapter, id)\n if (!deleted) {\n return reply.code(404).send({ success: false, error: 'File not found' })\n }\n ownerProfileService.clearOwnerExclusions(preferences(), [id])\n return { success: true }\n })\n\n server.patch<{ Params: { id: string }; Body: { name: string } }>('/_web/sessions/:id/name', async (request) => {\n sessionService.renameSession(adapter, request.params.id, request.body.name)\n return { success: true }\n })\n\n server.patch<{ Params: { id: string }; Body: { ownerId: string | null } }>(\n '/_web/sessions/:id/owner',\n async (request) => {\n sessionService.updateSessionOwnerId(adapter, request.params.id, request.body.ownerId ?? null)\n if (request.body.ownerId) ownerProfileService.clearOwnerExclusions(preferences(), [request.params.id])\n return { success: true }\n }\n )\n\n // Try to auto-apply the stored platform owner profile to this session.\n server.post<{ Params: { id: string } }>('/_web/sessions/:id/owner/apply-profile', async (request) => {\n return ownerProfileService.tryApplyOwnerProfile(adapter, preferences(), request.params.id)\n })\n\n // Manually select owner: writes meta.owner_id, updates the platform profile,\n // and batch-applies it to other unowned same-platform sessions.\n server.post<{ Params: { id: string }; Body: { ownerPlatformId: string } }>(\n '/_web/sessions/:id/owner/select',\n async (request) => {\n return ownerProfileService.setOwnerAndApplyProfile(\n adapter,\n preferences(),\n request.params.id,\n request.body.ownerPlatformId\n )\n }\n )\n\n // Mark the session as not containing the current user.\n server.post<{ Params: { id: string } }>('/_web/sessions/:id/owner/exclude', async (request) => {\n ownerProfileService.excludeOwnerSession(preferences(), request.params.id)\n return { success: true }\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport { executeSql, getSchemaDetailed } from '@openchatlab/core'\n\ntype SqlRouteContext = Pick<RuntimeRouteContext, 'sessionAdapter'>\n\nexport function registerSqlRoutes(server: FastifyInstance, ctx: SqlRouteContext): void {\n const { sessionAdapter: adapter } = ctx\n\n server.post<{ Params: { id: string }; Body: { sql: string } }>('/_web/sessions/:id/sql', async (request, reply) => {\n const db = adapter.ensureReadonly(request.params.id)\n const { sql } = request.body || {}\n if (!sql || typeof sql !== 'string') {\n return reply.code(400).send({ error: 'Missing sql parameter' })\n }\n try {\n const result = executeSql(db, sql, { columnar: true, timing: true, maxRows: 0 })\n return {\n columns: result.columns,\n rows: result.rows,\n rowCount: result.rowCount,\n duration: result.duration ?? 0,\n limited: result.truncated,\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'SQL execution error'\n return reply.code(400).send({ error: message })\n }\n })\n\n server.get<{ Params: { id: string } }>('/_web/sessions/:id/schema', async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getSchemaDetailed(db)\n })\n\n server.post<{\n Params: { id: string }\n Body: { sql: string; params?: unknown[] | Record<string, unknown> }\n }>('/_web/sessions/:id/query', async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n const { sql, params = [] } = request.body as { sql: string; params?: unknown[] | Record<string, unknown> }\n\n if (!sql || typeof sql !== 'string') {\n throw Object.assign(new Error('Missing or invalid \"sql\" field'), { statusCode: 400 })\n }\n\n const stmt = db.prepare(sql.trim())\n\n if (!stmt.readonly) {\n throw Object.assign(new Error('Only READ-ONLY statements are allowed'), { statusCode: 403 })\n }\n\n if (Array.isArray(params)) {\n return stmt.all(...params)\n }\n return stmt.all(params)\n })\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AnalyticsService } from '@openchatlab/node-runtime'\nimport type { AnalyticsEventName } from '@openchatlab/shared-types'\n\ninterface TelemetryRouteContext {\n analyticsService?: Pick<AnalyticsService, 'getEnabled' | 'setEnabled' | 'trackDailyActive' | 'track'>\n}\n\nexport function registerTelemetryRoutes(server: FastifyInstance, ctx: TelemetryRouteContext): void {\n server.get('/_web/telemetry/enabled', async () => {\n return { enabled: ctx.analyticsService?.getEnabled() ?? false }\n })\n\n server.post<{ Body: { enabled?: boolean } }>('/_web/telemetry/enabled', async (req) => {\n if (!ctx.analyticsService || typeof req.body?.enabled !== 'boolean') return { success: false }\n ctx.analyticsService.setEnabled(req.body.enabled)\n return { success: true }\n })\n\n server.post<{ Body: { eventName: AnalyticsEventName; properties?: Record<string, unknown> } }>(\n '/_web/telemetry/track',\n async (req, reply) => {\n if (!ctx.analyticsService) return { ok: true }\n const { eventName, properties } = req.body ?? {}\n if (!eventName) return reply.code(400).send({ error: 'eventName required' })\n if (eventName === 'app_active') {\n await ctx.analyticsService.trackDailyActive(properties)\n } else {\n await ctx.analyticsService.track(eventName, properties)\n }\n return { ok: true }\n }\n )\n}\n","import type { FastifyInstance } from 'fastify'\nimport { PreferencesManager } from '@openchatlab/node-runtime'\nimport type { AiRouteContext } from '../../context/ai'\nimport type { MergeRouteContext } from '../../context/merge'\nimport type { RuntimeRouteContext } from '../../context/runtime'\nimport type { ServiceRouteContext } from '../../context/services'\nimport type { StorageRouteContext } from '../../context/storage'\nimport { registerNodePlugins, type NodePluginDescriptor } from '../../plugins/node'\nimport { registerAiRoutes, type AiRouteOptions } from './register-ai'\nimport { registerAnalyticsRoutes } from './analytics'\nimport { registerCacheRoutes } from './cache'\nimport { registerContactsRoutes } from './contacts'\nimport { registerExportRoutes } from './export'\nimport { registerLogRoutes } from './logs'\nimport { registerMemberRoutes } from './members'\nimport { registerNavigationLayoutRoutes } from './navigation-layout'\nimport { registerMergeRoutes } from './merge'\nimport { registerNlpRoutes } from './nlp'\nimport { registerPeopleRelationshipsRoutes } from './people-relationships'\nimport { registerPreferencesRoutes } from './preferences'\nimport { registerSessionIndexRoutes } from './session-index'\nimport { registerSessionRoutes } from './sessions'\nimport { registerSqlRoutes } from './sql'\nimport { registerTelemetryRoutes } from './telemetry'\n\nexport type WebRoutesContext = RuntimeRouteContext &\n ServiceRouteContext &\n MergeRouteContext &\n AiRouteContext &\n StorageRouteContext\n\nexport interface WebRouteOptions extends AiRouteOptions {\n /** Trusted Node plugin facets selected by the platform's static catalog. */\n nodePlugins?: readonly NodePluginDescriptor[]\n}\n\n/** Register the internal Web API under /_web, excluding lifecycle-owned automation routes. */\nexport function registerWebRoutes(server: FastifyInstance, ctx: WebRoutesContext, options?: WebRouteOptions): void {\n // Sessions and preferences must share one manager to avoid stale-cache overwrites.\n const resolvedCtx: WebRoutesContext = ctx.preferencesManager\n ? ctx\n : { ...ctx, preferencesManager: new PreferencesManager(ctx.pathProvider.getSystemDir()) }\n\n registerSessionRoutes(server, resolvedCtx)\n registerMemberRoutes(server, resolvedCtx)\n registerContactsRoutes(server, resolvedCtx)\n registerPeopleRelationshipsRoutes(server, resolvedCtx)\n registerNavigationLayoutRoutes(server, resolvedCtx)\n registerNodePlugins(server, resolvedCtx, options?.nodePlugins ?? [])\n registerPreferencesRoutes(server, resolvedCtx)\n registerAnalyticsRoutes(server, resolvedCtx)\n registerSqlRoutes(server, resolvedCtx)\n registerSessionIndexRoutes(server, resolvedCtx)\n registerExportRoutes(server, resolvedCtx)\n registerNlpRoutes(server, resolvedCtx)\n registerAiRoutes(server, resolvedCtx, options)\n registerMergeRoutes(server, resolvedCtx)\n registerCacheRoutes(server, resolvedCtx)\n registerTelemetryRoutes(server, resolvedCtx)\n registerLogRoutes(server)\n}\n","/** Aggregate registration for the shared REST and Web route groups. */\n\nimport type { FastifyInstance } from 'fastify'\nimport type { HttpRouteContext } from './context'\nimport { registerRestRoutes } from './routes/rest/register'\nimport { registerWebRoutes, type WebRouteOptions } from './routes/web/register'\n\nexport type SharedRouteOptions = WebRouteOptions\n\nexport function registerSharedRoutes(\n server: FastifyInstance,\n ctx: HttpRouteContext,\n options?: SharedRouteOptions\n): void {\n registerRestRoutes(server, ctx)\n registerWebRoutes(server, ctx, options)\n}\n","import { ANNUAL_SUMMARY_PLUGIN_ID } from '@openchatlab/shared-types'\nimport { createGlobalInsightService, PreferencesManager } from '@openchatlab/node-runtime'\nimport type { NodePluginDescriptor } from '../../node'\n\ninterface AnnualSummaryQuery {\n mode?: string\n year?: string\n days?: string\n acceptStale?: string\n}\n\nexport const annualSummaryNodePlugin = {\n id: ANNUAL_SUMMARY_PLUGIN_ID,\n registerHttpRoutes(server, context) {\n let preferences = context.preferencesManager\n const getExcludedSessionIds = () => {\n preferences ??= new PreferencesManager(context.pathProvider.getSystemDir())\n return preferences.load().ownerExcludedSessionIds\n }\n const service =\n context.globalInsightService ??\n createGlobalInsightService({\n adapter: context.sessionAdapter,\n pathProvider: context.pathProvider,\n runtimeIdentity: context.runtimeIdentity,\n nativeBinding: context.nativeBinding,\n getExcludedSessionIds,\n })\n\n server.addHook('onClose', () => service.close())\n server.get<{ Querystring: AnnualSummaryQuery }>('/_web/global-insight/annual-summary', async (request) =>\n service.getAnnualSummary({\n ...parseRange(request.query),\n acceptStale: isTruthy(request.query.acceptStale),\n })\n )\n server.post<{ Querystring: AnnualSummaryQuery }>('/_web/global-insight/annual-summary/recompute', async (request) =>\n service.startRecompute(parseRange(request.query))\n )\n },\n} satisfies NodePluginDescriptor\n\nfunction parseRange(query: AnnualSummaryQuery) {\n const mode = query.mode === 'recent' ? ('recent' as const) : ('year' as const)\n return {\n mode,\n year: parseInteger(query.year),\n days: query.days === '365' ? (365 as const) : undefined,\n }\n}\n\nfunction parseInteger(value: string | undefined): number | undefined {\n if (!value) return undefined\n const parsed = Number(value)\n return Number.isInteger(parsed) ? parsed : undefined\n}\n\nfunction isTruthy(value: string | undefined): boolean {\n return value === '1' || value === 'true' || value === 'yes'\n}\n","import { createTimeInvestmentService, PreferencesManager } from '@openchatlab/node-runtime'\nimport { TIME_INVESTMENT_PLUGIN_ID } from '@openchatlab/shared-types'\nimport type { NodePluginDescriptor } from '../../node'\n\ninterface TimeInvestmentQuery {\n mode?: string\n year?: string\n days?: string\n acceptStale?: string\n}\n\nexport const timeInvestmentNodePlugin = {\n id: TIME_INVESTMENT_PLUGIN_ID,\n registerHttpRoutes(server, context) {\n let preferences = context.preferencesManager\n const getExcludedSessionIds = () => {\n preferences ??= new PreferencesManager(context.pathProvider.getSystemDir())\n return preferences.load().ownerExcludedSessionIds\n }\n const service =\n context.timeInvestmentService ??\n createTimeInvestmentService({\n adapter: context.sessionAdapter,\n pathProvider: context.pathProvider,\n runtimeIdentity: context.runtimeIdentity,\n nativeBinding: context.nativeBinding,\n getExcludedSessionIds,\n })\n server.addHook('onClose', () => service.close())\n\n server.get<{ Querystring: TimeInvestmentQuery }>('/_web/global-insight/time-investment', async (request) =>\n service.getTimeInvestment({\n ...parseRange(request.query),\n acceptStale: isTruthy(request.query.acceptStale),\n })\n )\n\n server.post<{ Querystring: TimeInvestmentQuery }>(\n '/_web/global-insight/time-investment/recompute',\n async (request) => service.startRecompute(parseRange(request.query))\n )\n },\n} satisfies NodePluginDescriptor\n\nfunction parseRange(query: TimeInvestmentQuery) {\n const mode = query.mode === 'recent' ? ('recent' as const) : ('year' as const)\n return {\n mode,\n year: parseInteger(query.year),\n days: query.days === '365' ? (365 as const) : undefined,\n }\n}\n\nfunction parseInteger(value: string | undefined): number | undefined {\n if (!value) return undefined\n const parsed = Number(value)\n return Number.isInteger(parsed) ? parsed : undefined\n}\n\nfunction isTruthy(value: string | undefined): boolean {\n return value === '1' || value === 'true' || value === 'yes'\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { AutomationRouteHostContext } from '../../context/automation'\n\nfunction requireAutomation(ctx: AutomationRouteHostContext) {\n return ctx.automation ?? null\n}\n\nfunction normalizeBaseUrl(input: string): string {\n let url = input.trim().replace(/\\/+$/, '')\n if (url && !/^https?:\\/\\//i.test(url)) url = `http://${url}`\n if (url && !url.endsWith('/api/v1')) {\n url = url.replace(/\\/api\\/v1$/, '') + '/api/v1'\n }\n return url\n}\n\nfunction buildRemoteSessionsUrl(\n baseUrl: string,\n query: { keyword?: string; limit?: string | number; cursor?: string } = {}\n): string {\n const searchParams = new URLSearchParams()\n searchParams.set('format', 'chatlab')\n if (query.keyword?.trim()) searchParams.set('keyword', query.keyword.trim())\n if (query.limit && Number(query.limit) > 0) searchParams.set('limit', String(query.limit))\n if (query.cursor) searchParams.set('cursor', query.cursor)\n return `${baseUrl}/sessions?${searchParams.toString()}`\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined\n}\n\nfunction parseRemoteSessionsResponse(body: string): {\n sessions: unknown[]\n page?: { hasMore: boolean; nextCursor?: string }\n} {\n const parsed = JSON.parse(body)\n\n let sessions: unknown[]\n let pageSource: Record<string, unknown> | undefined\n\n if (Array.isArray(parsed)) {\n sessions = parsed\n } else {\n const record = asRecord(parsed)\n const data = asRecord(record?.data)\n const sessionsSource = record?.sessions ?? data?.sessions ?? record?.data\n sessions = Array.isArray(sessionsSource) ? sessionsSource : []\n pageSource = asRecord(record?.page) ?? asRecord(data?.page)\n }\n\n return {\n sessions,\n page:\n pageSource && typeof pageSource === 'object'\n ? {\n hasMore: Boolean(pageSource.hasMore),\n nextCursor: typeof pageSource.nextCursor === 'string' ? pageSource.nextCursor : undefined,\n }\n : undefined,\n }\n}\n\nexport function registerAutomationRoutes(server: FastifyInstance, ctx: AutomationRouteHostContext): void {\n server.get('/_web/automation/config', async (_request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation?.serverInfo) return reply.code(404).send({ error: 'Automation is not enabled' })\n return {\n enabled: true,\n port: automation.serverInfo.port,\n token: automation.serverInfo.token,\n host: automation.serverInfo.host,\n socket: automation.serverInfo.socket,\n }\n })\n\n server.get('/_web/automation/data-sources', async (_request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n return automation.dsManager.loadAll()\n })\n\n server.post<{\n Body: { name?: string; baseUrl: string; token: string; intervalMinutes: number; pullLimit?: number }\n }>('/_web/automation/data-sources', async (request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n const ds = automation.dsManager.add(request.body)\n automation.reloadTimer?.((ds as { id: string }).id)\n return ds\n })\n\n server.patch<{\n Params: { id: string }\n Body: {\n name?: string\n baseUrl?: string\n token?: string\n intervalMinutes?: number\n pullLimit?: number\n enabled?: boolean\n }\n }>('/_web/automation/data-sources/:id', async (request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n const ds = automation.dsManager.update(request.params.id, request.body)\n if (!ds) return reply.code(404).send({ error: 'Data source not found' })\n automation.reloadTimer?.((ds as { id: string }).id)\n return ds\n })\n\n server.delete<{ Params: { id: string } }>('/_web/automation/data-sources/:id', async (request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n automation.stopTimer?.(request.params.id)\n const ok = automation.dsManager.delete(request.params.id)\n if (!ok) return reply.code(404).send({ error: 'Data source not found' })\n return { success: true }\n })\n\n server.post<{\n Params: { id: string }\n Body: { sessions: Array<{ name: string; remoteSessionId: string }> }\n }>('/_web/automation/data-sources/:id/sessions', async (request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n const added = automation.dsManager.addSessions(request.params.id, request.body.sessions)\n if (added.length === 0 && !automation.dsManager.get(request.params.id)) {\n return reply.code(404).send({ error: 'Data source not found' })\n }\n automation.reloadTimer?.(request.params.id, true)\n for (const sess of added as Array<{ id: string }>) {\n void automation.pullEngine.triggerPull(request.params.id, sess.id).catch(() => undefined)\n }\n return added\n })\n\n server.delete<{\n Params: { id: string; sessId: string }\n Querystring: { deleteData?: string }\n }>('/_web/automation/data-sources/:id/sessions/:sessId', async (request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n const removed = automation.dsManager.removeSession(request.params.id, request.params.sessId)\n if (!removed) return reply.code(404).send({ error: 'Session not found' })\n automation.reloadTimer?.(request.params.id)\n if (request.query.deleteData === 'true' && removed.targetSessionId) {\n automation.deleteSessionData?.(removed.targetSessionId)\n }\n return { success: true }\n })\n\n server.post<{ Params: { id: string }; Body: { sessionId?: string } }>(\n '/_web/automation/data-sources/:id/pull',\n async (request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n return automation.pullEngine.triggerPull(request.params.id, request.body?.sessionId)\n }\n )\n\n server.post<{ Params: { id: string } }>('/_web/automation/data-sources/:id/pull-all', async (request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n return automation.pullEngine.triggerPullAll(request.params.id)\n })\n\n server.get('/_web/automation/sync-progress', async (_request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n return automation.pullEngine.getProgress()\n })\n\n server.get<{\n Querystring: { baseUrl: string; token?: string; keyword?: string; limit?: string; cursor?: string }\n }>('/_web/automation/remote-sessions', async (request, reply) => {\n const automation = requireAutomation(ctx)\n if (!automation) return reply.code(404).send({ error: 'Automation is not enabled' })\n\n const { baseUrl, token, keyword, limit, cursor } = request.query\n if (!baseUrl) return reply.code(400).send({ error: 'baseUrl is required' })\n\n const url = buildRemoteSessionsUrl(normalizeBaseUrl(baseUrl), { keyword, limit, cursor })\n const headers: Record<string, string> = { Accept: 'application/json' }\n if (token) headers.Authorization = `Bearer ${token}`\n\n try {\n const resp = await fetch(url, { headers, signal: AbortSignal.timeout(30_000) })\n if (!resp.ok) throw new Error(`Remote server returned HTTP ${resp.status}`)\n const body = await resp.text()\n return parseRemoteSessionsResponse(body)\n } catch (err) {\n return reply.code(502).send({ error: err instanceof Error ? err.message : 'Failed to fetch remote sessions' })\n }\n })\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport { randomUUID } from 'node:crypto'\nimport { pipeline } from 'node:stream/promises'\nimport type { FastifyInstance } from 'fastify'\nimport {\n ArchiveImportError,\n ArchiveImportSourceManager,\n appLogger,\n createChatLabTempDir,\n getChatLabTempScopeDir,\n importDemoSessions,\n type DatabaseManager,\n} from '@openchatlab/node-runtime'\nimport { PARSER_FORMAT_IDS } from '@openchatlab/parser'\nimport {\n autoImport,\n autoImportBatch,\n streamImport,\n incrementalImport,\n analyzeIncrementalImport,\n analyzeNewImport,\n detectFormat,\n detectAllFormats,\n getSupportedFormats,\n scanMultiChatFile,\n findEntryFileInDirectory,\n} from '../../../import'\nimport type {\n AutoImportBatchOptions,\n AutoImportBatchRequest,\n AutoImportResult,\n StreamImportOptions,\n} from '../../../import'\nimport { resolveNativeBinding } from './helpers'\n\nconst ARCHIVE_UPLOAD_LIMIT = 50 * 1024 * 1024 * 1024\n\ninterface ImportRouteOptions {\n sourceManager?: ArchiveImportSourceManager\n runAutoImport?: (filePath: string, options: StreamImportOptions) => Promise<AutoImportResult>\n runAutoImportBatch?: (\n items: AutoImportBatchRequest[],\n options: AutoImportBatchOptions\n ) => ReturnType<typeof autoImportBatch>\n runPreparedImport?: (\n manifestPath: string,\n onProgress: (progress: unknown) => void,\n sessionGapThreshold?: number\n ) => Promise<{ success: boolean; sessionId?: string; error?: string; messageCount?: number; memberCount?: number }>\n}\n\nfunction parseOptionalInteger(value: unknown): number | undefined {\n if (typeof value === 'number') return Number.isInteger(value) ? value : undefined\n if (typeof value !== 'string' || value.trim() === '') return undefined\n const parsed = Number(value)\n return Number.isInteger(parsed) ? parsed : undefined\n}\n\nfunction cleanupTemp(...paths: string[]) {\n for (const p of paths) {\n try {\n const stat = fs.statSync(p)\n if (stat.isDirectory()) {\n fs.rmSync(p, { recursive: true, force: true })\n } else {\n fs.unlinkSync(p)\n }\n } catch {\n /* ignore */\n }\n }\n}\n\nexport function registerImportRoutes(\n server: FastifyInstance,\n dbManager: DatabaseManager,\n options: ImportRouteOptions = {}\n): void {\n const activeBatchControllers = new Map<string, AbortController>()\n const sourceManager = options.sourceManager ?? new ArchiveImportSourceManager()\n const runAutoImport = options.runAutoImport ?? autoImport.bind(null, dbManager)\n const runAutoImportBatch = options.runAutoImportBatch ?? autoImportBatch.bind(null, dbManager)\n const runPreparedImport =\n options.runPreparedImport ??\n (async (manifestPath: string, onProgress: (progress: unknown) => void, sessionGapThreshold?: number) => {\n const result = await runAutoImport(manifestPath, {\n formatId: PARSER_FORMAT_IDS.GOOGLE_CHAT_NATIVE,\n sessionGapThreshold,\n nativeBinding: resolveNativeBinding(),\n onProgress: onProgress as any,\n })\n return result\n })\n\n server.addHook('onClose', async () => {\n await sourceManager.close()\n })\n\n server.post('/_web/import-sources', async (request, reply) => {\n const data = await (request as any).file({\n limits: { fileSize: ARCHIVE_UPLOAD_LIMIT },\n })\n if (!data) return reply.code(400).send({ success: false, error: 'error.no_file_selected' })\n\n const uploadPath = path.join(getChatLabTempScopeDir('imports'), `archive-${randomUUID()}.zip`)\n try {\n await pipeline(data.file, fs.createWriteStream(uploadPath, { flags: 'wx' }))\n if (data.file.truncated) {\n cleanupTemp(uploadPath)\n return reply.code(413).send({ success: false, error: 'error.archive_limit_exceeded' })\n }\n\n const source = await sourceManager.prepareOwnedArchive(uploadPath)\n return { success: true, source }\n } catch (error) {\n cleanupTemp(uploadPath)\n if (error instanceof ArchiveImportError) {\n return reply.code(400).send({ success: false, error: error.code })\n }\n return reply.code(400).send({\n success: false,\n error: error instanceof Error ? error.message : String(error),\n })\n }\n })\n\n server.post<{ Params: { sourceId: string }; Body: { chatId?: string; sessionGapThreshold?: number } }>(\n '/_web/import-sources/:sourceId/import',\n async (request, reply) => {\n const chatId = request.body?.chatId\n if (!chatId) return reply.code(400).send({ success: false, error: 'error.no_chat_selected' })\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n function sendEvent(event: string, eventData: unknown) {\n reply.raw.write(`event: ${event}\\ndata: ${JSON.stringify(eventData)}\\n\\n`)\n }\n\n try {\n const sessionGapThreshold = parseOptionalInteger(request.body?.sessionGapThreshold)\n const result = await sourceManager.withMaterializedChat(request.params.sourceId, chatId, (manifestPath) =>\n runPreparedImport(manifestPath, (progress) => sendEvent('progress', progress), sessionGapThreshold)\n )\n if (result.success) {\n sendEvent('done', result)\n } else {\n sendEvent('error', { success: false, error: result.error || 'error.import_failed' })\n }\n } catch (error) {\n sendEvent('error', {\n success: false,\n error:\n error instanceof ArchiveImportError ? error.code : error instanceof Error ? error.message : String(error),\n })\n } finally {\n reply.raw.end()\n }\n }\n )\n\n server.delete<{ Params: { sourceId: string } }>('/_web/import-sources/:sourceId', async (request) => {\n await sourceManager.release(request.params.sourceId)\n return { success: true }\n })\n\n server.get('/_web/supported-formats', async () => {\n return getSupportedFormats()\n })\n\n server.post('/_web/detect-format', async (request, reply) => {\n const data = await (request as any).file()\n if (!data) return reply.code(400).send({ error: 'No file uploaded' })\n\n const tmpDir = createChatLabTempDir('imports', 'detect-')\n const tmpPath = path.join(tmpDir, data.filename || 'upload')\n\n try {\n const chunks: Buffer[] = []\n for await (const chunk of data.file) {\n chunks.push(chunk)\n }\n fs.writeFileSync(tmpPath, Buffer.concat(chunks))\n\n const format = detectFormat(tmpPath)\n const allFormats = detectAllFormats(tmpPath)\n return { format, allFormats }\n } finally {\n cleanupTemp(tmpPath, tmpDir)\n }\n })\n\n server.post('/_web/scan-multi-chat', async (request, reply) => {\n const data = await (request as any).file()\n if (!data) return reply.code(400).send({ error: 'No file uploaded' })\n\n const tmpDir = createChatLabTempDir('imports', 'scan-')\n const tmpPath = path.join(tmpDir, data.filename || 'upload')\n\n try {\n const chunks: Buffer[] = []\n for await (const chunk of data.file) {\n chunks.push(chunk)\n }\n fs.writeFileSync(tmpPath, Buffer.concat(chunks))\n\n const chats = await scanMultiChatFile(tmpPath)\n return { chats }\n } finally {\n cleanupTemp(tmpPath, tmpDir)\n }\n })\n\n server.post('/_web/import', async (request, reply) => {\n const data = await (request as any).file()\n if (!data) return reply.code(400).send({ error: 'No file uploaded' })\n\n const tmpDir = createChatLabTempDir('imports', 'upload-')\n const tmpPath = path.join(tmpDir, data.filename || 'upload')\n\n const chunks: Buffer[] = []\n for await (const chunk of data.file) {\n chunks.push(chunk)\n }\n fs.writeFileSync(tmpPath, Buffer.concat(chunks))\n\n const formatId = (data.fields?.formatId as any)?.value as string | undefined\n const chatIndexStr = (data.fields?.chatIndex as any)?.value as string | undefined\n const chatIndex = chatIndexStr !== undefined ? parseInt(chatIndexStr, 10) : undefined\n const sessionGapThreshold = parseOptionalInteger((data.fields?.sessionGapThreshold as any)?.value)\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n function sendEvent(event: string, eventData: unknown) {\n reply.raw.write(`event: ${event}\\ndata: ${JSON.stringify(eventData)}\\n\\n`)\n }\n\n try {\n const nativeBinding = resolveNativeBinding()\n const result = await runAutoImport(tmpPath, {\n formatId,\n chatIndex,\n sessionGapThreshold,\n nativeBinding,\n onProgress: (p) => sendEvent('progress', p),\n })\n\n if (result.success) {\n sendEvent('done', result)\n } else {\n sendEvent('error', result)\n }\n } catch (err) {\n sendEvent('error', { success: false, error: err instanceof Error ? err.message : String(err) })\n } finally {\n reply.raw.end()\n cleanupTemp(tmpPath, tmpDir)\n }\n })\n\n server.post('/_web/import/batch', async (request, reply) => {\n const parts = (request as any).parts()\n if (!parts) return reply.code(400).send({ error: 'No files uploaded' })\n\n const requestedBatchId = request.headers['x-chatlab-import-batch-id']\n const batchId = typeof requestedBatchId === 'string' && requestedBatchId ? requestedBatchId : randomUUID()\n if (activeBatchControllers.has(batchId)) {\n return reply.code(409).send({ error: 'Batch import id is already active' })\n }\n\n const tmpDir = createChatLabTempDir('imports', 'batch-')\n const items: AutoImportBatchRequest[] = []\n let sessionGapThreshold: number | undefined\n let completed = false\n const controller = new AbortController()\n activeBatchControllers.set(batchId, controller)\n\n try {\n for await (const part of parts) {\n if (part.type === 'field' && part.fieldname === 'sessionGapThreshold') {\n sessionGapThreshold = parseOptionalInteger(part.value)\n continue\n }\n if (part.type !== 'file') continue\n const index = items.length\n const safeName = path.basename(part.filename || `upload-${index}`)\n const filePath = path.join(tmpDir, `${index}-${safeName}`)\n await pipeline(part.file, fs.createWriteStream(filePath, { flags: 'wx' }))\n items.push({ id: String(index), filePath })\n }\n\n if (items.length === 0) return reply.code(400).send({ error: 'No files uploaded' })\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n reply.raw.once('close', () => {\n if (!completed) controller.abort()\n })\n\n const sendEvent = (event: string, eventData: unknown) => {\n if (!reply.raw.destroyed) {\n reply.raw.write(`event: ${event}\\ndata: ${JSON.stringify(eventData)}\\n\\n`)\n }\n }\n const results = await runAutoImportBatch(items, {\n sessionGapThreshold,\n signal: controller.signal,\n onItemStart: (_item, index) => sendEvent('batch-start', { index }),\n onItemProgress: (_item, index, progress) => sendEvent('batch-progress', { index, progress }),\n onItemComplete: (_item, index, result) => sendEvent('batch-complete', { index, result }),\n })\n completed = true\n sendEvent('done', results)\n } catch (error) {\n appLogger.error('import-batch', 'CLI Web batch import failed', error)\n const payload = { error: error instanceof Error ? error.message : String(error) }\n if (!reply.raw.headersSent) return reply.code(500).send(payload)\n if (!reply.raw.destroyed) {\n reply.raw.write(`event: error\\ndata: ${JSON.stringify(payload)}\\n\\n`)\n }\n } finally {\n completed = true\n if (activeBatchControllers.get(batchId) === controller) activeBatchControllers.delete(batchId)\n reply.raw.end()\n cleanupTemp(tmpDir)\n }\n })\n\n server.post<{ Params: { batchId: string } }>('/_web/import/batch/:batchId/cancel', async (request) => {\n const controller = activeBatchControllers.get(request.params.batchId)\n if (!controller) return { success: false, active: false }\n controller.abort()\n return { success: true, active: true }\n })\n\n // ==================== Directory Import ====================\n\n server.post('/_web/import-directory', async (request, reply) => {\n const parts = (request as any).parts()\n if (!parts) return reply.code(400).send({ error: 'No files uploaded' })\n\n const tmpDir = createChatLabTempDir('imports', 'directory-')\n const relativePaths: string[] = []\n const fileBuffers: { data: Buffer; filename: string }[] = []\n let sessionGapThreshold: number | undefined\n\n try {\n for await (const part of parts) {\n if (part.type === 'field' && part.fieldname === 'relativePaths') {\n relativePaths.push(String(part.value))\n } else if (part.type === 'field' && part.fieldname === 'sessionGapThreshold') {\n sessionGapThreshold = parseOptionalInteger(part.value)\n } else if (part.type === 'file') {\n const chunks: Buffer[] = []\n for await (const chunk of part.file) {\n chunks.push(chunk)\n }\n fileBuffers.push({ data: Buffer.concat(chunks), filename: part.filename || '' })\n }\n }\n\n for (let i = 0; i < fileBuffers.length; i++) {\n let relPath = relativePaths[i] || fileBuffers[i].filename || `file_${i}`\n const segments = relPath.split('/')\n if (segments.length > 1) {\n relPath = segments.slice(1).join('/')\n }\n const targetPath = path.resolve(tmpDir, relPath)\n if (!targetPath.startsWith(tmpDir + path.sep)) continue\n fs.mkdirSync(path.dirname(targetPath), { recursive: true })\n fs.writeFileSync(targetPath, fileBuffers[i].data)\n }\n\n const entryPath = findEntryFileInDirectory(tmpDir)\n if (!entryPath) {\n return reply.code(400).send({ error: 'No recognizable import format found in directory' })\n }\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n function sendEvent(event: string, eventData: unknown) {\n reply.raw.write(`event: ${event}\\ndata: ${JSON.stringify(eventData)}\\n\\n`)\n }\n\n const nativeBinding = resolveNativeBinding()\n const result = await runAutoImport(entryPath, {\n sessionGapThreshold,\n nativeBinding,\n onProgress: (p) => sendEvent('progress', p),\n })\n\n if (result.success) {\n sendEvent('done', result)\n } else {\n sendEvent('error', result)\n }\n } catch (err) {\n if (!reply.raw.headersSent) {\n return reply.code(500).send({ error: err instanceof Error ? err.message : String(err) })\n }\n reply.raw.write(\n `event: error\\ndata: ${JSON.stringify({ success: false, error: err instanceof Error ? err.message : String(err) })}\\n\\n`\n )\n } finally {\n reply.raw.end()\n cleanupTemp(tmpDir)\n }\n })\n\n // ==================== Incremental Import ====================\n\n server.post<{ Params: { id: string } }>('/_web/sessions/:id/import/incremental', async (request, reply) => {\n const sessionId = request.params.id\n const data = await (request as any).file()\n if (!data) return reply.code(400).send({ error: 'No file uploaded' })\n\n const tmpDir = createChatLabTempDir('imports', 'incremental-')\n const tmpPath = path.join(tmpDir, data.filename || 'upload')\n\n const chunks: Buffer[] = []\n for await (const chunk of data.file) {\n chunks.push(chunk)\n }\n fs.writeFileSync(tmpPath, Buffer.concat(chunks))\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n function sendEvent(event: string, eventData: unknown) {\n reply.raw.write(`event: ${event}\\ndata: ${JSON.stringify(eventData)}\\n\\n`)\n }\n\n try {\n const result = await incrementalImport(dbManager, sessionId, tmpPath, {\n onProgress: (p) => sendEvent('progress', p),\n })\n\n if (result.success) {\n sendEvent('done', result)\n } else {\n sendEvent('error', { success: false, error: result.error })\n }\n } catch (err) {\n sendEvent('error', { success: false, error: err instanceof Error ? err.message : String(err) })\n } finally {\n reply.raw.end()\n cleanupTemp(tmpPath, tmpDir)\n }\n })\n\n server.post<{ Params: { id: string } }>('/_web/sessions/:id/import/incremental/analyze', async (request, reply) => {\n const sessionId = request.params.id\n const data = await (request as any).file()\n if (!data) return reply.code(400).send({ error: 'No file uploaded' })\n\n const tmpDir = createChatLabTempDir('imports', 'analyze-')\n const tmpPath = path.join(tmpDir, data.filename || 'upload')\n\n const chunks: Buffer[] = []\n for await (const chunk of data.file) {\n chunks.push(chunk)\n }\n fs.writeFileSync(tmpPath, Buffer.concat(chunks))\n\n try {\n return await analyzeIncrementalImport(dbManager, sessionId, tmpPath)\n } catch (err) {\n return reply.code(500).send({ error: err instanceof Error ? err.message : String(err) })\n } finally {\n cleanupTemp(tmpPath, tmpDir)\n }\n })\n\n // ==================== Analyze New Import (dry-run) ====================\n\n server.post('/_web/import/analyze', async (request, reply) => {\n const data = await (request as any).file()\n if (!data) return reply.code(400).send({ error: 'No file uploaded' })\n\n const tmpDir = createChatLabTempDir('imports', 'analyze-')\n const tmpPath = path.join(tmpDir, data.filename || 'upload')\n\n const chunks: Buffer[] = []\n for await (const chunk of data.file) {\n chunks.push(chunk)\n }\n fs.writeFileSync(tmpPath, Buffer.concat(chunks))\n\n try {\n return await analyzeNewImport(tmpPath)\n } catch (err) {\n return reply.code(500).send({ error: err instanceof Error ? err.message : String(err) })\n } finally {\n cleanupTemp(tmpPath, tmpDir)\n }\n })\n\n // ==================== Demo Import ====================\n\n server.post<{ Body: { locale?: string; timeZone?: string; sessionGapThreshold?: number } }>(\n '/_web/demo/import',\n async (request, reply) => {\n const locale = request.body?.locale === 'cn' ? 'cn' : 'en'\n const targetTimeZone = typeof request.body?.timeZone === 'string' ? request.body.timeZone : undefined\n const sessionGapThreshold = parseOptionalInteger(request.body?.sessionGapThreshold)\n const nativeBinding = resolveNativeBinding()\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n function sendEvent(event: string, eventData: unknown) {\n reply.raw.write(`event: ${event}\\ndata: ${JSON.stringify(eventData)}\\n\\n`)\n }\n\n const result = await importDemoSessions({\n locale,\n tempPrefix: 'cli-demo-',\n targetTimeZone,\n importFile: (filePath) => streamImport(dbManager, filePath, { nativeBinding, sessionGapThreshold }),\n deleteSession: (sessionId) => {\n dbManager.deleteSessionDatabaseFiles(sessionId)\n },\n onProgress: (progress) => sendEvent('progress', progress),\n })\n sendEvent('result', result)\n reply.raw.end()\n }\n )\n}\n","/**\n * Shared helpers for web route modules.\n */\n\nimport * as fs from 'fs'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport { resolveCliPath } from '../../../paths'\n\nexport function resolveNativeBinding(): string | undefined {\n if (process.versions.electron) return undefined\n const nativePath = resolveCliPath('native/better_sqlite3.node')\n if (fs.existsSync(nativePath)) return nativePath\n return undefined\n}\n\nexport function getAiDataDir(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","/**\n * CLI-specific shell helpers for cache routes.\n *\n * Route registration has been migrated to packages/http-routes (shared).\n * Only the platform-specific openDirectoryPath / showPathInFolder functions\n * remain here, injected into HttpRouteContext by the CLI web-route initializer.\n */\nimport * as path from 'path'\nimport { execFile } from 'child_process'\n\ntype ExecFileRunner = (file: string, args: string[], callback: (error: Error | null) => void) => unknown\n\nfunction runExecFile(file: string, args: string[], runner: ExecFileRunner = execFile): Promise<void> {\n return new Promise((resolve, reject) => {\n runner(file, args, (error) => {\n if (error) {\n reject(error)\n return\n }\n resolve()\n })\n })\n}\n\nexport async function openDirectoryPath(\n dirPath: string,\n platform: NodeJS.Platform = process.platform,\n runner?: ExecFileRunner\n): Promise<void> {\n if (platform === 'darwin') {\n await runExecFile('open', [dirPath], runner)\n } else if (platform === 'win32') {\n await runExecFile('explorer.exe', [dirPath], runner)\n } else {\n await runExecFile('xdg-open', [dirPath], runner)\n }\n}\n\nexport async function showPathInFolder(\n filePath: string,\n platform: NodeJS.Platform = process.platform,\n runner?: ExecFileRunner\n): Promise<void> {\n if (platform === 'darwin') {\n await runExecFile('open', ['-R', filePath], runner)\n } else if (platform === 'win32') {\n await runExecFile('explorer.exe', [`/select,${filePath}`], runner)\n } else {\n await runExecFile('xdg-open', [path.dirname(filePath)], runner)\n }\n}\n","import { isNewerStableVersion } from '@openchatlab/core'\n\nexport interface WebUpdateCheckResult {\n hasUpdate: boolean\n currentVersion: string\n latestVersion?: string\n}\n\nfunction isDevelopmentPlaceholderVersion(version: string): boolean {\n return /^0\\.0\\.0(?:$|-)/.test(version.trim())\n}\n\nexport function buildWebUpdateCheckResult(options: {\n currentVersion: string\n latestVersion?: string | null\n}): WebUpdateCheckResult {\n const latestVersion = options.latestVersion || options.currentVersion\n return {\n hasUpdate:\n !isDevelopmentPlaceholderVersion(options.currentVersion) &&\n isNewerStableVersion(latestVersion, options.currentVersion),\n currentVersion: options.currentVersion,\n latestVersion,\n }\n}\n","/**\n * 反向代理路由 — /_proxy/chatlab.fun/*\n *\n * 在 Web 生产模式(clb web)下,将 /_proxy/chatlab.fun/* 代理到\n * https://chatlab.fun,行为与 vite.cli-web.config.mts 中的 dev proxy 保持一致,\n * 以解决浏览器 CORS 限制。\n *\n * 目标 host 硬编码为 https://chatlab.fun,不允许外部指定,避免开放代理风险。\n */\n\nimport type { FastifyInstance } from 'fastify'\n\nconst PROXY_TARGET = 'https://chatlab.fun'\n\nexport function registerProxyRoutes(server: FastifyInstance): void {\n server.get<{ Params: { '*': string } }>('/_proxy/chatlab.fun/*', async (request, reply) => {\n const subPath = request.params['*'] ?? ''\n const queryString = new URLSearchParams(request.query as Record<string, string>).toString()\n const targetUrl = queryString ? `${PROXY_TARGET}/${subPath}?${queryString}` : `${PROXY_TARGET}/${subPath}`\n\n try {\n const upstream = await fetch(targetUrl, {\n headers: { Accept: request.headers.accept ?? '*/*' },\n signal: AbortSignal.timeout(10_000),\n })\n\n const contentType = upstream.headers.get('content-type') ?? 'application/octet-stream'\n const body = Buffer.from(await upstream.arrayBuffer())\n\n reply.code(upstream.status).header('content-type', contentType).send(body)\n } catch (err) {\n reply.code(502).send({\n error: 'Proxy error',\n message: err instanceof Error ? err.message : String(err),\n })\n }\n })\n}\n","/**\n * @openchatlab/sync — Shared type definitions\n *\n * Platform-agnostic types used by config manager, data source manager,\n * pull engine, and scheduler.\n */\n\n// ==================== API Server Config ====================\n\nexport interface ApiServerConfig {\n enabled: boolean\n port: number\n token: string\n createdAt: number\n}\n\n// ==================== Data Source / Import Session ====================\n\nexport interface ImportSession {\n id: string\n name: string\n remoteSessionId: string\n targetSessionId: string\n lastPullAt: number\n lastStatus: 'idle' | 'success' | 'error'\n lastError: string\n lastNewMessages: number\n}\n\nexport interface DataSource {\n id: string\n name: string\n baseUrl: string\n token: string\n intervalMinutes: number\n pullLimit: number\n enabled: boolean\n createdAt: number\n sessions: ImportSession[]\n}\n\nexport type DataSourceUpdatable = Partial<\n Pick<DataSource, 'name' | 'baseUrl' | 'token' | 'intervalMinutes' | 'pullLimit' | 'enabled'>\n>\n\n// ==================== Remote Discovery ====================\n\nexport interface RemoteSession {\n id: string\n name: string\n platform: string\n type: string\n messageCount?: number\n memberCount?: number\n lastMessageAt?: number\n}\n\nexport interface RemoteSessionDiscoveryPage {\n hasMore: boolean\n nextCursor?: string\n}\n\nexport interface RemoteSessionDiscoveryResult {\n sessions: RemoteSession[]\n page?: RemoteSessionDiscoveryPage\n}\n\nexport interface RemoteSessionDiscoveryQuery {\n keyword?: string\n limit?: number\n cursor?: string\n}\n\n// ==================== Pull Engine Abstractions ====================\n\nexport interface FetchParams {\n since?: number\n offset?: number\n end?: number\n limit?: number\n}\n\nexport interface SyncMeta {\n hasMore: boolean\n nextSince?: number\n nextOffset?: number\n watermark?: number\n}\n\nexport interface ImportResult {\n success: boolean\n newMessageCount: number\n sessionId?: string\n error?: string\n needFullResync?: boolean\n /** The source page was not imported and should be retried without advancing the pull cursor. */\n retryable?: boolean\n}\n\nexport interface PullSessionResult {\n success: boolean\n newMessageCount: number\n error?: string\n sourceUnavailable?: boolean\n}\n\nexport interface PullProgress {\n sessionId: string\n sessionName: string\n current: number\n pages: number\n done: boolean\n}\n\n/**\n * Downloads remote data to a temporary file.\n * Platform implementations: Electron uses `net.request`, Node.js uses `fetch`.\n */\nexport interface HttpFetcher {\n fetchToTempFile(baseUrl: string, remoteSessionId: string, token: string, params: FetchParams): Promise<string>\n}\n\n/**\n * Imports a downloaded temp file into a local session database.\n * Platform implementations: Electron uses worker IPC, Server uses DatabaseManager.\n */\nexport interface DataImporter {\n /**\n * Import temp file into an existing or new local session.\n * If `targetSessionId` is provided, attempt incremental import.\n * Otherwise, create a new session (using `externalId` for deterministic naming).\n */\n importFile(tempFile: string, targetSessionId: string | undefined, externalId: string): Promise<ImportResult>\n\n /** Check if a local session database exists */\n sessionExists(sessionId: string): boolean\n}\n\n/**\n * Notifies the UI about sync events.\n * Electron uses BrowserWindow.webContents.send, Server can use SSE or noop.\n */\nexport interface SyncNotifier {\n onSessionListChanged(): void\n onPullResult(sourceId: string, sessionId: string | undefined, status: 'success' | 'error', detail: string): void\n}\n\nexport interface SyncLogger {\n info(message: string): void\n warn(message: string): void\n error(message: string, err?: unknown): void\n}\n\nconst noop = () => {}\n\nexport const NOOP_LOGGER: SyncLogger = { info: noop, warn: noop, error: noop }\n","/**\n * @openchatlab/sync — Data source configuration manager\n *\n * Extracted from electron/main/api/dataSource.ts.\n * Parameterized by `configDir` so it works in both Electron and CLI.\n *\n * DataSource (remote server) → ImportSession[] (subscribed conversations)\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as crypto from 'crypto'\nimport { NOOP_LOGGER } from './types'\nimport type { DataSource, DataSourceUpdatable, ImportSession, SyncLogger } from './types'\n\nconst CONFIG_FILE = 'data-sources.json'\n\nfunction generateId(prefix: string = 'ds'): string {\n return `${prefix}_${crypto.randomBytes(6).toString('hex')}`\n}\n\nexport function normalizeBaseUrl(input: string): string {\n let url = input.trim().replace(/\\/+$/, '')\n if (url && !/^https?:\\/\\//i.test(url)) {\n url = `http://${url}`\n }\n if (url && !url.endsWith('/api/v1')) {\n url = url.replace(/\\/api\\/v1$/, '') + '/api/v1'\n }\n return url\n}\n\nfunction isValidDataSourceArray(data: unknown): data is DataSource[] {\n if (!Array.isArray(data)) return false\n return data.every((item) => item && typeof item === 'object' && Array.isArray((item as any).sessions))\n}\n\nexport class DataSourceManager {\n private configDir: string\n private logger: SyncLogger\n\n constructor(configDir: string, logger?: SyncLogger) {\n this.configDir = configDir\n this.logger = logger ?? NOOP_LOGGER\n }\n\n private getConfigPath(): string {\n return path.join(this.configDir, CONFIG_FILE)\n }\n\n private ensureDir(): void {\n fs.mkdirSync(this.configDir, { recursive: true })\n }\n\n // ==================== Load / Save ====================\n\n loadAll(): DataSource[] {\n try {\n const filePath = this.getConfigPath()\n if (fs.existsSync(filePath)) {\n const raw = fs.readFileSync(filePath, 'utf-8')\n const parsed = JSON.parse(raw)\n\n if (!isValidDataSourceArray(parsed)) {\n this.logger.warn('[DataSource] Incompatible config format detected, returning empty.')\n return []\n }\n\n for (const ds of parsed) {\n if (!ds.pullLimit) ds.pullLimit = 1000\n }\n return parsed\n }\n } catch (err) {\n this.logger.error('[DataSource] Failed to load config', err)\n }\n return []\n }\n\n private saveAll(sources: DataSource[]): void {\n try {\n this.ensureDir()\n fs.writeFileSync(this.getConfigPath(), JSON.stringify(sources, null, 2), 'utf-8')\n } catch (err) {\n this.logger.error('[DataSource] Failed to save config', err)\n }\n }\n\n // ==================== DataSource CRUD ====================\n\n get(id: string): DataSource | null {\n return this.loadAll().find((s) => s.id === id) || null\n }\n\n add(partial: {\n name?: string\n baseUrl: string\n token: string\n intervalMinutes: number\n pullLimit?: number\n }): DataSource {\n const sources = this.loadAll()\n const ds: DataSource = {\n id: generateId('src'),\n name: partial.name || '',\n baseUrl: normalizeBaseUrl(partial.baseUrl),\n token: partial.token,\n intervalMinutes: partial.intervalMinutes,\n pullLimit: partial.pullLimit || 1000,\n enabled: true,\n createdAt: Math.floor(Date.now() / 1000),\n sessions: [],\n }\n sources.push(ds)\n this.saveAll(sources)\n return ds\n }\n\n update(id: string, updates: DataSourceUpdatable): DataSource | null {\n const sources = this.loadAll()\n const idx = sources.findIndex((s) => s.id === id)\n if (idx === -1) return null\n const ds = sources[idx]\n if (updates.name !== undefined) ds.name = updates.name\n if (updates.baseUrl !== undefined) ds.baseUrl = normalizeBaseUrl(updates.baseUrl)\n if (updates.token !== undefined) ds.token = updates.token\n if (updates.intervalMinutes !== undefined) ds.intervalMinutes = updates.intervalMinutes\n if (updates.pullLimit !== undefined) ds.pullLimit = updates.pullLimit\n if (updates.enabled !== undefined) ds.enabled = updates.enabled\n this.saveAll(sources)\n return ds\n }\n\n delete(id: string): boolean {\n const sources = this.loadAll()\n const filtered = sources.filter((s) => s.id !== id)\n if (filtered.length === sources.length) return false\n this.saveAll(filtered)\n return true\n }\n\n // ==================== ImportSession CRUD ====================\n\n addSessions(sourceId: string, sessions: Array<{ name: string; remoteSessionId: string }>): ImportSession[] {\n const sources = this.loadAll()\n const ds = sources.find((s) => s.id === sourceId)\n if (!ds) return []\n\n const added: ImportSession[] = []\n for (const sess of sessions) {\n if (ds.sessions.some((s) => s.remoteSessionId === sess.remoteSessionId)) continue\n const imp: ImportSession = {\n id: generateId('sess'),\n name: sess.name,\n remoteSessionId: sess.remoteSessionId,\n targetSessionId: '',\n lastPullAt: 0,\n lastStatus: 'idle',\n lastError: '',\n lastNewMessages: 0,\n }\n ds.sessions.push(imp)\n added.push(imp)\n }\n this.saveAll(sources)\n return added\n }\n\n removeSession(sourceId: string, sessionId: string): ImportSession | null {\n const sources = this.loadAll()\n const ds = sources.find((s) => s.id === sourceId)\n if (!ds) return null\n const removed = ds.sessions.find((s) => s.id === sessionId)\n if (!removed) return null\n ds.sessions = ds.sessions.filter((s) => s.id !== sessionId)\n this.saveAll(sources)\n return removed\n }\n\n updateSession(sourceId: string, sessionId: string, updates: Partial<ImportSession>): ImportSession | null {\n const sources = this.loadAll()\n const ds = sources.find((s) => s.id === sourceId)\n if (!ds) return null\n const sess = ds.sessions.find((s) => s.id === sessionId)\n if (!sess) return null\n Object.assign(sess, updates, { id: sessionId })\n this.saveAll(sources)\n return sess\n }\n}\n","/**\n * @openchatlab/sync — Pull engine\n *\n * Core paginated pull loop extracted from electron/main/api/pullScheduler.ts.\n * All platform-specific dependencies are injected via HttpFetcher, DataImporter, and SyncNotifier.\n */\n\nimport * as fs from 'fs'\nimport * as crypto from 'crypto'\nimport { NOOP_LOGGER } from './types'\nimport type {\n DataSource,\n ImportSession,\n HttpFetcher,\n DataImporter,\n SyncNotifier,\n SyncLogger,\n FetchParams,\n SyncMeta,\n ImportResult,\n PullSessionResult,\n PullProgress,\n} from './types'\nimport type { DataSourceManager } from './data-source-manager'\n\nconst MAX_PAGES_PER_PULL = 5000\nconst PULL_OVERLAP_SECONDS = 60\nconst SOURCE_UNAVAILABLE_LOG_COOLDOWN_MS = 5 * 60 * 1000\nconst SOURCE_UNAVAILABLE_ERROR_CODES = new Set(['ECONNREFUSED', 'ENOTFOUND', 'ECONNRESET', 'ETIMEDOUT', 'ABORT_ERR'])\n\n// ==================== Helpers ====================\n\nexport function buildPullUrl(baseUrl: string, remoteSessionId: string, params: FetchParams): string {\n const base = `${baseUrl}/sessions/${remoteSessionId}/messages`\n const qs: string[] = ['format=chatlab']\n if (params.since !== undefined && params.since > 0) qs.push(`since=${params.since}`)\n if (params.offset !== undefined && params.offset > 0) qs.push(`offset=${params.offset}`)\n if (params.limit !== undefined && params.limit > 0) qs.push(`limit=${params.limit}`)\n return base + '?' + qs.join('&')\n}\n\nexport function deriveLocalSessionId(baseUrl: string, remoteSessionId: string): string {\n const hash = crypto.createHash('sha256').update(`${baseUrl}\\0${remoteSessionId}`).digest('hex').slice(0, 12)\n return `remote_${hash}`\n}\n\nexport function parseSyncFromFile(filePath: string): SyncMeta | null {\n try {\n const isJsonl = filePath.endsWith('.jsonl')\n if (isJsonl) {\n const content = fs.readFileSync(filePath, 'utf-8')\n const lines = content.trimEnd().split('\\n')\n for (let i = lines.length - 1; i >= Math.max(0, lines.length - 5); i--) {\n try {\n const obj = JSON.parse(lines[i])\n if (obj._type === 'sync') {\n return {\n hasMore: !!obj.hasMore,\n nextSince: obj.nextSince,\n nextOffset: obj.nextOffset,\n watermark: obj.watermark,\n }\n }\n } catch {\n continue\n }\n }\n return null\n }\n\n const raw = fs.readFileSync(filePath, 'utf-8')\n const parsed = JSON.parse(raw)\n if (parsed.sync && typeof parsed.sync === 'object') {\n const s = parsed.sync\n return { hasMore: !!s.hasMore, nextSince: s.nextSince, nextOffset: s.nextOffset, watermark: s.watermark }\n }\n return null\n } catch {\n return null\n }\n}\n\nfunction fileContainsMessages(filePath: string): boolean {\n try {\n if (filePath.endsWith('.jsonl')) {\n const content = fs.readFileSync(filePath, 'utf-8')\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed) continue\n try {\n const obj = JSON.parse(trimmed)\n if (obj._type === 'message') return true\n } catch {\n continue\n }\n }\n return false\n }\n\n const raw = fs.readFileSync(filePath, 'utf-8')\n const parsed = JSON.parse(raw)\n return Array.isArray(parsed.messages) && parsed.messages.length > 0\n } catch {\n return false\n }\n}\n\nfunction getMaxMessageTimestampFromFile(filePath: string): number | null {\n try {\n let maxTs: number | null = null\n const visitTimestamp = (value: unknown) => {\n const ts = typeof value === 'string' && value.trim() !== '' ? Number(value) : value\n if (typeof ts === 'number' && Number.isFinite(ts)) {\n maxTs = maxTs === null ? ts : Math.max(maxTs, ts)\n }\n }\n\n if (filePath.endsWith('.jsonl')) {\n const content = fs.readFileSync(filePath, 'utf-8')\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed) continue\n try {\n const obj = JSON.parse(trimmed)\n if (obj._type === 'message') visitTimestamp(obj.timestamp)\n } catch {\n continue\n }\n }\n return maxTs\n }\n\n const raw = fs.readFileSync(filePath, 'utf-8')\n const parsed = JSON.parse(raw)\n if (Array.isArray(parsed.messages)) {\n for (const message of parsed.messages) {\n visitTimestamp(message?.timestamp)\n }\n }\n return maxTs\n } catch {\n return null\n }\n}\n\nfunction cleanupTempFile(filePath: string): void {\n try {\n if (fs.existsSync(filePath)) fs.unlinkSync(filePath)\n } catch {\n /* ignore */\n }\n}\n\nfunction getErrorProp(error: unknown, prop: string): unknown {\n return error && typeof error === 'object' ? (error as Record<string, unknown>)[prop] : undefined\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error || 'Pull failed')\n}\n\n// 只把连接级网络错误归为数据源不可达;导入/解析/HTTP 状态码仍按单会话失败处理。\nfunction describeSourceUnavailableError(error: unknown): string | null {\n let current: unknown = error\n while (current && typeof current === 'object') {\n const code = getErrorProp(current, 'code')\n const name = getErrorProp(current, 'name')\n if (typeof code === 'string' && SOURCE_UNAVAILABLE_ERROR_CODES.has(code)) {\n const address = getErrorProp(current, 'address')\n const port = getErrorProp(current, 'port')\n if (typeof address === 'string' && (typeof port === 'number' || typeof port === 'string')) {\n return `${code} ${address}:${port}`\n }\n const host = getErrorProp(current, 'hostname') ?? getErrorProp(current, 'host')\n return typeof host === 'string' ? `${code} ${host}` : code\n }\n if (name === 'AbortError') return 'Request timeout'\n current = getErrorProp(current, 'cause')\n }\n return null\n}\n\n// ==================== Pull Engine ====================\n\nexport interface PullEngineOptions {\n fetcher: HttpFetcher\n importer: DataImporter\n notifier: SyncNotifier\n dsManager: DataSourceManager\n logger?: SyncLogger\n /** Return true when an import is already in progress for the local session (skip pull) */\n isImporting?: (sessionId: string | undefined) => boolean\n /**\n * Called after a pull session completes successfully with the local session ID.\n * Used for post-import side effects (e.g. applying the platform owner profile).\n * Errors thrown by the hook never fail the pull.\n */\n onSessionImported?: (localSessionId: string) => void\n}\n\nexport class PullEngine {\n private fetcher: HttpFetcher\n private importer: DataImporter\n private notifier: SyncNotifier\n private dsManager: DataSourceManager\n private logger: SyncLogger\n private isImporting: (sessionId: string | undefined) => boolean\n private onSessionImported?: (localSessionId: string) => void\n private pullingSourceIds = new Set<string>()\n private progressMap = new Map<string, PullProgress>()\n private sourceUnavailableLogs = new Map<string, { detail: string; lastLoggedAt: number }>()\n\n constructor(options: PullEngineOptions) {\n this.fetcher = options.fetcher\n this.importer = options.importer\n this.notifier = options.notifier\n this.dsManager = options.dsManager\n this.logger = options.logger ?? NOOP_LOGGER\n this.isImporting = options.isImporting ?? (() => false)\n this.onSessionImported = options.onSessionImported\n }\n\n getProgress(): PullProgress[] {\n return Array.from(this.progressMap.values())\n }\n\n private async importTempFile(baseUrl: string, sess: ImportSession, tempFile: string): Promise<ImportResult> {\n let targetId = sess.targetSessionId\n if (!targetId) {\n const derived = deriveLocalSessionId(baseUrl, sess.remoteSessionId)\n if (this.importer.sessionExists(derived)) {\n targetId = derived\n this.logger.info(`[Pull] Reusing existing local session ${derived} for \"${sess.name}\"`)\n }\n }\n\n const externalId = deriveLocalSessionId(baseUrl, sess.remoteSessionId)\n return this.importer.importFile(tempFile, targetId || undefined, externalId)\n }\n\n private deferRetryableImport(sess: ImportSession, error?: string): PullSessionResult {\n const errMsg = error || 'Import deferred'\n this.logger.info(`[Pull] Deferring \"${sess.name}\": ${errMsg}`)\n this.markProgressDone(sess.id)\n return { success: false, newMessageCount: 0, error: errMsg }\n }\n\n async executePullSession(sourceId: string, ds: DataSource, sess: ImportSession): Promise<PullSessionResult> {\n const currentDs = this.dsManager.get(sourceId)\n if (!currentDs || !currentDs.sessions.some((s) => s.id === sess.id)) {\n this.logger.info(`[Pull] Skipping \"${sess.name}\": session no longer exists`)\n return { success: true, newMessageCount: 0 }\n }\n\n const importStatusSessionId = sess.targetSessionId || deriveLocalSessionId(ds.baseUrl, sess.remoteSessionId)\n if (this.isImporting(importStatusSessionId)) {\n this.logger.info(`[Pull] Skipping \"${sess.name}\": import in progress`)\n return { success: false, newMessageCount: 0, error: 'Import in progress' }\n }\n\n let totalNewMessages = 0\n let since = sess.lastPullAt\n let offset: number | undefined\n let nextPullSince = sess.lastPullAt\n let pageCount = 0\n let resyncAttempted = false\n\n this.progressMap.set(sess.id, { sessionId: sess.id, sessionName: sess.name, current: 0, pages: 0, done: false })\n\n try {\n while (pageCount < MAX_PAGES_PER_PULL) {\n pageCount++\n const tempFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {\n since,\n offset,\n limit: ds.pullLimit,\n })\n\n try {\n const stat = fs.statSync(tempFile)\n this.logger.info(`[Pull] \"${sess.name}\" page ${pageCount}: fetched ${stat.size} bytes`)\n\n const sync0 = parseSyncFromFile(tempFile)\n if (stat.size < 1024) {\n if (!fileContainsMessages(tempFile) && sync0?.hasMore === false) {\n cleanupTempFile(tempFile)\n if (sync0?.nextSince !== undefined) nextPullSince = Math.max(nextPullSince, sync0.nextSince)\n const retryDelays = [2000, 3000, 5000]\n let retrySuccess = false\n let retryHasMore = false\n for (let ri = 0; ri < retryDelays.length; ri++) {\n this.logger.info(\n `[Pull] \"${sess.name}\" page ${pageCount} got empty response, retry ${ri + 1}/${retryDelays.length} after ${retryDelays[ri]}ms`\n )\n await new Promise((r) => setTimeout(r, retryDelays[ri]))\n const retryFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {\n since,\n offset,\n limit: ds.pullLimit,\n })\n const retryStat = fs.statSync(retryFile)\n this.logger.info(`[Pull] \"${sess.name}\" retry ${ri + 1}: fetched ${retryStat.size} bytes`)\n const retrySync = parseSyncFromFile(retryFile)\n if (retryStat.size < 1024 && !fileContainsMessages(retryFile) && retrySync?.hasMore === false) {\n // 空 retry 页也可能只返回服务端 watermark,跳过导入前仍要推进保存游标。\n if (retrySync.nextSince !== undefined) nextPullSince = Math.max(nextPullSince, retrySync.nextSince)\n cleanupTempFile(retryFile)\n continue\n }\n const retryMaxTs = getMaxMessageTimestampFromFile(retryFile)\n const retryResult = await this.importTempFile(ds.baseUrl, sess, retryFile)\n cleanupTempFile(retryFile)\n\n if (retryResult.needFullResync && !resyncAttempted) {\n resyncAttempted = true\n this.logger.info(`[Pull] Resetting since=0 for \"${sess.name}\" full resync`)\n since = 0\n offset = undefined\n nextPullSince = 0\n pageCount = 0\n sess.targetSessionId = ''\n sess.lastPullAt = 0\n this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: '', lastPullAt: 0 })\n retrySuccess = true\n retryHasMore = true\n break\n }\n\n if (retryResult.needFullResync) {\n const errMsg = 'Full resync failed'\n this.logger.error(`[Pull] Full resync already attempted for \"${sess.name}\", aborting`)\n this.dsManager.updateSession(sourceId, sess.id, {\n lastPullAt: Math.floor(Date.now() / 1000),\n lastStatus: 'error',\n lastError: errMsg,\n })\n this.notifier.onPullResult(sourceId, sess.id, 'error', errMsg)\n this.markProgressDone(sess.id)\n return { success: false, newMessageCount: 0, error: errMsg }\n }\n\n if (!retryResult.success) {\n if (retryResult.retryable) return this.deferRetryableImport(sess, retryResult.error)\n\n const errMsg = retryResult.error || 'Import failed'\n this.dsManager.updateSession(sourceId, sess.id, {\n lastPullAt: Math.floor(Date.now() / 1000),\n lastStatus: 'error',\n lastError: errMsg,\n })\n this.notifier.onPullResult(sourceId, sess.id, 'error', errMsg)\n this.markProgressDone(sess.id)\n return { success: false, newMessageCount: 0, error: errMsg }\n }\n\n if (retryResult.success && retryResult.sessionId && !sess.targetSessionId) {\n sess.targetSessionId = retryResult.sessionId\n this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: retryResult.sessionId })\n }\n totalNewMessages += retryResult.newMessageCount\n if (retryMaxTs !== null) nextPullSince = Math.max(nextPullSince, retryMaxTs)\n // retry 终止页也可能携带服务端 watermark,必须保存,否则下次会重复拉取尾部窗口。\n if (retrySync?.nextSince !== undefined) nextPullSince = Math.max(nextPullSince, retrySync.nextSince)\n this.progressMap.set(sess.id, {\n sessionId: sess.id,\n sessionName: sess.name,\n current: totalNewMessages,\n pages: pageCount,\n done: false,\n })\n if (retrySync?.hasMore && retrySync.nextSince !== undefined) {\n since = retrySync.nextSince\n offset = undefined\n } else if (retrySync?.hasMore && retrySync.nextOffset !== undefined) {\n offset = retrySync.nextOffset\n }\n retryHasMore = !!retrySync?.hasMore\n retrySuccess = true\n break\n }\n if (!retrySuccess) break\n if (!retryHasMore) break\n continue\n }\n }\n\n if (stat.size === 0) {\n cleanupTempFile(tempFile)\n break\n }\n\n const sync = sync0\n const maxMessageTs = getMaxMessageTimestampFromFile(tempFile)\n const result = await this.importTempFile(ds.baseUrl, sess, tempFile)\n cleanupTempFile(tempFile)\n\n if (result.needFullResync && !resyncAttempted) {\n resyncAttempted = true\n this.logger.info(`[Pull] Resetting since=0 for \"${sess.name}\" full resync`)\n since = 0\n offset = undefined\n nextPullSince = 0\n pageCount = 0\n sess.targetSessionId = ''\n sess.lastPullAt = 0\n this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: '', lastPullAt: 0 })\n continue\n }\n\n if (result.needFullResync) {\n const errMsg = 'Full resync failed'\n this.logger.error(`[Pull] Full resync already attempted for \"${sess.name}\", aborting`)\n this.dsManager.updateSession(sourceId, sess.id, {\n lastPullAt: Math.floor(Date.now() / 1000),\n lastStatus: 'error',\n lastError: errMsg,\n })\n this.notifier.onPullResult(sourceId, sess.id, 'error', errMsg)\n this.markProgressDone(sess.id)\n return { success: false, newMessageCount: 0, error: errMsg }\n }\n\n if (!result.success) {\n if (result.retryable) return this.deferRetryableImport(sess, result.error)\n\n const errMsg = result.error || 'Import failed'\n this.dsManager.updateSession(sourceId, sess.id, {\n lastPullAt: Math.floor(Date.now() / 1000),\n lastStatus: 'error',\n lastError: errMsg,\n })\n this.notifier.onPullResult(sourceId, sess.id, 'error', errMsg)\n this.markProgressDone(sess.id)\n return { success: false, newMessageCount: 0, error: errMsg }\n }\n\n if (!sess.targetSessionId && result.sessionId) {\n sess.targetSessionId = result.sessionId\n this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: result.sessionId })\n }\n\n totalNewMessages += result.newMessageCount\n if (maxMessageTs !== null) nextPullSince = Math.max(nextPullSince, maxMessageTs)\n this.progressMap.set(sess.id, {\n sessionId: sess.id,\n sessionName: sess.name,\n current: totalNewMessages,\n pages: pageCount,\n done: false,\n })\n\n if (sync?.nextSince !== undefined) nextPullSince = Math.max(nextPullSince, sync.nextSince)\n\n if (!sync || !sync.hasMore) break\n\n // 游标推进优先使用时间戳链;旧数据源只返回 nextOffset 时,继续使用 offset 续拉同一个 since 窗口。\n if (sync.nextSince !== undefined) {\n since = sync.nextSince\n offset = undefined\n } else if (sync.nextOffset !== undefined) {\n offset = sync.nextOffset\n } else {\n this.logger.warn(`[Pull] \"${sess.name}\" returned hasMore=true without nextSince or nextOffset, stopping`)\n break\n }\n } catch (importErr) {\n cleanupTempFile(tempFile)\n throw importErr\n }\n }\n\n if (pageCount >= MAX_PAGES_PER_PULL) {\n this.logger.warn(`[Pull] \"${sess.name}\" reached page limit (${MAX_PAGES_PER_PULL}), data may be incomplete`)\n }\n\n // 保留 overlap 窗口,但成功拉取未观察到更新游标时不能把已保存游标向后移动。\n const savedLastPullAt = Math.max(sess.lastPullAt, Math.max(0, nextPullSince - PULL_OVERLAP_SECONDS))\n this.dsManager.updateSession(sourceId, sess.id, {\n lastPullAt: savedLastPullAt,\n lastStatus: 'success',\n lastNewMessages: totalNewMessages,\n lastError: '',\n })\n if (totalNewMessages > 0) this.notifier.onSessionListChanged()\n this.notifier.onPullResult(sourceId, sess.id, 'success', `+${totalNewMessages} messages`)\n this.markProgressDone(sess.id)\n if (this.onSessionImported && sess.targetSessionId) {\n try {\n this.onSessionImported(sess.targetSessionId)\n } catch (hookErr) {\n this.logger.warn(`[Pull] onSessionImported hook failed for \"${sess.name}\": ${hookErr}`)\n }\n }\n return { success: true, newMessageCount: totalNewMessages }\n } catch (error: any) {\n const sourceUnavailable = describeSourceUnavailableError(error)\n const errMsg = sourceUnavailable ?? getErrorMessage(error)\n if (!sourceUnavailable) {\n this.logger.error(`[Pull] Pull failed for \"${sess.name}\": ${errMsg}`)\n }\n this.dsManager.updateSession(sourceId, sess.id, {\n lastPullAt: Math.floor(Date.now() / 1000),\n lastStatus: 'error',\n lastError: errMsg,\n })\n this.notifier.onPullResult(sourceId, sess.id, 'error', errMsg)\n this.markProgressDone(sess.id)\n return { success: false, newMessageCount: 0, error: errMsg, sourceUnavailable: !!sourceUnavailable }\n }\n }\n\n private markProgressDone(sessionId: string): void {\n const p = this.progressMap.get(sessionId)\n if (p) {\n p.done = true\n setTimeout(() => this.progressMap.delete(sessionId), 5000)\n }\n }\n\n async pullAllSessions(ds: DataSource): Promise<void> {\n if (this.pullingSourceIds.has(ds.id)) {\n this.logger.info(`[Pull] Skipping pullAllSessions for \"${ds.baseUrl}\": pull already in progress`)\n return\n }\n this.pullingSourceIds.add(ds.id)\n try {\n let sourceUnavailable = false\n for (let index = 0; index < ds.sessions.length; index++) {\n const sess = ds.sessions[index]\n const result = await this.executePullSession(ds.id, ds, sess)\n if (result.sourceUnavailable && result.error) {\n sourceUnavailable = true\n this.markRemainingSessionsSourceUnavailable(ds, index + 1, result.error)\n this.logSourceUnavailable(ds, result.error, ds.sessions.length - index)\n break\n }\n }\n if (!sourceUnavailable) this.sourceUnavailableLogs.delete(ds.id)\n } finally {\n this.pullingSourceIds.delete(ds.id)\n }\n }\n\n private markRemainingSessionsSourceUnavailable(ds: DataSource, startIndex: number, detail: string): void {\n const now = Math.floor(Date.now() / 1000)\n for (const sess of ds.sessions.slice(startIndex)) {\n this.dsManager.updateSession(ds.id, sess.id, {\n lastPullAt: now,\n lastStatus: 'error',\n lastError: detail,\n })\n this.notifier.onPullResult(ds.id, sess.id, 'error', detail)\n this.markProgressDone(sess.id)\n }\n }\n\n private logSourceUnavailable(ds: DataSource, detail: string, affectedSessions: number): void {\n const now = Date.now()\n const previous = this.sourceUnavailableLogs.get(ds.id)\n if (previous && previous.detail === detail && now - previous.lastLoggedAt < SOURCE_UNAVAILABLE_LOG_COOLDOWN_MS) {\n return\n }\n this.sourceUnavailableLogs.set(ds.id, { detail, lastLoggedAt: now })\n this.logger.warn(`[Pull] Source ${ds.baseUrl} unavailable: ${detail}, skipped ${affectedSessions} sessions`)\n }\n\n async triggerPull(sourceId: string, sessionId?: string): Promise<{ success: boolean; error?: string }> {\n const ds = this.dsManager.get(sourceId)\n if (!ds) return { success: false, error: 'Data source not found' }\n\n if (sessionId) {\n const sess = ds.sessions.find((s) => s.id === sessionId)\n if (!sess) return { success: false, error: 'Session not found' }\n const result = await this.executePullSession(sourceId, ds, sess)\n if (result.sourceUnavailable && result.error) this.logSourceUnavailable(ds, result.error, 1)\n if (result.success) this.sourceUnavailableLogs.delete(ds.id)\n return { success: result.success, error: result.error }\n }\n\n if (this.pullingSourceIds.has(sourceId)) {\n this.logger.info(`[Pull] Skipping triggerPull for source ${sourceId}: pull already in progress`)\n return { success: true }\n }\n this.pullingSourceIds.add(sourceId)\n try {\n const errors: string[] = []\n let sourceUnavailable = false\n for (let index = 0; index < ds.sessions.length; index++) {\n const sess = ds.sessions[index]\n const result = await this.executePullSession(sourceId, ds, sess)\n if (!result.success && result.error) errors.push(`${sess.name}: ${result.error}`)\n if (result.sourceUnavailable && result.error) {\n sourceUnavailable = true\n this.markRemainingSessionsSourceUnavailable(ds, index + 1, result.error)\n this.logSourceUnavailable(ds, result.error, ds.sessions.length - index)\n break\n }\n }\n if (!sourceUnavailable) this.sourceUnavailableLogs.delete(ds.id)\n if (errors.length > 0) {\n return { success: false, error: errors.join('; ') }\n }\n return { success: true }\n } finally {\n this.pullingSourceIds.delete(sourceId)\n }\n }\n\n async triggerPullAll(sourceId: string): Promise<{ success: boolean; error?: string }> {\n return this.triggerPull(sourceId)\n }\n}\n","/**\n * @openchatlab/sync — Timer-based pull scheduler\n *\n * Manages one timer per DataSource; each tick pulls all ImportSessions.\n * Pure setInterval logic, no platform dependencies.\n */\n\nimport { NOOP_LOGGER } from './types'\nimport type { DataSource, SyncLogger } from './types'\nimport type { DataSourceManager } from './data-source-manager'\nimport type { PullEngine } from './pull-engine'\n\nconst timers = new Map<string, ReturnType<typeof setInterval>>()\nlet initialized = false\n\nexport interface SchedulerOptions {\n dsManager: DataSourceManager\n pullEngine: PullEngine\n logger?: SyncLogger\n}\n\nlet _dsManager: DataSourceManager\nlet _pullEngine: PullEngine\nlet _logger: SyncLogger\n\nfunction startTimer(ds: DataSource, skipInitialPull = false): void {\n stopTimer(ds.id)\n if (!ds.enabled || ds.intervalMinutes < 1 || ds.sessions.length === 0) return\n\n const intervalMs = ds.intervalMinutes * 60 * 1000\n\n if (!skipInitialPull) {\n _pullEngine.pullAllSessions(ds).catch((err) => {\n _logger.error('[Pull] Initial pull failed', err)\n })\n }\n\n const timer = setInterval(() => {\n const current = _dsManager.loadAll().find((s) => s.id === ds.id)\n if (!current || !current.enabled || current.sessions.length === 0) {\n stopTimer(ds.id)\n return\n }\n _pullEngine.pullAllSessions(current).catch((err) => {\n _logger.error('[Pull] Scheduled pull failed', err)\n })\n }, intervalMs)\n\n timers.set(ds.id, timer)\n _logger.info(\n `[Pull] Timer started for source ${ds.baseUrl} (${ds.sessions.length} sessions, every ${ds.intervalMinutes}min)`\n )\n}\n\nexport function stopTimer(id: string): void {\n const timer = timers.get(id)\n if (timer) {\n clearInterval(timer)\n timers.delete(id)\n }\n}\n\nexport function initScheduler(options: SchedulerOptions): void {\n if (initialized) return\n initialized = true\n\n _dsManager = options.dsManager\n _pullEngine = options.pullEngine\n _logger = options.logger ?? NOOP_LOGGER\n\n const sources = _dsManager.loadAll()\n for (const ds of sources) {\n if (ds.enabled && ds.sessions.length > 0) {\n startTimer(ds)\n }\n }\n\n _logger.info(`[Pull] Initialized with ${sources.filter((s) => s.enabled).length} active sources`)\n}\n\nexport function stopAllTimers(): void {\n for (const [id] of timers) {\n stopTimer(id)\n }\n initialized = false\n _logger?.info('[Pull] All timers stopped')\n}\n\nexport function reloadTimer(dsId: string, skipInitialPull = false): void {\n stopTimer(dsId)\n const ds = _dsManager?.loadAll().find((s) => s.id === dsId)\n if (ds && ds.enabled) {\n startTimer(ds, skipInitialPull)\n }\n}\n","/**\n * Server-side implementations of @openchatlab/sync abstractions.\n *\n * NodeFetcher: uses Node.js fetch API\n * DirectImporter: uses DatabaseManager + streamImport/incrementalImport\n * NoopNotifier: placeholder (future: SSE push)\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as crypto from 'crypto'\nimport type { HttpFetcher, DataImporter, SyncNotifier, ImportResult, FetchParams, SyncLogger } from '@openchatlab/sync'\nimport { NOOP_LOGGER } from '@openchatlab/sync'\nimport { buildPullUrl } from '@openchatlab/sync'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport {\n DataDirCompatibilityError,\n getChatLabTempScopeDir,\n IMPORT_IN_PROGRESS_ERROR_KEY,\n} from '@openchatlab/node-runtime'\nimport { streamImport, incrementalImport } from '../import/stream-import'\n\nfunction getTempFilePath(ext: string): string {\n const id = crypto.randomBytes(8).toString('hex')\n return path.join(getChatLabTempScopeDir('sync'), `pull-${id}${ext}`)\n}\n\n// ==================== NodeFetcher ====================\n\nexport class NodeFetcher implements HttpFetcher {\n async fetchToTempFile(baseUrl: string, remoteSessionId: string, token: string, params: FetchParams): Promise<string> {\n const url = buildPullUrl(baseUrl, remoteSessionId, params)\n const headers: Record<string, string> = {\n Accept: 'application/json',\n }\n if (token) headers['Authorization'] = `Bearer ${token}`\n\n const response = await fetch(url, { headers, signal: AbortSignal.timeout(120_000) })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`)\n }\n\n const contentType = response.headers.get('content-type') || 'application/json'\n const isJsonl = contentType.includes('ndjson') || contentType.includes('jsonl')\n const tempFile = getTempFilePath(isJsonl ? '.jsonl' : '.json')\n\n const buffer = Buffer.from(await response.arrayBuffer())\n fs.writeFileSync(tempFile, buffer)\n return tempFile\n }\n}\n\n// ==================== DirectImporter ====================\n\nexport class DirectImporter implements DataImporter {\n private dbManager: DatabaseManager\n private logger: SyncLogger\n\n constructor(dbManager: DatabaseManager, logger?: SyncLogger) {\n this.dbManager = dbManager\n this.logger = logger ?? NOOP_LOGGER\n }\n\n sessionExists(sessionId: string): boolean {\n const dbPath = this.dbManager.getDbPath(sessionId)\n if (!fs.existsSync(dbPath)) return false\n try {\n const db = this.dbManager.openRawSessionDatabase(sessionId, { readonly: true })\n const row = db\n .prepare(\"SELECT COUNT(*) as cnt FROM sqlite_master WHERE type='table' AND name='message'\")\n .get() as { cnt: number }\n db.close()\n if (row.cnt === 0) {\n this.logger.warn(`[DirectImporter] DB file exists but has no message table: ${sessionId}, removing`)\n try {\n fs.unlinkSync(dbPath)\n } catch {\n /* ignore */\n }\n return false\n }\n return true\n } catch (error) {\n if (error instanceof DataDirCompatibilityError) throw error\n\n this.logger.warn(`[DirectImporter] Cannot validate DB file: ${sessionId}, removing`)\n try {\n fs.unlinkSync(dbPath)\n } catch {\n /* ignore */\n }\n return false\n }\n }\n\n async importFile(tempFile: string, targetSessionId: string | undefined, externalId: string): Promise<ImportResult> {\n if (targetSessionId && this.sessionExists(targetSessionId)) {\n return this.incrementalImportFile(targetSessionId, tempFile)\n }\n\n if (targetSessionId) {\n this.logger.info(`[DirectImporter] Session ${targetSessionId} not found locally, need full resync`)\n return { success: false, newMessageCount: 0, needFullResync: true }\n }\n\n return this.fullImportFile(tempFile, externalId)\n }\n\n private async incrementalImportFile(sessionId: string, tempFile: string): Promise<ImportResult> {\n try {\n this.dbManager.close(sessionId)\n const result = await incrementalImport(this.dbManager, sessionId, tempFile)\n\n if (result.success) {\n const newMessageCount = result.newMessageCount\n const duplicateCount = result.batch?.duplicateCount ?? 0\n this.logger.info(\n `[DirectImporter] Incremental OK: +${newMessageCount} messages (${duplicateCount} duplicates skipped)`\n )\n return { success: true, newMessageCount, sessionId }\n }\n\n if (result.error === 'error.session_not_found' || result.error?.includes('no such table')) {\n return { success: false, newMessageCount: 0, sessionId, needFullResync: true }\n }\n if (result.error === IMPORT_IN_PROGRESS_ERROR_KEY) {\n this.logger.info(`[DirectImporter] Incremental import deferred: another import is in progress`)\n return { success: false, newMessageCount: 0, sessionId, error: result.error, retryable: true }\n }\n\n return { success: false, newMessageCount: 0, sessionId, error: result.error }\n } catch (err: any) {\n this.logger.error(`[DirectImporter] Incremental import failed`, err)\n return { success: false, newMessageCount: 0, sessionId, error: err.message }\n }\n }\n\n private async fullImportFile(tempFile: string, externalId: string): Promise<ImportResult> {\n try {\n const result = await streamImport(this.dbManager, tempFile, { sessionId: externalId })\n\n if (result.success) {\n const newMessageCount = result.diagnostics?.messagesWritten ?? 0\n this.logger.info(`[DirectImporter] Full import OK: +${newMessageCount} messages`)\n return { success: true, newMessageCount, sessionId: result.sessionId ?? externalId }\n }\n if (result.error === IMPORT_IN_PROGRESS_ERROR_KEY) {\n this.logger.info(`[DirectImporter] Full import deferred: another import is in progress`)\n return { success: false, newMessageCount: 0, error: result.error, retryable: true }\n }\n\n return { success: false, newMessageCount: 0, error: result.error }\n } catch (err: any) {\n this.logger.error(`[DirectImporter] Full import failed`, err)\n return { success: false, newMessageCount: 0, error: err.message }\n }\n }\n}\n\n// ==================== NoopNotifier ====================\n\nconst noop = () => {}\n\nexport class NoopNotifier implements SyncNotifier {\n onSessionListChanged = noop\n onPullResult = noop\n}\n","/**\n * ChatLab Server — Sync module entry point\n *\n * Wires @openchatlab/sync with server-side implementations.\n */\n\nimport type { FastifyInstance } from 'fastify'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport { PreferencesManager, createDatabaseManagerAdapter, ownerProfileService } from '@openchatlab/node-runtime'\nimport type { PathProvider } from '@openchatlab/core'\nimport { DataSourceManager, PullEngine, initScheduler, stopAllTimers, reloadTimer, stopTimer } from '@openchatlab/sync'\nimport type { SyncLogger } from '@openchatlab/sync'\nimport { registerAutomationRoutes } from '@openchatlab/http-routes'\nimport type { AutomationRouteContext } from '@openchatlab/http-routes'\nimport { NodeFetcher, DirectImporter, NoopNotifier } from './adapters'\n\nexport interface SyncRouteContext {\n automation: AutomationRouteContext\n}\n\nconst syncLogger: SyncLogger = {\n info: (msg) => console.log(`[Sync] ${msg}`),\n warn: (msg) => console.warn(`[Sync] ${msg}`),\n error: (msg, err?) => console.error(`[Sync] ${msg}`, err ?? ''),\n}\n\nlet dsManager: DataSourceManager | null = null\nlet pullEngine: PullEngine | null = null\n\nexport function initSync(\n server: FastifyInstance,\n dbManager: DatabaseManager,\n pathProvider: PathProvider,\n serverInfo: { port: number; host: string; socket?: string; token: string }\n): void {\n const settingsDir = pathProvider.getSettingsDir()\n\n dsManager = new DataSourceManager(settingsDir, syncLogger)\n\n const fetcher = new NodeFetcher()\n const importer = new DirectImporter(dbManager, syncLogger)\n const notifier = new NoopNotifier()\n\n const sessionAdapter = createDatabaseManagerAdapter(dbManager)\n const preferences = new PreferencesManager(pathProvider.getSystemDir())\n\n pullEngine = new PullEngine({\n fetcher,\n importer,\n notifier,\n dsManager,\n logger: syncLogger,\n onSessionImported: (localSessionId) => {\n preferences.invalidateCache()\n const result = ownerProfileService.tryApplyOwnerProfile(sessionAdapter, preferences, localSessionId)\n if (result.applied) {\n syncLogger.info(`[Pull] Applied owner profile to session ${localSessionId} (owner: ${result.ownerId})`)\n }\n },\n })\n\n registerAutomationRoutes(server, {\n automation: {\n dsManager,\n pullEngine,\n serverInfo,\n deleteSessionData: (sessionId) => dbManager.deleteSessionDatabaseFiles(sessionId),\n reloadTimer,\n stopTimer,\n },\n })\n\n initScheduler({\n dsManager,\n pullEngine,\n logger: syncLogger,\n })\n}\n\nexport function cleanupSync(): void {\n stopAllTimers()\n dsManager = null\n pullEngine = null\n}\n"],"mappings":"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","names":["fs","crypto","server","path","outcome","response","server","dbManager","server","apiErr","server","server","server","server","server","server","server","server","server","stat","server","server","aiChatManager","path","server","path","server","server","server","server","fs","path","path","server","fs","path","stat","server","server","server","server","server","server","fs","path","server","dbManager","streamImport","fs","path","server","server","isTruthy","parseContactsTimeRangePreset","server","server","server","server","server","server","server","server","isTruthy","server","parseRange","isTruthy","parseInteger","server","fs","path","randomUUID","fs","stat","registerImportRoutes","server","dbManager","randomUUID","sendEvent","path","resolve","registerWebRoutes","server","dbManager","streamImport","IMPORT_IN_PROGRESS_ERROR_KEY","ImportInProgressError","registerImportRoutes","server","fs","path","normalizeBaseUrl","fs","crypto","stat","fs","path","crypto","dbManager","noop","server","dbManager","resolveNativeBinding","registerWebRoutes"]}
|