chatlab-cli 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +5 -5
  2. package/dist/{chunk-XUHPCRVT.mjs → chunk-3UBWLWXB.mjs} +2 -2
  3. package/dist/{chunk-EWCSGYVT.mjs → chunk-4U45E7TO.mjs} +2 -2
  4. package/dist/{chunk-NB4BIAYM.mjs → chunk-6GLMVWGA.mjs} +24 -15
  5. package/dist/chunk-6GLMVWGA.mjs.map +1 -0
  6. package/dist/{chunk-2AIOU3PW.mjs → chunk-6NB475AA.mjs} +12 -3
  7. package/dist/chunk-6NB475AA.mjs.map +1 -0
  8. package/dist/{chunk-FBTHZU55.mjs → chunk-AMMSVJG4.mjs} +507 -115
  9. package/dist/chunk-AMMSVJG4.mjs.map +1 -0
  10. package/dist/{chunk-3DIWXYMJ.mjs → chunk-D2XJ4Z7G.mjs} +2 -2
  11. package/dist/{chunk-EIRLEPXP.mjs → chunk-QJQJIUUS.mjs} +107 -96
  12. package/dist/chunk-QJQJIUUS.mjs.map +1 -0
  13. package/dist/chunk-VSOWNKPA.mjs +49 -0
  14. package/dist/cli.mjs +4 -3
  15. package/dist/{http-QVYJ5HER.mjs → http-R5UECMPJ.mjs} +8 -7
  16. package/dist/{import-AJKL6JPR.mjs → import-3LOWRXWA.mjs} +5 -4
  17. package/dist/index.mjs +8 -7
  18. package/dist/{mcp-FRF3YAN5.mjs → mcp-WBHNLED2.mjs} +8 -7
  19. package/dist/mcp-WBHNLED2.mjs.map +1 -0
  20. package/dist/{src-KOIGBZJX.mjs → src-UHM2UDRD.mjs} +3 -2
  21. package/dist/{stream-import-URGOCXUH.mjs → stream-import-V6Z7DXSW.mjs} +4 -3
  22. package/dist/stream-import-V6Z7DXSW.mjs.map +1 -0
  23. package/dist/update-checker-MQMQ6A4B.mjs +191 -0
  24. package/dist/update-checker-MQMQ6A4B.mjs.map +1 -0
  25. package/dist-web/assets/{DebugToolsPanel-dUV6pVqD.css → DebugToolsPanel-DkbsB6lr.css} +1 -1
  26. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-CxYyne-Q.js +147 -0
  27. package/dist-web/assets/{EChartWordcloud-BYLFxPAX.js → EChartWordcloud-Ubal_aYg.js} +1 -1
  28. package/dist-web/assets/{MessageExportModal-BAf68-wB.js → MessageExportModal-De5_tX6a.js} +1 -1
  29. package/dist-web/assets/{electron-CTK4NJag.js → electron-CRSL7qPM.js} +1 -1
  30. package/dist-web/assets/electron-H65bUnhW.js +1 -0
  31. package/dist-web/assets/{fetch-Ayp337Ng.js → fetch-Q-PqsiMb.js} +1 -1
  32. package/dist-web/assets/fetch-cFjLAPG2.js +1 -0
  33. package/dist-web/assets/{index-CmU6x-uJ.css → index-BE64tUWq.css} +1 -1
  34. package/dist-web/assets/index-BJUGnYn5.js +24 -0
  35. package/dist-web/assets/index-B_31fXeB.js +2 -0
  36. package/dist-web/assets/index-CbOwHYzO.css +1 -0
  37. package/dist-web/assets/index-CbQMfheg.css +1 -0
  38. package/dist-web/assets/index-DKMUn8F5.js +173 -0
  39. package/dist-web/assets/{index-Bd5r2oFG.js → index-D_ksezTw.js} +4 -4
  40. package/dist-web/assets/index-Dhg3SDb6.js +7 -0
  41. package/dist-web/assets/logo-DXIuG_WE.svg +17 -0
  42. package/dist-web/assets/{vendor-echarts-C13vDgZW.js → vendor-echarts-C5u62NnM.js} +1 -1
  43. package/dist-web/assets/{vendor-echarts-wordcloud-uVdwYsYa.js → vendor-echarts-wordcloud-CZ9gsX8l.js} +1 -1
  44. package/dist-web/assets/{vendor-nuxt-ui-CYMNNdeD.js → vendor-nuxt-ui-7OAuiz_i.js} +1 -1
  45. package/dist-web/assets/{vendor-zrender-5DcYjSZk.js → vendor-zrender-DFl4U2Oe.js} +1 -1
  46. package/dist-web/assets/{web-C5yfcwjn.js → web-CZe0Ismu.js} +1 -1
  47. package/dist-web/index.html +3 -3
  48. package/package.json +4 -9
  49. package/dist/chunk-2AIOU3PW.mjs.map +0 -1
  50. package/dist/chunk-EIRLEPXP.mjs.map +0 -1
  51. package/dist/chunk-FBTHZU55.mjs.map +0 -1
  52. package/dist/chunk-NB4BIAYM.mjs.map +0 -1
  53. package/dist/mcp-FRF3YAN5.mjs.map +0 -1
  54. package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-DFN1Co1H.js +0 -155
  55. package/dist-web/assets/electron-BHjOx6B6.js +0 -1
  56. package/dist-web/assets/fetch-BWtpQwBZ.js +0 -1
  57. package/dist-web/assets/index-BfZM-q0T.js +0 -7
  58. package/dist-web/assets/index-CLGv8Den.css +0 -1
  59. package/dist-web/assets/index-CLYHD_f4.js +0 -2
  60. package/dist-web/assets/index-CaTRpNBK.js +0 -16
  61. package/dist-web/assets/index-CzR1sElx.css +0 -1
  62. package/dist-web/assets/index-Ksa--o23.js +0 -173
  63. /package/dist/{chunk-XUHPCRVT.mjs.map → chunk-3UBWLWXB.mjs.map} +0 -0
  64. /package/dist/{chunk-EWCSGYVT.mjs.map → chunk-4U45E7TO.mjs.map} +0 -0
  65. /package/dist/{chunk-3DIWXYMJ.mjs.map → chunk-D2XJ4Z7G.mjs.map} +0 -0
  66. /package/dist/{http-QVYJ5HER.mjs.map → chunk-VSOWNKPA.mjs.map} +0 -0
  67. /package/dist/{import-AJKL6JPR.mjs.map → http-R5UECMPJ.mjs.map} +0 -0
  68. /package/dist/{src-KOIGBZJX.mjs.map → import-3LOWRXWA.mjs.map} +0 -0
  69. /package/dist/{stream-import-URGOCXUH.mjs.map → src-UHM2UDRD.mjs.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/http/index.ts","../src/http/server.ts","../src/http/auth.ts","../src/http/errors.ts","../src/http/routes/system.ts","../src/http/routes/sessions.ts","../src/http/routes/web/index.ts","../src/merger/merge-cache.ts","../src/http/routes/web/sessions.ts","../src/http/routes/web/members.ts","../src/http/routes/web/helpers.ts","../src/http/routes/web/analytics.ts","../src/http/routes/web/sql.ts","../src/http/routes/web/session-index.ts","../src/ai/llm-config.ts","../src/http/routes/web/summaries.ts","../src/http/routes/web/import.ts","../src/http/routes/web/merge.ts","../src/http/routes/web/export.ts","../src/http/routes/web/cache.ts","../src/http/routes/nlp.ts","../src/http/routes/ai.ts","../src/ai/logger.ts","../src/ai/tool-adapter.ts","../src/ai/assistant-loader.ts","../src/ai/manager-factory.ts","../src/ai/agent.ts","../src/ai/custom-store.ts","../src/http/routes/preferences.ts","../../../packages/sync/src/types.ts","../../../packages/sync/src/data-source-manager.ts","../../../packages/sync/src/discovery.ts","../../../packages/sync/src/pull-engine.ts","../../../packages/sync/src/scheduler.ts","../src/sync/adapters.ts","../src/sync/routes.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 path from 'path'\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 AIConversationManager,\n hasPendingElectronDataWarning,\n verifyCliDataPath,\n} from '@openchatlab/node-runtime'\nimport { createServer } from './server'\nimport { setAuthToken, setWebMode } from './auth'\nimport { registerSystemRoutes } from './routes/system'\nimport { registerSessionRoutes } from './routes/sessions'\nimport { registerWebRoutes } from './routes/web'\nimport { registerNlpRoutes } from './routes/nlp'\nimport { registerAiRoutes } from './routes/ai'\nimport { registerPreferencesRoutes } from './routes/preferences'\nimport { initServerAiLogger, closeServerAiLogger } from '../ai/logger'\nimport { initSync, cleanupSync } from '../sync'\n\nlet server: FastifyInstance | null = null\nlet dbManager: DatabaseManager | null = null\nlet convManager: AIConversationManager | null = null\n\nexport interface HttpServerOptions {\n port?: number\n host?: string\n token?: string\n /** dist-web/ 目录路径,启用后托管 Web SPA 静态资源 */\n webRoot?: string\n}\n\nfunction resolveNativeBinding(): string | undefined {\n if (process.versions.electron) return undefined\n const nativePath = path.resolve(__dirname, '../../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 token: string\n}> {\n if (server) {\n throw new Error('HTTP server is already running')\n }\n\n const config = loadConfig()\n const port = options?.port ?? config.api.port\n const host = options?.host ?? config.api.host\n const token = options?.token ?? ensureToken(config)\n\n const userDataDir = config.data.user_data_dir || undefined\n const pathProvider = new NodePathProvider(userDataDir)\n pathProvider.ensureAllDirs()\n\n if (hasPendingElectronDataWarning() || !verifyCliDataPath(pathProvider.getDatabaseDir())) {\n throw new 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 })\n convManager = new AIConversationManager(pathProvider.getAiDataDir(), { nativeBinding })\n\n initServerAiLogger(pathProvider.getLogsDir())\n\n setAuthToken(token)\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 registerSystemRoutes(server, dbManager)\n registerSessionRoutes(server, dbManager)\n registerNlpRoutes(server, dbManager)\n registerAiRoutes(server, dbManager, convManager)\n registerWebRoutes(server, dbManager, { pathProvider, nativeBinding })\n registerPreferencesRoutes(server, pathProvider)\n\n initSync(server, dbManager, pathProvider, { port, host, token })\n\n if (options?.webRoot && fs.existsSync(options.webRoot)) {\n setWebMode(true)\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 await server.listen({ port, host })\n\n return { 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 (convManager) {\n convManager.close()\n convManager = null\n }\n if (dbManager) {\n dbManager.closeAll()\n dbManager = null\n }\n closeServerAiLogger()\n setWebMode(false)\n server = null\n }\n}\n\nexport { createServer } from './server'\nexport { registerSystemRoutes } from './routes/system'\nexport { registerSessionRoutes } from './routes/sessions'\nexport { registerWebRoutes } from './routes/web'\nexport { registerNlpRoutes } from './routes/nlp'\nexport { registerAiRoutes } from './routes/ai'\n","/**\n * ChatLab HTTP API — Fastify server factory\n *\n * 从 electron/main/api/server.ts 迁移,完全平台无关。\n */\n\nimport Fastify, { type FastifyInstance, type FastifyError } from 'fastify'\nimport { authHook } from './auth'\nimport { ApiError, ApiErrorCode, errorResponse, serverError } from './errors'\n\nconst JSON_BODY_LIMIT = 50 * 1024 * 1024 // 50MB\n\nexport function createServer(): FastifyInstance {\n const server = Fastify({\n logger: false,\n bodyLimit: JSON_BODY_LIMIT,\n })\n\n server.addHook('onRequest', authHook)\n\n server.setErrorHandler((error: FastifyError, _request, reply) => {\n if (error instanceof ApiError) {\n reply.code(error.statusCode).send(errorResponse(error))\n return\n }\n\n if (error.statusCode === 413) {\n const bodyErr = new ApiError(ApiErrorCode.BODY_TOO_LARGE, 'Request body exceeds 50MB limit')\n reply.code(413).send(errorResponse(bodyErr))\n return\n }\n\n const statusCode = (error as any).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 const err = serverError(error.message)\n reply.code(err.statusCode).send(errorResponse(err))\n })\n\n return server\n}\n","/**\n * ChatLab HTTP API — Bearer Token authentication hook\n *\n * 从 electron/main/api/auth.ts 迁移,使用 @openchatlab/config 读取 token。\n */\n\nimport type { FastifyRequest, FastifyReply } from 'fastify'\nimport { timingSafeEqual } from 'crypto'\nimport { unauthorized, errorResponse } from './errors'\n\nlet cachedToken: string | null = null\nlet webModeEnabled = false\n\n/**\n * 设置 auth hook 使用的 token(由 server 启动时注入)\n */\nexport function setAuthToken(token: string): void {\n cachedToken = token\n}\n\n/**\n * Enable web mode: static resources and SPA paths bypass auth.\n * Only `/api/` routes remain protected.\n */\nexport function setWebMode(enabled: boolean): void {\n webModeEnabled = enabled\n}\n\nfunction safeTokenCompare(a: string, b: string): boolean {\n const bufA = Buffer.from(a)\n const bufB = Buffer.from(b)\n if (bufA.length !== bufB.length) return false\n return timingSafeEqual(bufA, bufB)\n}\n\nexport async function authHook(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n if (!cachedToken) return\n\n // /_web/ internal API: no auth required (same-origin Web UI only)\n if (request.url.startsWith('/_web/')) return\n\n // Web mode: only /api/ routes require auth; static files and SPA are public\n if (webModeEnabled && !request.url.startsWith('/api/')) return\n\n const authHeader = request.headers.authorization\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n const err = unauthorized()\n reply.code(err.statusCode).send(errorResponse(err))\n return\n }\n\n const token = authHeader.slice(7)\n\n if (!safeTokenCompare(token, cachedToken)) {\n const err = unauthorized()\n reply.code(err.statusCode).send(errorResponse(err))\n return\n }\n}\n","/**\n * ChatLab HTTP API — Error codes and factory functions\n *\n * 从 electron/main/api/errors.ts 迁移,完全平台无关。\n */\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 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.SERVER_ERROR]: 500,\n}\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 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 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: '0.0.2',\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 — 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 type { DatabaseManager } from '@openchatlab/node-runtime'\nimport { successResponse } from '../errors'\nimport { getVersion } from '../../version'\n\nexport function registerSystemRoutes(server: FastifyInstance, dbManager: DatabaseManager): void {\n server.get('/api/v1/status', async () => {\n let sessionCount = 0\n try {\n sessionCount = dbManager.listSessionIds().length\n } catch {\n // ignore\n }\n\n return successResponse({\n name: 'ChatLab API',\n version: 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: '0.0.2',\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","/**\n * ChatLab HTTP API — Session routes\n *\n * 从 electron/main/api/routes/sessions.ts 迁移。\n * 使用 DatabaseManager + @openchatlab/core 替代 workerManager。\n */\n\nimport type { FastifyInstance } from 'fastify'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport {\n getSessionInfo,\n getSessionMeta,\n getSessionOverview,\n queryMessages,\n getMembers,\n getMembersDetailed,\n getMemberActivity,\n getMessageTypeStats,\n executeReadonlySql,\n} from '@openchatlab/core'\nimport { successResponse, errorResponse, sessionNotFound, exportTooLarge, sqlExecutionError, ApiError } from '../errors'\n\nconst EXPORT_MESSAGE_LIMIT = 100_000\n\nfunction ensureDb(dbManager: DatabaseManager, sessionId: string) {\n const db = dbManager.open(sessionId)\n if (!db) throw sessionNotFound(sessionId)\n return db\n}\n\nexport function registerSessionRoutes(server: FastifyInstance, dbManager: DatabaseManager): void {\n // GET /api/v1/sessions — List all sessions\n server.get('/api/v1/sessions', async () => {\n const sessionIds = dbManager.listSessionIds()\n const sessions = sessionIds\n .map((id) => {\n const db = dbManager.open(id)\n if (!db) return null\n const info = getSessionInfo(db)\n if (!info) return null\n return {\n id,\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 }\n })\n .filter(Boolean)\n return successResponse(sessions)\n })\n\n // GET /api/v1/sessions/:id — Single session detail\n server.get<{ Params: { id: string } }>('/api/v1/sessions/:id', async (request) => {\n const db = ensureDb(dbManager, request.params.id)\n const info = getSessionInfo(db)\n if (!info) throw sessionNotFound(request.params.id)\n return successResponse({\n id: request.params.id,\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 })\n })\n\n // GET /api/v1/sessions/:id/messages — Query messages (paginated)\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 const db = ensureDb(dbManager, id)\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 = queryMessages(db, {\n keyword: keyword || undefined,\n startTs: startTime ? parseInt(startTime, 10) : undefined,\n endTs: endTime ? parseInt(endTime, 10) : undefined,\n senderId: senderId ? parseInt(senderId, 10) : undefined,\n limit,\n offset,\n })\n\n return successResponse({\n messages: result.messages,\n total: result.total,\n page,\n limit,\n totalPages: result.totalPages,\n })\n })\n\n // GET /api/v1/sessions/:id/members — Member list\n server.get<{ Params: { id: string } }>('/api/v1/sessions/:id/members', async (request) => {\n const db = ensureDb(dbManager, request.params.id)\n const members = getMembers(db)\n return successResponse(members)\n })\n\n // GET /api/v1/sessions/:id/stats/overview — Overview statistics\n server.get<{ Params: { id: string } }>('/api/v1/sessions/:id/stats/overview', async (request) => {\n const { id } = request.params\n const db = ensureDb(dbManager, id)\n\n const overview = getSessionOverview(db)\n const memberActivity = getMemberActivity(db)\n const typeDistribution = getMessageTypeStats(db)\n\n const typeMap: Record<string, number> = {}\n for (const item of typeDistribution) {\n typeMap[String(item.type)] = item.count\n }\n\n const topMembers = memberActivity.slice(0, 10).map((m) => ({\n platformId: m.platformId,\n name: m.name,\n messageCount: m.messageCount,\n percentage: m.percentage,\n }))\n\n return successResponse({\n messageCount: overview.totalMessages,\n memberCount: overview.totalMembers,\n timeRange: {\n start: overview.firstMessageTs ?? 0,\n end: overview.lastMessageTs ?? 0,\n },\n messageTypeDistribution: typeMap,\n topMembers,\n })\n })\n\n // POST /api/v1/sessions/:id/sql — Execute SQL (read-only)\n server.post<{ Params: { id: string }; Body: { sql: string } }>('/api/v1/sessions/:id/sql', async (request, reply) => {\n const { id } = request.params\n const db = ensureDb(dbManager, id)\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 = executeReadonlySql(db, sql)\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 // GET /api/v1/sessions/:id/export — Export ChatLab Format JSON\n server.get<{ Params: { id: string } }>('/api/v1/sessions/:id/export', async (request, reply) => {\n const { id } = request.params\n const db = ensureDb(dbManager, id)\n const meta = getSessionMeta(db)\n if (!meta) throw sessionNotFound(id)\n const overview = getSessionOverview(db)\n\n if (overview.totalMessages > EXPORT_MESSAGE_LIMIT) {\n const err = exportTooLarge(overview.totalMessages, EXPORT_MESSAGE_LIMIT)\n return reply.code(err.statusCode).send(errorResponse(err))\n }\n\n const members = getMembersDetailed(db)\n const allMessages = queryMessages(db, { limit: EXPORT_MESSAGE_LIMIT, offset: 0 })\n\n const chatLabFormat = {\n chatlab: {\n version: '0.0.2',\n exportedAt: Math.floor(Date.now() / 1000),\n generator: 'ChatLab API',\n },\n meta: {\n name: meta.name,\n platform: meta.platform,\n type: meta.type,\n groupId: meta.groupId || undefined,\n },\n members: members.map((m) => ({\n platformId: m.platformId,\n accountName: m.accountName || m.platformId,\n groupNickname: m.groupNickname || undefined,\n })),\n messages: allMessages.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 Internal Web API — /_web/ routes\n *\n * 供 CLI serve 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 + FTS\n * summaries – LLM summary generation\n * import – File / directory / incremental import + demo\n * merge – Merge parse / conflicts / execute\n * export – Markdown export\n * cache – 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 { DatabaseManager } from '@openchatlab/node-runtime'\nimport { createDatabaseManagerAdapter } from '@openchatlab/node-runtime'\nimport { MergeSessionCache } from '../../../merger/merge-cache'\nimport { registerSessionRoutes } from './sessions'\nimport { registerMemberRoutes } from './members'\nimport { registerAnalyticsRoutes } from './analytics'\nimport { registerSqlRoutes } from './sql'\nimport { registerSessionIndexRoutes } from './session-index'\nimport { registerSummaryRoutes } from './summaries'\nimport { registerImportRoutes } from './import'\nimport { registerMergeRoutes } from './merge'\nimport { registerExportRoutes } from './export'\nimport { registerCacheRoutes } from './cache'\n\nexport function registerWebRoutes(\n server: FastifyInstance,\n dbManager: DatabaseManager,\n options?: { pathProvider?: import('@openchatlab/core').PathProvider; nativeBinding?: string }\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 downloadsDir = options?.pathProvider?.getDownloadsDir() || path.join(os.homedir(), 'Downloads')\n\n registerSessionRoutes(server, adapter)\n registerMemberRoutes(server, adapter)\n registerAnalyticsRoutes(server, dbManager, adapter)\n registerSqlRoutes(server, adapter)\n registerSessionIndexRoutes(server, adapter)\n registerSummaryRoutes(server, dbManager, adapter)\n registerImportRoutes(server, dbManager)\n if (mergeCache) {\n registerMergeRoutes(server, dbManager, mergeCache)\n }\n registerExportRoutes(server, adapter)\n registerCacheRoutes(server, downloadsDir)\n}\n","/**\n * Server-side merge session cache.\n *\n * Manages temporary databases for the multi-file merge workflow.\n * Each uploaded/parsed file gets a temp DB handle that persists\n * across HTTP requests until merge completes or cache is cleared.\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport * as crypto from 'crypto'\nimport type { PathProvider, DatabaseAdapter } from '@openchatlab/core'\nimport {\n openBetterSqliteDatabase,\n TempDbReader,\n deleteTempDatabase,\n cleanupTempDatabases,\n} from '@openchatlab/node-runtime'\n\ninterface CacheEntry {\n tempDbPath: string\n filename: string\n createdAt: number\n}\n\nexport class MergeSessionCache {\n private cache = new Map<string, CacheEntry>()\n private tempDir: string\n private nativeBinding?: string\n\n constructor(pathProvider: PathProvider, options?: { nativeBinding?: string }) {\n this.tempDir = pathProvider.getTempDir()\n this.nativeBinding = options?.nativeBinding\n if (!fs.existsSync(this.tempDir)) {\n fs.mkdirSync(this.tempDir, { recursive: true })\n }\n }\n\n generateTempDbPath(filename: string): string {\n const ts = Date.now()\n const rand = Math.random().toString(36).slice(2, 8)\n const safeName = filename.replace(/[/\\\\?%*:|\"<>]/g, '_').slice(0, 40)\n return path.join(this.tempDir, `merge_${safeName}_${ts}_${rand}.db`)\n }\n\n /** Store a parsed file's temp DB and return a handle for subsequent requests. */\n store(filename: string, tempDbPath: string): string {\n const handle = crypto.randomUUID()\n this.cache.set(handle, { tempDbPath, filename, createdAt: Date.now() })\n return handle\n }\n\n /** Open a TempDbReader for a given handle. Caller must close the reader. */\n openReader(handle: string): { reader: TempDbReader; filename: string } | null {\n const entry = this.cache.get(handle)\n if (!entry || !fs.existsSync(entry.tempDbPath)) return null\n const adapter = openBetterSqliteDatabase(entry.tempDbPath, {\n readonly: true,\n nativeBinding: this.nativeBinding,\n })\n return { reader: new TempDbReader(adapter), filename: entry.filename }\n }\n\n /** Create a writable temp DB for streaming parse. */\n createTempDatabase(filename: string): { db: DatabaseAdapter; tempDbPath: string } {\n const tempDbPath = this.generateTempDbPath(filename)\n const adapter = openBetterSqliteDatabase(tempDbPath, { nativeBinding: this.nativeBinding })\n return { db: adapter, tempDbPath }\n }\n\n /** Remove a single entry and its temp DB file. */\n delete(handle: string): void {\n const entry = this.cache.get(handle)\n if (entry) {\n deleteTempDatabase(entry.tempDbPath)\n this.cache.delete(handle)\n }\n }\n\n /** Clear all entries and delete their temp DB files. */\n clear(): void {\n for (const entry of this.cache.values()) {\n deleteTempDatabase(entry.tempDbPath)\n }\n this.cache.clear()\n }\n\n /** Cleanup orphan temp DBs from previous runs. */\n cleanupOrphans(): void {\n cleanupTempDatabases(this.tempDir)\n }\n\n /** Auto-cleanup entries older than maxAge (default 1 hour). */\n cleanupExpired(maxAgeMs = 3600_000): void {\n const now = Date.now()\n for (const [handle, entry] of this.cache) {\n if (now - entry.createdAt > maxAgeMs) {\n deleteTempDatabase(entry.tempDbPath)\n this.cache.delete(handle)\n }\n }\n }\n}\n","import type { FastifyInstance } from 'fastify'\nimport { sessionService, type SessionRuntimeAdapter } from '@openchatlab/node-runtime'\n\nexport function registerSessionRoutes(server: FastifyInstance, adapter: SessionRuntimeAdapter): void {\n server.get('/_web/sessions', async () => {\n return sessionService.listAnalysisSessions(adapter)\n })\n\n server.get<{ Params: { id: string } }>('/_web/sessions/:id', async (request) => {\n const session = sessionService.getAnalysisSession(adapter, request.params.id)\n if (!session) {\n throw Object.assign(new Error(`Session not found: ${request.params.id}`), { statusCode: 404 })\n }\n return session\n })\n\n server.delete<{ Params: { id: string } }>('/_web/sessions/:id', async (request, reply) => {\n const { id } = request.params\n try {\n const deleted = sessionService.deleteSession(adapter, id)\n if (!deleted) {\n return reply.code(404).send({ success: false, error: 'File not found' })\n }\n return { success: true }\n } catch (err) {\n return reply.code(500).send({ success: false, error: String(err) })\n }\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 return { success: true }\n }\n )\n}\n","import type { FastifyInstance } from 'fastify'\nimport { memberService, type SessionRuntimeAdapter } from '@openchatlab/node-runtime'\n\nexport function registerMemberRoutes(server: FastifyInstance, adapter: SessionRuntimeAdapter): void {\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)\n return { success: true }\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)\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","/**\n * Shared helpers for web route modules.\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport type { TimeFilter } from '@openchatlab/shared-types'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\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\nexport function resolveNativeBinding(): string | undefined {\n if (process.versions.electron) return undefined\n const nativePath = path.resolve(__dirname, '../../../../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\nexport function ensureDb(dbManager: DatabaseManager, sessionId: string) {\n const db = dbManager.open(sessionId)\n if (!db) {\n throw Object.assign(new Error(`Session not found: ${sessionId}`), { statusCode: 404 })\n }\n return db\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport { createJiebaNlpProvider, type SessionRuntimeAdapter } 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 getRelationshipStats,\n getCatchphraseAnalysis,\n getMentionAnalysis,\n getMentionGraph,\n getLaughAnalysis,\n getClusterGraph,\n getLanguagePreferenceAnalysis,\n} from '@openchatlab/core'\nimport { parseTimeFilter } from './helpers'\n\ntype FilteredQuery = { startTs?: string; endTs?: string; memberId?: string }\n\nexport function registerAnalyticsRoutes(\n server: FastifyInstance,\n _dbManager: DatabaseManager,\n adapter: SessionRuntimeAdapter\n): void {\n // ==================== 时间范围 ====================\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 // ==================== 统计分析 ====================\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/member-activity',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getMemberActivity(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/hourly',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getHourlyActivity(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/daily',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getDailyActivity(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/weekday',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getWeekdayActivity(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/stats/message-types',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getMessageTypeStats(db, parseTimeFilter(request.query))\n }\n )\n\n // ==================== 高级分析 ====================\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/relationship',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getRelationshipStats(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/catchphrase',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getCatchphraseAnalysis(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/mention',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getMentionAnalysis(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/mention-graph',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getMentionGraph(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/laugh',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getLaughAnalysis(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery & { topEdges?: string } }>(\n '/_web/sessions/:id/analytics/cluster',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n const filter = parseTimeFilter(request.query)\n const topEdges = request.query.topEdges ? parseInt(request.query.topEdges, 10) : undefined\n return getClusterGraph(db, filter, topEdges ? { topEdges } : 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 db = adapter.ensureReadonly(request.params.id)\n const filter = parseTimeFilter(request.query)\n const locale = request.query.locale || 'zh-CN'\n const nlpProvider = createJiebaNlpProvider()\n return getLanguagePreferenceAnalysis(db, { locale, timeFilter: filter, nlpProvider })\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/monthly-activity',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getMonthlyActivity(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/yearly-activity',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getYearlyActivity(db, parseTimeFilter(request.query))\n }\n )\n\n server.get<{ Params: { id: string }; Querystring: FilteredQuery }>(\n '/_web/sessions/:id/analytics/message-length-distribution',\n async (request) => {\n const db = adapter.ensureReadonly(request.params.id)\n return getMessageLengthDistribution(db, parseTimeFilter(request.query))\n }\n )\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { SessionRuntimeAdapter } from '@openchatlab/node-runtime'\nimport { executeSql, getSchemaDetailed } from '@openchatlab/core'\n\nexport function registerSqlRoutes(server: FastifyInstance, adapter: SessionRuntimeAdapter): void {\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 return executeSql(db, sql, { timing: true })\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 { sessionIndexService, type SessionRuntimeAdapter } from '@openchatlab/node-runtime'\n\nexport function registerSessionIndexRoutes(server: FastifyInstance, adapter: SessionRuntimeAdapter): void {\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<{ Params: { id: string } }>('/_web/sessions/:id/clear-index', async (request) => {\n sessionIndexService.clearIndex(adapter, request.params.id)\n return { success: true }\n })\n\n server.get<{\n Params: { id: string }\n Querystring: { keywords: string; limit?: string; offset?: string }\n }>('/_web/sessions/:id/search/fts', async (request, reply) => {\n if (!sessionIndexService.getFtsStatus(adapter, request.params.id)) {\n return reply.code(400).send({ error: 'FTS index not built for this session' })\n }\n const keywords = request.query.keywords.split(/\\s+/).filter(Boolean)\n if (keywords.length === 0) return { rowids: [], total: 0 }\n const limit = parseInt(request.query.limit || '100', 10)\n const offset = parseInt(request.query.offset || '0', 10)\n return sessionIndexService.searchFts(adapter, request.params.id, keywords, limit, offset)\n })\n\n server.get<{ Params: { id: string } }>('/_web/sessions/:id/fts/status', async (request) => {\n return { hasFtsIndex: sessionIndexService.getFtsStatus(adapter, request.params.id) }\n })\n\n server.post<{ Params: { id: string } }>('/_web/sessions/:id/fts/rebuild', async (request) => {\n const result = sessionIndexService.rebuildFts(adapter, request.params.id)\n return { success: true, indexed: result.indexed }\n })\n}\n","/**\n * 服务端 LLM 配置加载\n *\n * API Key 从 ~/.chatlab/auth-profiles.json 读取,\n * 匹配顺序:config.authProfile 精确匹配 > config.provider 兜底匹配。\n *\n * 模型/Provider 等配置仍从 llm-config.json 读取。\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport type { PiModel, PiApi } from '@openchatlab/node-runtime'\nimport { buildPiModel as buildPiModelCore, type PiModelConfig } from '@openchatlab/node-runtime'\nimport { resolveApiKey, writeAuthProfile } from '@openchatlab/config'\nimport { randomUUID } from 'crypto'\n\n// ==================== Types ====================\n\nexport interface AIServiceConfig {\n id: string\n name: string\n provider: string\n apiKey: string\n model?: string\n baseUrl?: string\n maxTokens?: number\n apiFormat?: string\n disableThinking?: boolean\n isReasoningModel?: boolean\n authProfile?: string\n}\n\ninterface ModelSlot {\n configId: string\n modelId?: string\n}\n\ninterface AIConfigStore {\n configs: AIServiceConfig[]\n defaultAssistant: ModelSlot | null\n fastModel: ModelSlot | null\n}\n\n// ==================== Config Loading ====================\n\nexport function loadLlmConfig(aiDataDir: string): AIConfigStore {\n const configPath = path.join(aiDataDir, 'llm-config.json')\n if (!fs.existsSync(configPath)) {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\n\n try {\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n\n const configs = (data.configs || []).map((c: Record<string, unknown>) => {\n const provider = (c.provider as string) || ''\n const authProfile = c.authProfile as string | undefined\n const profileKey = resolveApiKey(provider, authProfile)\n const rawKey = (c.apiKey as string) || ''\n const fallbackKey = rawKey.startsWith('enc:') ? '' : rawKey\n return {\n ...c,\n apiKey: profileKey || fallbackKey,\n }\n })\n return {\n configs,\n defaultAssistant: data.defaultAssistant ?? null,\n fastModel: data.fastModel ?? null,\n }\n } catch {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\n}\n\nfunction resolveSlot(slot: ModelSlot | null | undefined, configs: AIServiceConfig[]): ModelSlot | null {\n if (slot && configs.some((c) => c.id === slot.configId)) return slot\n const fallback = configs[0]\n if (!fallback) return null\n return { configId: fallback.id, modelId: fallback.model }\n}\n\nexport function getDefaultAssistantConfig(aiDataDir: string): AIServiceConfig | null {\n const store = loadLlmConfig(aiDataDir)\n const slot = resolveSlot(store.defaultAssistant, store.configs)\n if (!slot) return null\n const config = store.configs.find((c) => c.id === slot.configId)\n if (!config) return null\n return { ...config, model: slot.modelId || config.model }\n}\n\n// ==================== Config Write Operations ====================\n\nconst MAX_CONFIG_COUNT = 99\n\nfunction saveLlmConfig(aiDataDir: string, store: AIConfigStore): void {\n const configPath = path.join(aiDataDir, 'llm-config.json')\n const toSave = {\n ...store,\n configs: store.configs.map((c) => {\n const { apiKey: _k, ...rest } = c\n return rest\n }),\n schemaVersion: 3,\n }\n fs.writeFileSync(configPath, JSON.stringify(toSave, null, 2), 'utf-8')\n}\n\nexport function addLlmConfig(\n aiDataDir: string,\n config: Omit<AIServiceConfig, 'id'>\n): { success: boolean; config?: AIServiceConfig; error?: string } {\n const store = loadLlmConfig(aiDataDir)\n\n if (store.configs.length >= MAX_CONFIG_COUNT) {\n return { success: false, error: `Maximum ${MAX_CONFIG_COUNT} configs reached` }\n }\n\n const newConfig: AIServiceConfig = {\n ...config,\n id: randomUUID(),\n }\n\n const storeForSave = loadRawConfigStore(aiDataDir)\n storeForSave.configs.push({\n ...newConfig,\n apiKey: '',\n })\n\n if (storeForSave.configs.length === 1) {\n storeForSave.defaultAssistant = { configId: newConfig.id, modelId: newConfig.model || '' }\n }\n\n if (config.apiKey) {\n const profileName = config.name?.toLowerCase().replace(/\\s+/g, '-') || config.provider\n writeAuthProfile(profileName, {\n type: 'api_key',\n provider: config.provider,\n key: config.apiKey,\n })\n ;(storeForSave.configs[storeForSave.configs.length - 1] as unknown as Record<string, unknown>).authProfile =\n profileName\n }\n\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true, config: { ...newConfig, apiKey: '' } }\n}\n\nexport function updateLlmConfig(\n aiDataDir: string,\n id: string,\n updates: Partial<Omit<AIServiceConfig, 'id'>>\n): { success: boolean; error?: string } {\n const storeForSave = loadRawConfigStore(aiDataDir)\n const index = storeForSave.configs.findIndex((c) => c.id === id)\n\n if (index === -1) {\n return { success: false, error: 'Config not found' }\n }\n\n const { apiKey: newApiKey, ...restUpdates } = updates\n const updated = {\n ...storeForSave.configs[index],\n ...restUpdates,\n }\n storeForSave.configs[index] = updated\n\n if (newApiKey) {\n const profileName = updated.name?.toLowerCase().replace(/\\s+/g, '-') || updated.provider\n writeAuthProfile(profileName, {\n type: 'api_key',\n provider: updated.provider,\n key: newApiKey,\n })\n ;(storeForSave.configs[index] as unknown as Record<string, unknown>).authProfile = profileName\n }\n\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true }\n}\n\nexport function deleteLlmConfig(aiDataDir: string, id: string): { success: boolean; error?: string } {\n const storeForSave = loadRawConfigStore(aiDataDir)\n const index = storeForSave.configs.findIndex((c) => c.id === id)\n\n if (index === -1) {\n return { success: false, error: 'Config not found' }\n }\n\n storeForSave.configs.splice(index, 1)\n\n const fallback = storeForSave.configs[0]\n if (storeForSave.defaultAssistant?.configId === id) {\n storeForSave.defaultAssistant = fallback ? { configId: fallback.id, modelId: fallback.model || '' } : null\n }\n if (storeForSave.fastModel?.configId === id) {\n storeForSave.fastModel = fallback ? { configId: fallback.id, modelId: fallback.model || '' } : null\n }\n\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true }\n}\n\nexport function setDefaultAssistantSlot(\n aiDataDir: string,\n configId: string,\n modelId: string\n): { success: boolean; error?: string } {\n const storeForSave = loadRawConfigStore(aiDataDir)\n const config = storeForSave.configs.find((c) => c.id === configId)\n\n if (!config) {\n return { success: false, error: 'Config not found' }\n }\n\n storeForSave.defaultAssistant = { configId, modelId }\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true }\n}\n\nexport function setFastModelSlot(aiDataDir: string, slot: ModelSlot | null): { success: boolean; error?: string } {\n const storeForSave = loadRawConfigStore(aiDataDir)\n\n if (slot !== null) {\n const config = storeForSave.configs.find((c) => c.id === slot.configId)\n if (!config) {\n return { success: false, error: 'Config not found' }\n }\n }\n\n storeForSave.fastModel = slot\n saveLlmConfig(aiDataDir, storeForSave)\n return { success: true }\n}\n\nfunction loadRawConfigStore(aiDataDir: string): AIConfigStore {\n const configPath = path.join(aiDataDir, 'llm-config.json')\n if (!fs.existsSync(configPath)) {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\n try {\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n return {\n configs: data.configs || [],\n defaultAssistant: data.defaultAssistant ?? null,\n fastModel: data.fastModel ?? null,\n }\n } catch {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\n}\n\n// ==================== PiModel Builder ====================\n\nexport function buildPiModel(config: AIServiceConfig): PiModel<PiApi> {\n return buildPiModelCore(config as PiModelConfig)\n}\n","import type { FastifyInstance } from 'fastify'\nimport type { DatabaseManager, SessionRuntimeAdapter, SummaryServiceDeps } from '@openchatlab/node-runtime'\nimport { summaryService } from '@openchatlab/node-runtime'\nimport { getAiDataDir } from './helpers'\nimport { getDefaultAssistantConfig, buildPiModel } from '../../../ai/llm-config'\n\nfunction createSummaryDeps(dbManager: DatabaseManager): SummaryServiceDeps {\n const aiDataDir = getAiDataDir(dbManager)\n return {\n getLlmConfig() {\n return getDefaultAssistantConfig(aiDataDir)\n },\n buildPiModel(config) {\n return buildPiModel(config as ReturnType<typeof getDefaultAssistantConfig> & object)\n },\n }\n}\n\nexport function registerSummaryRoutes(\n server: FastifyInstance,\n dbManager: DatabaseManager,\n adapter: SessionRuntimeAdapter\n): void {\n const deps = createSummaryDeps(dbManager)\n\n server.post<{\n Params: { id: string }\n Body: { chatSessionId: number; locale?: string; forceRegenerate?: boolean }\n }>('/_web/sessions/:id/summaries/generate', async (request, reply) => {\n const { chatSessionId, locale, forceRegenerate } = request.body\n const result = await summaryService.generateSummary(adapter, request.params.id, chatSessionId, deps, {\n locale,\n forceRegenerate,\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","import * as fs from 'fs'\nimport * as os from 'os'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport {\n streamImport,\n incrementalImport,\n analyzeIncrementalImport,\n analyzeNewImport,\n detectFormat,\n detectAllFormats,\n getSupportedFormats,\n scanMultiChatFile,\n findEntryFileInDirectory,\n} from '../../../import'\nimport { resolveNativeBinding } from './helpers'\n\nconst DEMO_BASE_URL = 'https://chatlab.fun/assets/demo'\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(server: FastifyInstance, dbManager: DatabaseManager): void {\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 = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-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 = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-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 = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-import-'))\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\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 streamImport(dbManager, tmpPath, {\n formatId,\n chatIndex,\n nativeBinding,\n onProgress: (p) => sendEvent('progress', p),\n })\n\n if (result.success) {\n sendEvent('done', {\n success: true,\n sessionId: result.sessionId,\n messageCount: result.diagnostics?.messagesWritten ?? 0,\n memberCount: 0,\n })\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 // ==================== 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 = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-dir-import-'))\n const relativePaths: string[] = []\n const fileBuffers: { data: Buffer; filename: string }[] = []\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 === '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 streamImport(dbManager, entryPath, {\n nativeBinding,\n onProgress: (p) => sendEvent('progress', p),\n })\n\n if (result.success) {\n sendEvent('done', {\n success: true,\n sessionId: result.sessionId,\n messageCount: result.diagnostics?.messagesWritten ?? 0,\n memberCount: 0,\n })\n } else {\n sendEvent('error', { success: false, error: result.error })\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 = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-inc-'))\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 = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-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 = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-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 } }>('/_web/demo/import', async (request, reply) => {\n const locale = (request.body as any)?.locale || 'en'\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 tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-demo-'))\n const groupPath = path.join(tmpDir, 'demo-group.json')\n const privatePath = path.join(tmpDir, 'demo-private.json')\n\n try {\n sendEvent('progress', { stage: 'downloading', current: 1, total: 2 })\n const groupResp = await fetch(`${DEMO_BASE_URL}/${locale}/demo-group.json`, {\n signal: AbortSignal.timeout(60_000),\n })\n if (!groupResp.ok) throw new Error(`Download group demo failed: ${groupResp.status}`)\n fs.writeFileSync(groupPath, Buffer.from(await groupResp.arrayBuffer()))\n\n sendEvent('progress', { stage: 'downloading', current: 2, total: 2 })\n const privateResp = await fetch(`${DEMO_BASE_URL}/${locale}/demo-private.json`, {\n signal: AbortSignal.timeout(60_000),\n })\n if (!privateResp.ok) throw new Error(`Download private demo failed: ${privateResp.status}`)\n fs.writeFileSync(privatePath, Buffer.from(await privateResp.arrayBuffer()))\n\n sendEvent('progress', { stage: 'importing', current: 1, total: 2 })\n const groupResult = await streamImport(dbManager, groupPath, { nativeBinding })\n if (!groupResult.success) throw new Error(groupResult.error || 'Failed to import group demo')\n\n sendEvent('progress', { stage: 'importing', current: 2, total: 2 })\n const privateResult = await streamImport(dbManager, privatePath, { nativeBinding })\n if (!privateResult.success) throw new Error(privateResult.error || 'Failed to import private demo')\n\n sendEvent('progress', { stage: 'done', current: 2, total: 2 })\n sendEvent('result', {\n success: true,\n groupSessionId: groupResult.sessionId,\n privateSessionId: privateResult.sessionId,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n sendEvent('progress', { stage: 'error', current: 0, total: 2, message })\n sendEvent('result', { success: false, error: message })\n } finally {\n reply.raw.end()\n cleanupTemp(tmpDir)\n }\n })\n}\n","import * as fs from 'fs'\nimport * as os from 'os'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\nimport {\n streamParseFileInfo,\n checkConflictsFromSources,\n buildMergedOutput,\n serializeChatLabToJsonl,\n exportSessionToJson,\n TempDbReader,\n} from '@openchatlab/node-runtime'\nimport { MergeSessionCache } from '../../../merger/merge-cache'\nimport { ensureDb } from './helpers'\n\nexport function registerMergeRoutes(\n server: FastifyInstance,\n dbManager: DatabaseManager,\n mergeCache: MergeSessionCache\n): void {\n server.post('/_web/merge/parse', 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 = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-merge-'))\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 const result = await streamParseFileInfo(tmpPath, {\n createTempDatabase(sourceFilePath: string) {\n return mergeCache.createTempDatabase(path.basename(sourceFilePath))\n },\n onProgress() {\n /* no-op for HTTP merge parse */\n },\n })\n\n const handle = mergeCache.store(data.filename || 'upload', 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 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 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: import('@openchatlab/node-runtime').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 server.post<{\n Body: { handles: string[]; outputName: string; format?: 'json' | 'jsonl'; andImport?: boolean }\n }>('/_web/merge/execute', async (request, reply) => {\n const { handles, outputName, format = 'json', andImport } = request.body as any\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: import('@openchatlab/node-runtime').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 const { streamImport: serverStreamImport } = await import('../../../import/stream-import')\n const jsonData = JSON.stringify(merged.chatLabData)\n const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'chatlab-merged-'))\n const tmpPath = path.join(tmpDir, `${outputName}.json`)\n fs.writeFileSync(tmpPath, jsonData, 'utf-8')\n\n try {\n const importResult = await serverStreamImport(dbManager, tmpPath)\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 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 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(dbManager, sid)\n const exported = exportSessionToJson(db)\n const { db: tempDb, tempDbPath } = mergeCache.createTempDatabase(exported.meta.name)\n\n const { TempDbWriter } = await import('@openchatlab/node-runtime')\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 })\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 senderPlatformId: msg.sender,\n senderAccountName: msg.accountName,\n senderGroupNickname: msg.groupNickname,\n timestamp: msg.timestamp,\n type: msg.type,\n content: msg.content,\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","import type { FastifyInstance } from 'fastify'\nimport { exportService, type SessionRuntimeAdapter } from '@openchatlab/node-runtime'\n\nexport function registerExportRoutes(server: FastifyInstance, adapter: SessionRuntimeAdapter): void {\n server.post<{\n Params: { id: string }\n Body: {\n sessionName: string\n filterMode: 'condition' | 'session'\n keywords?: string[]\n timeFilter?: { startTs: number; endTs: number }\n senderIds?: number[]\n contextSize?: number\n chatSessionIds?: number[]\n }\n }>('/_web/sessions/:id/export/markdown', async (request, reply) => {\n const { id } = request.params\n const body = request.body as any\n const sessionName = body?.sessionName || id\n\n const { result, content } = exportService.exportMarkdown(adapter, {\n sessionId: id,\n sessionName,\n filterMode: body.filterMode || 'condition',\n keywords: body.keywords,\n timeFilter: body.timeFilter,\n senderIds: body.senderIds,\n contextSize: body.contextSize,\n chatSessionIds: body.chatSessionIds,\n })\n\n if (!result.success) {\n return reply.code(500).send({ error: result.error })\n }\n\n reply.header('Content-Type', 'text/markdown; charset=utf-8')\n reply.header('Content-Disposition', `attachment; filename=\"${encodeURIComponent(sessionName)}_export.md\"`)\n return reply.send(content)\n })\n}\n","import * as fs from 'fs'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\n\nexport function registerCacheRoutes(server: FastifyInstance, downloadsDir: string): void {\n server.post<{\n Body: { filename: string; dataUrl: string }\n }>('/_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 const base64Prefix = dataUrl.indexOf(',')\n const base64Data = base64Prefix >= 0 ? dataUrl.slice(base64Prefix + 1) : dataUrl\n const buffer = Buffer.from(base64Data, 'base64')\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 server.post<{\n Body: { filePath: string }\n }>('/_web/cache/show-in-folder', async (request) => {\n const { filePath } = request.body\n if (!filePath) {\n return { success: false, error: 'filePath is required' }\n }\n\n const { exec } = await import('child_process')\n const platform = process.platform\n const dir = path.dirname(filePath)\n\n if (platform === 'darwin') {\n exec(`open -R \"${filePath}\"`)\n } else if (platform === 'win32') {\n exec(`explorer /select,\"${filePath}\"`)\n } else {\n exec(`xdg-open \"${dir}\"`)\n }\n\n return { success: true }\n })\n}\n","/**\n * NLP Web API — /_web/nlp/ routes\n *\n * 提供词频统计、词性标签、词库管理等 NLP 功能的 HTTP 接口,\n * 供 CLI serve Web 前端使用(对齐 Electron preload 的 window.nlpApi)。\n *\n * 业务逻辑全部来自 @openchatlab/core(类型/数据)和\n * @openchatlab/node-runtime(分词引擎/词频计算/词库管理)。\n */\n\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { DatabaseManager } from '@openchatlab/node-runtime'\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\nfunction ensureDb(dbManager: DatabaseManager, sessionId: string) {\n const db = dbManager.open(sessionId)\n if (!db) {\n throw Object.assign(new Error(`Session not found: ${sessionId}`), { statusCode: 404 })\n }\n return db\n}\n\nexport function registerNlpRoutes(server: FastifyInstance, dbManager: DatabaseManager): void {\n const pathProvider = (dbManager as any)['pathProvider']\n if (pathProvider) {\n const nlpDir = path.join(pathProvider.getUserDataDir(), 'nlp')\n initNlpDir(nlpDir)\n ensureDefaultDict(nlpDir).catch((err) => console.warn('[NLP] Auto-download 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 const nlpDir = resolveNlpDir(dbManager)\n return getDictList(nlpDir)\n })\n\n server.get<{ Params: { id: string } }>('/_web/nlp/dicts/:id/status', async (request) => {\n const nlpDir = resolveNlpDir(dbManager)\n return isDictDownloaded(nlpDir, request.params.id)\n })\n\n server.post<{ Params: { id: string } }>('/_web/nlp/dicts/:id/download', async (request) => {\n const nlpDir = resolveNlpDir(dbManager)\n return downloadDict(nlpDir, request.params.id)\n })\n\n server.delete<{ Params: { id: string } }>('/_web/nlp/dicts/:id', async (request) => {\n const nlpDir = resolveNlpDir(dbManager)\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 = ensureDb(dbManager, params.sessionId)\n return computeWordFrequency(db, params)\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\nfunction resolveNlpDir(dbManager: DatabaseManager): string {\n const pathProvider = (dbManager as any)['pathProvider']\n return path.join(pathProvider.getUserDataDir(), 'nlp')\n}\n","/**\n * AI Web API — /_web/ai/ routes\n *\n * 提供助手、技能、LLM 配置和工具目录的只读 HTTP 接口,\n * 供 CLI serve Web 前端使用(对齐 Electron preload 的 window.*Api)。\n *\n * - 助手/技能数据来自 ~/.chatlab/ai/{assistants,skills}/*.md\n * - LLM 配置来自 ~/.chatlab/ai/llm-config.json\n * - 工具目录来自 @openchatlab/core 静态数据\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport type { FastifyInstance } from 'fastify'\nimport type { DatabaseManager, AIConversationManager } from '@openchatlab/node-runtime'\nimport { SkillManager, createActivateSkillTool } from '@openchatlab/node-runtime'\nimport type { AssistantConfig } from '@openchatlab/node-runtime'\nimport {\n BUILTIN_TOOL_CATALOG,\n BUILTIN_PROVIDERS,\n BUILTIN_MODELS,\n getBuiltinModelsByProvider,\n getChatOverview,\n} from '@openchatlab/core'\nimport type { DataSnapshot, OwnerInfo, MentionedMember } from '@openchatlab/node-runtime'\nimport { runSimpleLlmStream } from '@openchatlab/node-runtime'\nimport { AGENT_TOOL_REGISTRY } from '@openchatlab/tools'\nimport { adaptToolsForAgent } from '../../ai/tool-adapter'\nimport { getDefaultAssistantConfig, buildPiModel } from '../../ai/llm-config'\nimport { loadAssistantConfig } from '../../ai/assistant-loader'\nimport { getAssistantManager, getSkillManagerCore } from '../../ai/manager-factory'\nimport { runServerAgent, type AgentStreamChunk } from '../../ai/agent'\nimport {\n addLlmConfig,\n updateLlmConfig,\n deleteLlmConfig,\n setDefaultAssistantSlot,\n setFastModelSlot,\n} from '../../ai/llm-config'\nimport {\n addCustomProvider,\n updateCustomProvider,\n deleteCustomProvider,\n addCustomModel,\n updateCustomModel,\n deleteCustomModel,\n} from '../../ai/custom-store'\nimport { validateApiKey, fetchRemoteModels } from '../../ai/remote-api'\n\nfunction getAiDir(dbManager: DatabaseManager): string {\n const pathProvider = (dbManager as any)['pathProvider']\n if (!pathProvider) {\n throw Object.assign(new Error('PathProvider not available'), { statusCode: 500 })\n }\n return pathProvider.getAiDataDir()\n}\n\nexport function registerAiRoutes(\n server: FastifyInstance,\n dbManager: DatabaseManager,\n convManager?: AIConversationManager\n): void {\n // ==================== Assistants (via shared AssistantManager) ====================\n\n server.get('/_web/ai/assistants', async () => {\n const mgr = getAssistantManager(getAiDir(dbManager))\n return mgr.getAllAssistants()\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/assistants/:id', async (request, reply) => {\n const mgr = getAssistantManager(getAiDir(dbManager))\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 const mgr = getAssistantManager(getAiDir(dbManager))\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 mgr = getAssistantManager(getAiDir(dbManager))\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 mgr = getAssistantManager(getAiDir(dbManager))\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 mgr = getAssistantManager(getAiDir(dbManager))\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<{ Body: { rawMd: string } }>('/_web/ai/assistants/import', async (request) => {\n const mgr = getAssistantManager(getAiDir(dbManager))\n return mgr.importAssistantFromMd(request.body.rawMd)\n })\n\n // ==================== Skills (via shared SkillManagerCore) ====================\n\n server.get('/_web/ai/skills', async () => {\n const mgr = getSkillManagerCore(getAiDir(dbManager))\n return mgr.getAllSkills()\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/skills/:id', async (request, reply) => {\n const mgr = getSkillManagerCore(getAiDir(dbManager))\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 const mgr = getSkillManagerCore(getAiDir(dbManager))\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 mgr = getSkillManagerCore(getAiDir(dbManager))\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 mgr = getSkillManagerCore(getAiDir(dbManager))\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 const mgr = getSkillManagerCore(getAiDir(dbManager))\n return mgr.importSkillFromMd(request.body.rawMd)\n })\n\n server.get('/_web/ai/skills/builtin-catalog', async () => {\n const mgr = getSkillManagerCore(getAiDir(dbManager))\n return mgr.getBuiltinCatalog()\n })\n\n // ==================== LLM Config ====================\n\n server.get('/_web/ai/llm/has-config', async () => {\n const configPath = path.join(getAiDir(dbManager), 'llm-config.json')\n if (!fs.existsSync(configPath)) return false\n\n try {\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n if (!data.configs || !Array.isArray(data.configs) || data.configs.length === 0) return false\n return data.defaultAssistant != null\n } catch {\n return false\n }\n })\n\n server.get('/_web/ai/llm/configs', async () => {\n const configPath = path.join(getAiDir(dbManager), 'llm-config.json')\n if (!fs.existsSync(configPath)) return { configs: [], defaultAssistant: null, fastModel: null }\n\n try {\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n const configs = (data.configs || []).map((c: Record<string, unknown>) => {\n const { apiKey: _k, ...rest } = c\n return { ...rest, apiKey: '' }\n })\n return {\n configs,\n defaultAssistant: data.defaultAssistant ?? null,\n fastModel: data.fastModel ?? null,\n }\n } catch {\n return { configs: [], defaultAssistant: null, fastModel: null }\n }\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 customPath = path.join(getAiDir(dbManager), 'custom-providers.json')\n let custom: unknown[] = []\n if (fs.existsSync(customPath)) {\n try {\n custom = JSON.parse(fs.readFileSync(customPath, 'utf-8'))\n if (!Array.isArray(custom)) custom = []\n } catch {\n custom = []\n }\n }\n return [...BUILTIN_PROVIDERS, ...custom]\n })\n\n server.get('/_web/ai/llm/model-catalog', async () => {\n const customPath = path.join(getAiDir(dbManager), 'custom-models.json')\n let custom: unknown[] = []\n if (fs.existsSync(customPath)) {\n try {\n custom = JSON.parse(fs.readFileSync(customPath, 'utf-8'))\n if (!Array.isArray(custom)) custom = []\n } catch {\n custom = []\n }\n }\n return [...BUILTIN_MODELS, ...custom]\n })\n\n server.get('/_web/ai/llm/default-assistant-slot', async () => {\n const configPath = path.join(getAiDir(dbManager), 'llm-config.json')\n if (!fs.existsSync(configPath)) return null\n try {\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n return data.defaultAssistant ?? null\n } catch {\n return null\n }\n })\n\n server.get('/_web/ai/llm/fast-model-slot', async () => {\n const configPath = path.join(getAiDir(dbManager), 'llm-config.json')\n if (!fs.existsSync(configPath)) return null\n try {\n const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))\n return data.fastModel ?? null\n } catch {\n return null\n }\n })\n\n // ==================== LLM Config Write Operations ====================\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 }\n }>('/_web/ai/llm/configs', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return addLlmConfig(aiDataDir, request.body)\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 }\n }>('/_web/ai/llm/configs/:id', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return updateLlmConfig(aiDataDir, request.params.id, request.body)\n })\n\n server.delete<{ Params: { id: string } }>('/_web/ai/llm/configs/:id', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return deleteLlmConfig(aiDataDir, request.params.id)\n })\n\n server.put<{\n Body: { configId: string; modelId: string }\n }>('/_web/ai/llm/default-assistant-slot', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return setDefaultAssistantSlot(aiDataDir, request.body.configId, request.body.modelId)\n })\n\n server.put<{\n Body: { configId: string; modelId: string } | null\n }>('/_web/ai/llm/fast-model-slot', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return setFastModelSlot(aiDataDir, request.body)\n })\n\n // ==================== Custom Provider CRUD ====================\n\n server.post<{\n Body: {\n name: string\n kind: string\n defaultBaseUrl: string\n authMode?: string\n supportsCustomModels?: boolean\n modelIds?: string[]\n website?: string\n consoleUrl?: string\n }\n }>('/_web/ai/llm/custom-providers', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return addCustomProvider(aiDataDir, {\n ...request.body,\n kind: (request.body.kind || 'openai-compatible') as 'official' | 'aggregator' | 'openai-compatible',\n authMode: 'api-key',\n supportsCustomModels: request.body.supportsCustomModels ?? true,\n modelIds: request.body.modelIds ?? [],\n })\n })\n\n server.put<{\n Params: { id: string }\n Body: Record<string, unknown>\n }>('/_web/ai/llm/custom-providers/:id', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return updateCustomProvider(aiDataDir, request.params.id, request.body as any)\n })\n\n server.delete<{ Params: { id: string } }>('/_web/ai/llm/custom-providers/:id', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return deleteCustomProvider(aiDataDir, request.params.id)\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) => {\n const aiDataDir = getAiDir(dbManager)\n return addCustomModel(aiDataDir, {\n ...request.body,\n capabilities: (request.body.capabilities ?? ['chat']) as any,\n recommendedFor: (request.body.recommendedFor ?? ['chat']) as any,\n status: (request.body.status ?? 'stable') as any,\n })\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) => {\n const aiDataDir = getAiDir(dbManager)\n return updateCustomModel(aiDataDir, request.params.providerId, request.params.modelId, request.body as any)\n })\n\n server.delete<{\n Params: { providerId: string; modelId: string }\n }>('/_web/ai/llm/custom-models/:providerId/:modelId', async (request) => {\n const aiDataDir = getAiDir(dbManager)\n return deleteCustomModel(aiDataDir, request.params.providerId, request.params.modelId)\n })\n\n // ==================== Remote API (Validate Key & Fetch Models) ====================\n\n server.post<{\n Body: { provider: string; apiKey: string; baseUrl?: string; model?: string; apiFormat?: string }\n }>('/_web/ai/llm/validate-key', async (request) => {\n const { provider, apiKey, baseUrl, model, apiFormat } = request.body\n return validateApiKey(provider, apiKey, baseUrl, model, apiFormat)\n })\n\n server.post<{\n Body: { provider: string; apiKey: string; baseUrl?: string; apiFormat?: string }\n }>('/_web/ai/llm/remote-models', async (request) => {\n const { provider, apiKey, baseUrl, apiFormat } = request.body\n return fetchRemoteModels(provider, apiKey, baseUrl, apiFormat)\n })\n\n // ==================== LLM Simple Chat Stream ====================\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 aiDataDir = getAiDir(dbManager)\n const llmConfig = getDefaultAssistantConfig(aiDataDir)\n if (!llmConfig) {\n return reply.code(400).send({ success: false, error: 'LLM service not configured' })\n }\n\n const piModel = buildPiModel(llmConfig)\n\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n\n const sendChunk = (data: unknown) => {\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 })\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n sendChunk({ content: '', isFinished: true, finishReason: 'error', error: msg })\n }\n\n reply.raw.end()\n })\n\n // ==================== Tool Catalog ====================\n\n server.get('/_web/ai/tools/catalog', async () => {\n return BUILTIN_TOOL_CATALOG\n })\n\n // ==================== AI Conversations CRUD ====================\n\n if (!convManager) return\n\n server.post<{\n Body: { sessionId: string; title?: string; assistantId: string }\n }>('/_web/ai/conversations', async (request) => {\n const { sessionId, title, assistantId } = request.body\n return convManager.createConversation(sessionId, title, assistantId)\n })\n\n server.get<{\n Querystring: { sessionId: string }\n }>('/_web/ai/conversations', async (request) => {\n const { sessionId } = request.query\n if (!sessionId) return []\n return convManager.getConversations(sessionId)\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/conversations/:id', async (request, reply) => {\n const conv = convManager.getConversation(request.params.id)\n if (!conv) return reply.code(404).send({ error: 'Conversation not found' })\n return conv\n })\n\n server.put<{\n Params: { id: string }\n Body: { title: string }\n }>('/_web/ai/conversations/:id/title', async (request) => {\n return convManager.updateConversationTitle(request.params.id, request.body.title)\n })\n\n server.delete<{ Params: { id: string } }>('/_web/ai/conversations/:id', async (request) => {\n return convManager.deleteConversation(request.params.id)\n })\n\n // ==================== AI Messages CRUD ====================\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?: { promptTokens: number; completionTokens: number; totalTokens: number }\n }\n }>('/_web/ai/conversations/:id/messages', async (request) => {\n const { role, content, dataKeywords, dataMessageCount, contentBlocks, tokenUsage } = request.body\n return convManager.addMessage(\n request.params.id,\n role,\n content,\n dataKeywords,\n dataMessageCount,\n contentBlocks as any,\n tokenUsage\n )\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/conversations/:id/messages', async (request) => {\n return convManager.getMessages(request.params.id)\n })\n\n server.get<{ Params: { id: string } }>('/_web/ai/conversations/:id/token-usage', async (request) => {\n return convManager.getConversationTokenUsage(request.params.id)\n })\n\n // ==================== Agent SSE Stream ====================\n\n const activeAgentAborts = new Map<string, AbortController>()\n\n server.post<{\n Body: {\n userMessage: string\n conversationId: string\n sessionId: string\n chatType?: 'group' | 'private'\n locale?: string\n assistantId?: string\n compressionConfig?: {\n enabled: boolean\n tokenThresholdPercent?: number\n bufferSizePercent?: number\n maxToolResultPercent?: number\n }\n ownerInfo?: OwnerInfo\n mentionedMembers?: MentionedMember[]\n }\n }>('/_web/ai/agent/stream', async (request, reply) => {\n const {\n userMessage,\n conversationId,\n sessionId,\n chatType,\n locale,\n assistantId,\n compressionConfig,\n ownerInfo,\n mentionedMembers,\n } = request.body\n\n const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`\n const abortController = new AbortController()\n activeAgentAborts.set(requestId, abortController)\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 const sendSSE = (event: string, data: unknown) => {\n reply.raw.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`)\n }\n\n sendSSE('meta', { requestId })\n\n const aiDataDir = getAiDir(dbManager)\n\n let assistantSystemPrompt: string | undefined\n if (assistantId) {\n const assistantConfig = loadAssistantConfig(aiDataDir, assistantId)\n if (assistantConfig?.systemPrompt) {\n assistantSystemPrompt = assistantConfig.systemPrompt\n }\n }\n\n const llmConfig = getDefaultAssistantConfig(aiDataDir)\n const maxToolResultPercent = compressionConfig?.maxToolResultPercent ?? 50\n const contextWindow = llmConfig ? (buildPiModel(llmConfig).contextWindow ?? 128000) : 128000\n const maxToolResultTokens = Math.floor(contextWindow * (maxToolResultPercent / 100))\n\n const db = (dbManager as any).open?.(sessionId)\n const agentTools = db\n ? adaptToolsForAgent(AGENT_TOOL_REGISTRY, () => ({ db, sessionId, locale }), { maxToolResultTokens })\n : []\n\n const skillManager = new SkillManager(aiDataDir)\n skillManager.init()\n const toolNames = agentTools.map((t: { name: string }) => t.name)\n const skillMenu = skillManager.getSkillMenu(chatType ?? 'group', toolNames)\n\n if (skillMenu) {\n const activateSkillTool = createActivateSkillTool({\n chatType: chatType ?? 'group',\n allowedTools: toolNames,\n locale,\n getSkillConfig: (id) => skillManager.getSkillConfig(id),\n })\n agentTools.push(activateSkillTool as any)\n }\n\n const onEvent = (event: AgentStreamChunk) => {\n sendSSE(event.type, event)\n if (event.type === 'done') {\n activeAgentAborts.delete(requestId)\n reply.raw.end()\n }\n }\n\n reply.raw.on('close', () => {\n if (!abortController.signal.aborted) {\n abortController.abort()\n }\n activeAgentAborts.delete(requestId)\n })\n\n try {\n const resolvedCompression = compressionConfig?.enabled\n ? {\n enabled: true as const,\n tokenThresholdPercent: compressionConfig.tokenThresholdPercent ?? 75,\n bufferSizePercent: compressionConfig.bufferSizePercent ?? 20,\n maxToolResultPercent: compressionConfig.maxToolResultPercent,\n }\n : undefined\n\n let dataSnapshot: DataSnapshot | undefined\n if (db) {\n try {\n const overview = getChatOverview(db, 5)\n if (overview) {\n dataSnapshot = {\n name: overview.name,\n platform: overview.platform,\n type: overview.type,\n totalMessages: overview.totalMessages,\n totalMembers: overview.totalMembers,\n firstMessageTs: overview.firstMessageTs,\n lastMessageTs: overview.lastMessageTs,\n capturedAt: Math.floor(Date.now() / 1000),\n }\n }\n } catch {\n // non-fatal: proceed without snapshot\n }\n }\n\n await runServerAgent({\n userMessage,\n conversationId,\n chatType,\n locale,\n assistantSystemPrompt,\n skillMenu,\n compressionConfig: resolvedCompression,\n tools: agentTools,\n aiDataDir,\n convManager,\n onEvent,\n abortSignal: abortController.signal,\n ownerInfo,\n mentionedMembers,\n dataSnapshot,\n })\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n sendSSE('error', { type: 'error', error: { name: 'ServerError', message: msg } })\n sendSSE('done', { type: 'done', isFinished: true })\n activeAgentAborts.delete(requestId)\n reply.raw.end()\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 // ==================== Debug SQL ====================\n\n server.get('/_web/ai/debug/schema', async (_request, reply) => {\n if (!convManager) {\n return reply.code(503).send({ error: 'AI conversation manager not available' })\n }\n return convManager.getAiSchema()\n })\n\n server.post<{\n Body: { sql: string }\n }>('/_web/ai/debug/execute-sql', async (request, reply) => {\n if (!convManager) {\n return reply.code(503).send({ error: 'AI conversation manager not available' })\n }\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 convManager.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 (_request, reply) => {\n if (!convManager) {\n return reply.code(503).send({ error: 'AI conversation manager not available' })\n }\n const cleared = convManager.clearAllDebugContext()\n return { success: true, cleared }\n })\n}\n","/**\n * Server 端 AI 日志\n *\n * 复用 @openchatlab/node-runtime 的 AiLogger,\n * 在 startHttpServer() 中通过 initServerAiLogger() 初始化。\n */\n\nimport { AiLogger } from '@openchatlab/node-runtime'\n\nlet logger: AiLogger | null = null\n\nexport function initServerAiLogger(logsDir: string): AiLogger {\n if (!logger) {\n logger = new AiLogger(logsDir)\n }\n return logger\n}\n\nexport function getServerAiLogger(): AiLogger | null {\n return logger\n}\n\nexport function closeServerAiLogger(): void {\n if (logger) {\n logger.close()\n logger = null\n }\n}\n","/**\n * 工具适配层\n *\n * 将 @openchatlab/tools 的 ToolDefinition 适配为 @mariozechner/pi-agent-core 的 AgentTool 格式。\n * 消息类工具返回 rawMessages 时自动执行预处理管道(清洗、去噪、脱敏、截断、格式化)。\n */\n\nimport type { ToolDefinition, ToolExecutionContext } from '@openchatlab/tools'\nimport { CoreDataProvider } from '@openchatlab/tools'\nimport type { DatabaseAdapter } from '@openchatlab/core'\nimport {\n applyPreprocessingPipeline,\n batchSegmentWithFrequency,\n type AgentTool,\n type AgentToolResult,\n type PreprocessableMessage,\n type TruncationStrategy,\n} from '@openchatlab/node-runtime'\nimport { getServerAiLogger } from './logger'\n\nconst DEFAULT_MAX_TOOL_RESULT_TOKENS = 8000\n\nconst TOOL_TRUNCATION_STRATEGY: Record<string, TruncationStrategy> = {\n search_messages: 'keep_first',\n deep_search_messages: 'keep_first',\n get_recent_messages: 'keep_last',\n get_message_context: 'keep_last',\n get_session_messages: 'keep_last',\n get_conversation_between: 'keep_last',\n}\n\nexport interface ServerToolContext {\n db: DatabaseAdapter\n sessionId: string\n locale?: string\n}\n\nfunction convertJsonSchemaToParameters(schema: ToolDefinition['inputSchema']) {\n const properties: Record<string, unknown> = {}\n for (const [key, prop] of Object.entries(schema.properties)) {\n properties[key] = { ...prop }\n }\n return {\n type: 'object' as const,\n properties,\n required: schema.required || [],\n }\n}\n\nexport interface AdaptToolsOptions {\n maxToolResultTokens?: number\n}\n\nexport function adaptToolsForAgent(\n tools: ToolDefinition[],\n getContext: () => ServerToolContext,\n options?: AdaptToolsOptions\n): AgentTool<any, any>[] {\n const tokenBudget = options?.maxToolResultTokens ?? DEFAULT_MAX_TOOL_RESULT_TOKENS\n\n return tools.map((tool) => ({\n name: tool.name,\n label: tool.name,\n description: tool.description,\n parameters: convertJsonSchemaToParameters(tool.inputSchema) as any,\n async execute(_toolCallId: string, params: Record<string, unknown>): Promise<AgentToolResult<unknown>> {\n const ctx = getContext()\n const execCtx: ToolExecutionContext = {\n db: ctx.db,\n dataProvider: new CoreDataProvider(ctx.db),\n sessionId: ctx.sessionId,\n locale: ctx.locale,\n segmentText: (texts, locale, options) => batchSegmentWithFrequency(texts, locale as any, options as any),\n }\n try {\n const result = await tool.handler(params, execCtx)\n\n if (result.rawMessages && result.rawMessages.length > 0) {\n const pipelineResult = applyPreprocessingPipeline({\n rawMessages: result.rawMessages as PreprocessableMessage[],\n locale: ctx.locale,\n maxToolResultTokens: tokenBudget,\n truncationStrategy: TOOL_TRUNCATION_STRATEGY[tool.name] ?? 'keep_last',\n extraDetails: (result.data ?? {}) as Record<string, unknown>,\n logger: getServerAiLogger() ?? undefined,\n })\n return { content: [{ type: 'text', text: pipelineResult.text }], details: null }\n }\n\n return { content: [{ type: 'text', text: result.content }], details: null }\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error)\n return { content: [{ type: 'text', text: `Error: ${msg}` }], details: null }\n }\n },\n }))\n}\n","/**\n * 助手配置加载器\n *\n * 从 ~/.chatlab/ai/assistants/*.md 加载助手系统提示词。\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { parseAssistantFile } from '@openchatlab/node-runtime'\nimport type { AssistantConfig } from '@openchatlab/node-runtime'\n\nexport function loadAssistantConfig(aiDataDir: string, assistantId: string): AssistantConfig | null {\n const filePath = path.join(aiDataDir, 'assistants', `${assistantId}.md`)\n if (!fs.existsSync(filePath)) return null\n\n try {\n const content = fs.readFileSync(filePath, 'utf-8')\n return parseAssistantFile(content, filePath)\n } catch {\n return null\n }\n}\n","/**\n * Factory functions for creating AssistantManager and SkillManagerCore instances.\n *\n * Server-side equivalent of the Electron adapter in electron/main/ai/assistant/manager.ts.\n * Uses Node.js fs directly (no Electron dependency).\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { createHash, randomUUID } from 'crypto'\nimport {\n AssistantManager,\n SkillManagerCore,\n type AssistantManagerFs,\n type SkillManagerFs,\n} from '@openchatlab/node-runtime'\n\nconst nodeFs: AssistantManagerFs & SkillManagerFs = {\n ensureDir(dir: string) {\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n },\n listFiles(dir: string, ext: string) {\n if (!fs.existsSync(dir)) return []\n return fs.readdirSync(dir).filter((f) => f.endsWith(ext))\n },\n readFile(filePath: string) {\n return fs.readFileSync(filePath, 'utf-8')\n },\n writeFile(filePath: string, content: string) {\n fs.writeFileSync(filePath, content, 'utf-8')\n },\n deleteFile(filePath: string) {\n if (fs.existsSync(filePath)) fs.unlinkSync(filePath)\n },\n fileExists(filePath: string) {\n return fs.existsSync(filePath)\n },\n joinPath(...parts: string[]) {\n return path.join(...parts)\n },\n}\n\nconst managerCache = new Map<string, { assistant: AssistantManager; skill: SkillManagerCore }>()\n\nexport function getAssistantManager(aiDataDir: string): AssistantManager {\n let cached = managerCache.get(aiDataDir)\n if (!cached) {\n cached = {\n assistant: new AssistantManager({\n fs: nodeFs,\n assistantsDir: path.join(aiDataDir, 'assistants'),\n builtinRawConfigs: [],\n generateId: () => `custom_${randomUUID().replace(/-/g, '').slice(0, 12)}`,\n }),\n skill: new SkillManagerCore({\n fs: nodeFs,\n skillsDir: path.join(aiDataDir, 'skills'),\n builtinRawSkills: [],\n contentHash: (content: string) => createHash('md5').update(content).digest('hex'),\n }),\n }\n managerCache.set(aiDataDir, cached)\n }\n return cached.assistant\n}\n\nexport function getSkillManagerCore(aiDataDir: string): SkillManagerCore {\n let cached = managerCache.get(aiDataDir)\n if (!cached) {\n getAssistantManager(aiDataDir)\n cached = managerCache.get(aiDataDir)!\n }\n return cached.skill\n}\n","/**\n * 服务端 Agent\n *\n * 使用 @openchatlab/node-runtime 的 runAgentCore 编排对话流程,\n * 通过 AgentEventHandler 输出与 Electron 端一致的流式事件。\n */\n\nimport {\n runAgentCore,\n checkAndCompress,\n buildSystemPrompt,\n createAiTranslate,\n createCompressionLlmAdapter,\n AgentEventHandler,\n formatAIError,\n type AgentStreamChunk,\n type PiMessage,\n type SimpleHistoryMessage,\n type AIConversationManager,\n type CompressionConfig,\n type AgentTool,\n type DataSnapshot,\n type OwnerInfo,\n type MentionedMember,\n} from '@openchatlab/node-runtime'\n\nimport { getDefaultAssistantConfig, buildPiModel } from './llm-config'\nimport { getServerAiLogger } from './logger'\n\nexport type { AgentStreamChunk }\n\nexport interface RunAgentOptions {\n userMessage: string\n conversationId: string\n chatType?: 'group' | 'private'\n locale?: string\n assistantSystemPrompt?: string\n skillMenu?: string | null\n compressionConfig?: CompressionConfig\n tools?: AgentTool[]\n aiDataDir: string\n convManager: AIConversationManager\n onEvent: (event: AgentStreamChunk) => void\n abortSignal?: AbortSignal\n ownerInfo?: OwnerInfo\n mentionedMembers?: MentionedMember[]\n dataSnapshot?: DataSnapshot\n}\n\nexport async function runServerAgent(options: RunAgentOptions): Promise<void> {\n const {\n userMessage,\n conversationId,\n chatType = 'group',\n locale = 'zh-CN',\n assistantSystemPrompt,\n skillMenu,\n compressionConfig,\n tools = [],\n aiDataDir,\n convManager,\n onEvent,\n abortSignal,\n ownerInfo,\n mentionedMembers,\n dataSnapshot,\n } = options\n\n const aiLogger = getServerAiLogger()\n\n const llmConfig = getDefaultAssistantConfig(aiDataDir)\n if (!llmConfig) {\n onEvent({ type: 'error', error: { name: 'ConfigError', message: 'LLM service not configured' } })\n onEvent({ type: 'done', isFinished: true })\n return\n }\n\n const piModel = buildPiModel(llmConfig)\n const t = createAiTranslate(locale)\n\n let skillCtx: { skillDef?: { name: string; prompt: string }; skillMenu?: string } | undefined\n if (skillMenu) {\n skillCtx = { skillMenu }\n }\n\n const systemPrompt = buildSystemPrompt({\n t,\n chatType,\n assistantSystemPrompt,\n ownerInfo,\n locale,\n skillCtx,\n mentionedMembers,\n dataSnapshot,\n })\n\n const handler = new AgentEventHandler({\n onChunk: onEvent,\n context: {},\n systemPrompt,\n })\n\n if (compressionConfig?.enabled) {\n const llmAdapter = createCompressionLlmAdapter({\n piModel,\n apiKey: llmConfig.apiKey,\n onCompressing: () => handler.emitStatus('compressing', []),\n })\n const compressionResult = await checkAndCompress(\n conversationId,\n compressionConfig,\n systemPrompt,\n llmAdapter,\n convManager,\n aiLogger ?? undefined\n )\n if (compressionResult.compressed) {\n onEvent({\n type: 'compression_done',\n compressionResult: {\n summaryContent: compressionResult.summaryContent ?? '',\n tokensBefore: compressionResult.tokensBefore ?? 0,\n tokensAfter: compressionResult.tokensAfter ?? 0,\n timestamp: Date.now(),\n },\n })\n }\n }\n\n if (abortSignal?.aborted) {\n handler.emitStatus('aborted', [], { force: true })\n onEvent({ type: 'done', isFinished: true, usage: handler.cloneUsage() })\n return\n }\n\n let history: SimpleHistoryMessage[] = []\n try {\n history = convManager.getHistoryForAgent(conversationId)\n } catch {\n // empty history on failure\n }\n\n handler.emitStatus('preparing', [], { pendingUserMessage: userMessage, force: true })\n\n const steerMessage = t('ai.agent.answerWithoutTools')\n let cachedMessages: PiMessage[] = []\n\n try {\n const result = await runAgentCore({\n piModel,\n apiKey: llmConfig.apiKey,\n systemPrompt,\n tools,\n history,\n userMessage,\n maxToolRounds: 5,\n abortSignal,\n steerMessage,\n onConvertToLlm: (filteredMessages) => {\n cachedMessages = filteredMessages as PiMessage[]\n },\n onEvent: (coreEvent) => handler.handleCoreEvent(coreEvent, cachedMessages),\n onDebugContext: (messages) => {\n try {\n convManager.setPendingDebugContext(conversationId, JSON.stringify(messages, null, 2))\n } catch {\n // silent\n }\n },\n })\n\n if (result.error) {\n const friendlyMessage = formatAIError(result.error)\n onEvent({ type: 'error', error: { name: 'AgentError', message: friendlyMessage } })\n }\n\n handler.emitStatus('completed', cachedMessages, { force: true })\n onEvent({ type: 'done', isFinished: true, usage: result.usage })\n } catch (error) {\n const friendlyMessage = formatAIError(error)\n aiLogger?.error('ServerAgent', 'Agent execution error', { error: String(error) })\n handler.emitStatus('error', cachedMessages, { force: true })\n onEvent({ type: 'error', error: { name: 'AgentError', message: friendlyMessage } })\n onEvent({ type: 'done', isFinished: true, usage: handler.cloneUsage() })\n }\n}\n","/**\n * 自定义 Provider / Model 持久化存储(平台无关)\n *\n * 文件位置:\n * - {aiDataDir}/custom-providers.json\n * - {aiDataDir}/custom-models.json\n */\n\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { randomUUID } from 'crypto'\nimport type { ProviderDefinition, ModelDefinition } from '@openchatlab/core'\n\n// ==================== Custom Providers ====================\n\nfunction readProviders(aiDataDir: string): ProviderDefinition[] {\n const storePath = path.join(aiDataDir, 'custom-providers.json')\n if (!fs.existsSync(storePath)) return []\n try {\n const content = fs.readFileSync(storePath, 'utf-8')\n return JSON.parse(content) as ProviderDefinition[]\n } catch {\n return []\n }\n}\n\nfunction writeProviders(aiDataDir: string, providers: ProviderDefinition[]): void {\n const storePath = path.join(aiDataDir, 'custom-providers.json')\n const dir = path.dirname(storePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(storePath, JSON.stringify(providers, null, 2), 'utf-8')\n}\n\nexport function addCustomProvider(\n aiDataDir: string,\n input: Omit<ProviderDefinition, 'id' | 'builtin' | 'enabledByDefault'>\n): ProviderDefinition {\n const providers = readProviders(aiDataDir)\n const newProvider: ProviderDefinition = {\n ...input,\n id: `custom:${randomUUID()}`,\n builtin: false,\n enabledByDefault: false,\n }\n providers.push(newProvider)\n writeProviders(aiDataDir, providers)\n return newProvider\n}\n\nexport function updateCustomProvider(\n aiDataDir: string,\n id: string,\n updates: Partial<Omit<ProviderDefinition, 'id' | 'builtin'>>\n): { success: boolean; error?: string } {\n const providers = readProviders(aiDataDir)\n const index = providers.findIndex((p) => p.id === id)\n if (index === -1) return { success: false, error: 'Custom provider not found' }\n\n providers[index] = { ...providers[index], ...updates }\n writeProviders(aiDataDir, providers)\n return { success: true }\n}\n\nexport function deleteCustomProvider(aiDataDir: string, id: string): { success: boolean; error?: string } {\n const providers = readProviders(aiDataDir)\n const index = providers.findIndex((p) => p.id === id)\n if (index === -1) return { success: false, error: 'Custom provider not found' }\n\n providers.splice(index, 1)\n writeProviders(aiDataDir, providers)\n return { success: true }\n}\n\n// ==================== Custom Models ====================\n\nfunction readModels(aiDataDir: string): ModelDefinition[] {\n const storePath = path.join(aiDataDir, 'custom-models.json')\n if (!fs.existsSync(storePath)) return []\n try {\n const content = fs.readFileSync(storePath, 'utf-8')\n return JSON.parse(content) as ModelDefinition[]\n } catch {\n return []\n }\n}\n\nfunction writeModels(aiDataDir: string, models: ModelDefinition[]): void {\n const storePath = path.join(aiDataDir, 'custom-models.json')\n const dir = path.dirname(storePath)\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(storePath, JSON.stringify(models, null, 2), 'utf-8')\n}\n\nexport function addCustomModel(\n aiDataDir: string,\n input: Omit<ModelDefinition, 'builtin' | 'editable'>\n): { success: boolean; model?: ModelDefinition; error?: string } {\n const models = readModels(aiDataDir)\n\n const existing = models.find((m) => m.id === input.id && m.providerId === input.providerId)\n if (existing) {\n return { success: false, error: `Model \"${input.id}\" already exists under provider \"${input.providerId}\"` }\n }\n\n const newModel: ModelDefinition = {\n ...input,\n builtin: false,\n editable: true,\n }\n models.push(newModel)\n writeModels(aiDataDir, models)\n return { success: true, model: newModel }\n}\n\nexport function updateCustomModel(\n aiDataDir: string,\n providerId: string,\n modelId: string,\n updates: Partial<Omit<ModelDefinition, 'id' | 'providerId' | 'builtin'>>\n): { success: boolean; error?: string } {\n const models = readModels(aiDataDir)\n const index = models.findIndex((m) => m.id === modelId && m.providerId === providerId)\n if (index === -1) return { success: false, error: 'Custom model not found' }\n\n models[index] = { ...models[index], ...updates }\n writeModels(aiDataDir, models)\n return { success: true }\n}\n\nexport function deleteCustomModel(\n aiDataDir: string,\n providerId: string,\n modelId: string\n): { success: boolean; error?: string } {\n const models = readModels(aiDataDir)\n const index = models.findIndex((m) => m.id === modelId && m.providerId === providerId)\n if (index === -1) return { success: false, error: 'Custom model not found' }\n\n models.splice(index, 1)\n writeModels(aiDataDir, models)\n return { success: true }\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 { PreferencesManager, type Preferences } from '@openchatlab/node-runtime'\nimport { loadConfig, writeConfigField, type UiConfig } from '@openchatlab/config'\nimport type { PathProvider } from '@openchatlab/core'\n\nlet prefManager: PreferencesManager | null = null\n\nexport function registerPreferencesRoutes(server: FastifyInstance, pathProvider: PathProvider): void {\n if (!prefManager) {\n prefManager = new PreferencesManager(pathProvider.getSystemDir())\n }\n\n server.get('/_web/preferences', async () => {\n return prefManager!.load()\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","/**\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}\n\nexport interface PullSessionResult {\n success: boolean\n newMessageCount: number\n error?: string\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): boolean {\n const sources = this.loadAll()\n const ds = sources.find((s) => s.id === sourceId)\n if (!ds) return false\n const before = ds.sessions.length\n ds.sessions = ds.sessions.filter((s) => s.id !== sessionId)\n if (ds.sessions.length === before) return false\n this.saveAll(sources)\n return true\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 — Remote session discovery\n *\n * Moved from electron/main/api/pullDiscovery.shared.ts (already platform-agnostic).\n * Builds discovery URLs and parses responses from remote ChatLab API servers.\n */\n\nimport type { RemoteSessionDiscoveryQuery, RemoteSessionDiscoveryResult, RemoteSession } from './types'\n\nexport function buildRemoteSessionsUrl(baseUrl: string, query: RemoteSessionDiscoveryQuery = {}): string {\n const searchParams = new URLSearchParams()\n searchParams.set('format', 'chatlab')\n\n if (query.keyword?.trim()) searchParams.set('keyword', query.keyword.trim())\n if (query.limit && query.limit > 0) searchParams.set('limit', String(query.limit))\n if (query.cursor) searchParams.set('cursor', query.cursor)\n\n return `${baseUrl}/sessions?${searchParams.toString()}`\n}\n\n/**\n * Parse remote sessions response with backward compatibility.\n * Supports: Pull protocol `{ sessions, page? }`, ChatLab API `{ success, data }`, and plain array.\n */\nexport function parseRemoteSessionsResponse(body: string): RemoteSessionDiscoveryResult {\n const parsed = JSON.parse(body)\n\n let sessions: RemoteSession[]\n let pageSource: Record<string, unknown> | undefined\n\n if (Array.isArray(parsed)) {\n sessions = parsed\n } else if (parsed && typeof parsed === 'object') {\n sessions = parsed.sessions ?? parsed.data?.sessions ?? parsed.data ?? []\n if (!Array.isArray(sessions)) sessions = []\n pageSource = parsed.page ?? parsed.data?.page\n } else {\n sessions = []\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","/**\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 PullSessionResult,\n} from './types'\nimport type { DataSourceManager } from './data-source-manager'\n\nconst MAX_PAGES_PER_PULL = 50\nconst PULL_OVERLAP_SECONDS = 60\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.end !== undefined && params.end > 0) qs.push(`end=${params.end}`)\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 cleanupTempFile(filePath: string): void {\n try {\n if (fs.existsSync(filePath)) fs.unlinkSync(filePath)\n } catch {\n /* ignore */\n }\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 (skip pull) */\n isImporting?: () => boolean\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: () => boolean\n private pullingSourceIds = new Set<string>()\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 }\n\n private async importTempFile(\n baseUrl: string,\n sess: ImportSession,\n tempFile: string\n ): Promise<{\n success: boolean\n newMessageCount: number\n sessionId?: string\n error?: string\n needFullResync?: boolean\n }> {\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 async executePullSession(sourceId: string, ds: DataSource, sess: ImportSession): Promise<PullSessionResult> {\n if (this.isImporting()) {\n this.logger.info(`[Pull] Skipping \"${sess.name}\": import in progress`)\n return { success: false, newMessageCount: 0, error: 'Import in progress' }\n }\n\n this.logger.info(`[Pull] Pulling \"${sess.name}\" from ${ds.baseUrl}`)\n\n let totalNewMessages = 0\n let since = sess.lastPullAt\n let offset = 0\n let end: number | undefined\n let pageCount = 0\n let resyncAttempted = 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 end,\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 if (stat.size === 0) {\n cleanupTempFile(tempFile)\n break\n }\n\n const sync = parseSyncFromFile(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 = 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 return { success: false, newMessageCount: 0, error: errMsg }\n }\n\n if (!result.success) {\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 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\n if (!sync || !sync.hasMore) break\n\n if (sync.nextSince !== undefined) since = sync.nextSince\n if (sync.nextOffset !== undefined) offset = sync.nextOffset\n else offset = 0\n if (sync.watermark !== undefined && !end) end = sync.watermark\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 this.dsManager.updateSession(sourceId, sess.id, {\n lastPullAt: Math.floor(Date.now() / 1000) - PULL_OVERLAP_SECONDS,\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 return { success: true, newMessageCount: totalNewMessages }\n } catch (error: any) {\n const errMsg = error.message || 'Pull failed'\n this.logger.error(`[Pull] Pull failed for \"${sess.name}\"`, error)\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 return { success: false, newMessageCount: 0, error: errMsg }\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 for (const sess of ds.sessions) {\n await this.executePullSession(ds.id, ds, sess)\n }\n } finally {\n this.pullingSourceIds.delete(ds.id)\n }\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 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 for (const sess of ds.sessions) {\n const result = await this.executePullSession(sourceId, ds, sess)\n if (!result.success && result.error) errors.push(`${sess.name}: ${result.error}`)\n }\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/importData\n * NoopNotifier: placeholder (future: SSE push)\n */\n\nimport * as fs from 'fs'\nimport * as os from 'os'\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 { parseFile } from '../import/chatlab-reader'\nimport { importData } from '../import/importer'\n\nfunction getTempFilePath(ext: string): string {\n const id = crypto.randomBytes(8).toString('hex')\n return path.join(os.tmpdir(), `chatlab-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, application/x-ndjson',\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\nfunction resolveNativeBinding(): string | undefined {\n if (process.versions.electron) return undefined\n const nativePath = path.resolve(__dirname, '../../native/better_sqlite3.node')\n if (fs.existsSync(nativePath)) return nativePath\n return undefined\n}\n\nexport class DirectImporter implements DataImporter {\n private dbManager: DatabaseManager\n private nativeBinding: string | undefined\n private logger: SyncLogger\n\n constructor(dbManager: DatabaseManager, logger?: SyncLogger) {\n this.dbManager = dbManager\n this.nativeBinding = resolveNativeBinding()\n this.logger = logger ?? NOOP_LOGGER\n }\n\n sessionExists(sessionId: string): boolean {\n const dbPath = this.dbManager.getDbPath(sessionId)\n return fs.existsSync(dbPath)\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 const data = await parseFile(tempFile)\n\n this.dbManager.close(sessionId)\n const result = await importData(this.dbManager, data, {\n sessionId,\n nativeBinding: this.nativeBinding,\n })\n\n if (result.success) {\n this.logger.info(\n `[DirectImporter] Incremental OK: +${result.messageCount} messages (${result.duplicateCount} duplicates skipped)`\n )\n return {\n success: true,\n newMessageCount: result.messageCount,\n sessionId,\n }\n }\n\n if (result.error?.includes('not found') || result.error?.includes('session_not_found')) {\n return { success: false, newMessageCount: 0, sessionId, needFullResync: 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 data = await parseFile(tempFile)\n\n const result = await importData(this.dbManager, data, {\n sessionId: externalId,\n nativeBinding: this.nativeBinding,\n })\n\n if (result.success) {\n this.logger.info(\n `[DirectImporter] Full import OK: ${result.messageCount} messages, ${result.memberCount} members`\n )\n return { success: true, newMessageCount: result.messageCount, sessionId: externalId }\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 Internal Web API — /_web/automation/ routes\n *\n * Exposes sync engine functionality to the Web UI via HTTP endpoints.\n */\n\nimport type { FastifyInstance } from 'fastify'\nimport {\n buildRemoteSessionsUrl,\n parseRemoteSessionsResponse,\n normalizeBaseUrl,\n reloadTimer,\n stopTimer,\n} from '@openchatlab/sync'\nimport type { SyncRouteContext } from './index'\n\nexport function registerAutomationRoutes(server: FastifyInstance, ctx: SyncRouteContext): void {\n const { dsManager, pullEngine, serverInfo } = ctx\n\n // ==================== Config (read-only in CLI mode) ====================\n\n server.get('/_web/automation/config', async () => {\n return {\n enabled: true,\n port: serverInfo.port,\n token: serverInfo.token,\n host: serverInfo.host,\n }\n })\n\n // ==================== Data Sources ====================\n\n server.get('/_web/automation/data-sources', async () => {\n return 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) => {\n const ds = dsManager.add(request.body)\n reloadTimer(ds.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 ds = dsManager.update(request.params.id, request.body)\n if (!ds) return reply.code(404).send({ error: 'Data source not found' })\n reloadTimer(ds.id)\n return ds\n })\n\n server.delete<{ Params: { id: string } }>('/_web/automation/data-sources/:id', async (request, reply) => {\n stopTimer(request.params.id)\n const ok = 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 // ==================== Import Sessions ====================\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 added = dsManager.addSessions(request.params.id, request.body.sessions)\n if (added.length === 0 && !dsManager.get(request.params.id)) {\n return reply.code(404).send({ error: 'Data source not found' })\n }\n reloadTimer(request.params.id, true)\n for (const sess of added) {\n pullEngine.triggerPull(request.params.id, sess.id).catch(() => {})\n }\n return added\n })\n\n server.delete<{\n Params: { id: string; sessId: string }\n }>('/_web/automation/data-sources/:id/sessions/:sessId', async (request, reply) => {\n const ok = dsManager.removeSession(request.params.id, request.params.sessId)\n if (!ok) return reply.code(404).send({ error: 'Session not found' })\n reloadTimer(request.params.id)\n return { success: true }\n })\n\n // ==================== Pull / Sync ====================\n\n server.post<{ Params: { id: string }; Body: { sessionId?: string } }>(\n '/_web/automation/data-sources/:id/pull',\n async (request) => {\n return 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) => {\n return pullEngine.triggerPullAll(request.params.id)\n })\n\n // ==================== Remote Session Discovery ====================\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 { baseUrl, token, keyword, limit, cursor } = request.query\n if (!baseUrl) return reply.code(400).send({ error: 'baseUrl is required' })\n\n const normalizedUrl = normalizeBaseUrl(baseUrl)\n const url = buildRemoteSessionsUrl(normalizedUrl, {\n keyword,\n limit: limit ? parseInt(limit, 10) : undefined,\n cursor,\n })\n\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: any) {\n return reply.code(502).send({ error: err.message || 'Failed to fetch remote sessions' })\n }\n })\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 type { PathProvider } from '@openchatlab/core'\nimport { DataSourceManager, PullEngine, initScheduler, stopAllTimers } from '@openchatlab/sync'\nimport type { SyncLogger } from '@openchatlab/sync'\nimport { NodeFetcher, DirectImporter, NoopNotifier } from './adapters'\nimport { registerAutomationRoutes } from './routes'\n\nexport interface SyncRouteContext {\n dsManager: DataSourceManager\n pullEngine: PullEngine\n serverInfo: { port: number; host: string; token: string }\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; 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 pullEngine = new PullEngine({\n fetcher,\n importer,\n notifier,\n dsManager,\n logger: syncLogger,\n })\n\n registerAutomationRoutes(server, { dsManager, pullEngine, serverInfo })\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","path","crypto","server","server","dbManager","dbManager","server","apiErr","os","path","registerSessionRoutes","server","server","fs","path","dbManager","ensureDb","server","server","server","fs","path","randomUUID","buildPiModel","dbManager","buildPiModel","server","fs","path","server","dbManager","sendEvent","fs","os","path","server","dbManager","ensureDb","server","fs","path","server","server","dbManager","registerSessionRoutes","path","ensureDb","dbManager","server","fs","path","options","fs","path","fs","path","randomUUID","randomUUID","convManager","buildPiModel","fs","path","randomUUID","dbManager","server","convManager","buildPiModel","server","fs","path","crypto","logger","fs","crypto","fs","os","path","crypto","resolveNativeBinding","dbManager","logger","noop","server","dsManager","pullEngine","server","dbManager","resolveNativeBinding"]}