chatlab-cli 0.30.2 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-command-VBDMWOKL.mjs → chat-command-MOETAGU5.mjs} +9 -8
- package/dist/{chat-command-VBDMWOKL.mjs.map → chat-command-MOETAGU5.mjs.map} +1 -1
- package/dist/{chunk-M2PXDX4G.mjs → chunk-2IXPWPLR.mjs} +168 -77
- package/dist/chunk-2IXPWPLR.mjs.map +1 -0
- package/dist/{chunk-TCZHG3G7.mjs → chunk-3VMKS7PU.mjs} +44 -5
- package/dist/chunk-3VMKS7PU.mjs.map +1 -0
- package/dist/{chunk-TEX44HNL.mjs → chunk-7HBVGVOB.mjs} +5 -15
- package/dist/chunk-7HBVGVOB.mjs.map +1 -0
- package/dist/{chunk-LVEJHB3X.mjs → chunk-DQ45LDKZ.mjs} +512 -98
- package/dist/chunk-DQ45LDKZ.mjs.map +1 -0
- package/dist/{chunk-ULNRUS55.mjs → chunk-E6W2RURS.mjs} +3 -3
- package/dist/{chunk-36JGKW6K.mjs → chunk-KCPGEILH.mjs} +1503 -530
- package/dist/chunk-KCPGEILH.mjs.map +1 -0
- package/dist/{chunk-WV5GSRQM.mjs → chunk-LJXSUN25.mjs} +5 -15
- package/dist/chunk-LJXSUN25.mjs.map +1 -0
- package/dist/chunk-N5AGDT7I.mjs +268 -0
- package/dist/chunk-N5AGDT7I.mjs.map +1 -0
- package/dist/{chunk-D3DPCDII.mjs → chunk-SZEBCNBB.mjs} +193 -79
- package/dist/chunk-SZEBCNBB.mjs.map +1 -0
- package/dist/{chunk-5EE2EFPE.mjs → chunk-VOVLPSG6.mjs} +29 -52
- package/dist/chunk-VOVLPSG6.mjs.map +1 -0
- package/dist/chunk-YAQLYL52.mjs +14 -0
- package/dist/chunk-YAQLYL52.mjs.map +1 -0
- package/dist/{chunk-326OCJOT.mjs → chunk-ZVWUR7ET.mjs} +2 -2
- package/dist/cli.mjs +10 -7
- package/dist/contacts-worker.mjs +2 -2
- package/dist/global-insight-worker.mjs +179 -0
- package/dist/global-insight-worker.mjs.map +1 -0
- package/dist/{http-L4AMELPZ.mjs → http-M6NHWJZD.mjs} +12 -11
- package/dist/{import-WWCSXGVS.mjs → import-SEYHFXS5.mjs} +12 -7
- package/dist/index.mjs +13 -12
- package/dist/{mcp-A4M3LT5O.mjs → mcp-MIPFYRLV.mjs} +12 -11
- package/dist/{mcp-A4M3LT5O.mjs.map → mcp-MIPFYRLV.mjs.map} +1 -1
- package/dist/people-relationships-worker.mjs +2 -2
- package/dist/semantic-index-worker.mjs +1 -1
- package/dist/{src-MPNBTFOE.mjs → src-7OD6RD5V.mjs} +38 -6
- package/dist/{stream-import-HIE7PNL4.mjs → stream-import-AWEHGQJY.mjs} +12 -7
- package/dist/{worker-runtime-BJXO24XX.mjs → worker-runtime-TGYMASIE.mjs} +6 -5
- package/dist/{worker-runtime-BJXO24XX.mjs.map → worker-runtime-TGYMASIE.mjs.map} +1 -1
- package/dist-web/assets/ActionToolsPanel-fAio70bI.css +1 -0
- package/dist-web/assets/ActionToolsPanel.vue_vue_type_script_setup_true_lang-CkDGVRXe.js +110 -0
- package/dist-web/assets/{BufferResource-q3rzaWWd.js → BufferResource-CHI62pIA.js} +1 -1
- package/dist-web/assets/{CanvasRenderer-BRk1y8tp.js → CanvasRenderer-OZRoiF0j.js} +1 -1
- package/dist-web/assets/{EChartWordcloud-Clg60FMo.js → EChartWordcloud-DU3ZYdgz.js} +1 -1
- package/dist-web/assets/{Filter-BJwode73.js → Filter-DNb5VErW.js} +1 -1
- package/dist-web/assets/{LoadingState.vue_vue_type_script_setup_true_lang-D_dJuLWJ.js → LoadingState.vue_vue_type_script_setup_true_lang-DACMroOe.js} +1 -1
- package/dist-web/assets/MessageExportModal-CqP-w7HP.js +1 -0
- package/dist-web/assets/PageHeader-Ck8ULyZH.js +1 -0
- package/dist-web/assets/PageHeader-XIXMTomn.css +1 -0
- package/dist-web/assets/{RelationshipGalaxyCanvas-CORMD7vL.js → RelationshipGalaxyCanvas-ioRNObb5.js} +3 -3
- package/dist-web/assets/{RelationshipGalaxyThreeCanvas-B_w_P4ob.js → RelationshipGalaxyThreeCanvas-L1Y43p1A.js} +1 -1
- package/dist-web/assets/{RenderTargetSystem-CGhV9R9E.js → RenderTargetSystem-fJ7D7Chv.js} +1 -1
- package/dist-web/assets/ThemeCard.vue_vue_type_script_setup_true_lang-BoZyssJF.js +1 -0
- package/dist-web/assets/TimeSelect.vue_vue_type_script_setup_true_lang-7SEaCxDL.js +1 -0
- package/dist-web/assets/{WebGLRenderer-CAokTE5X.js → WebGLRenderer-BD3ZUtxH.js} +1 -1
- package/dist-web/assets/{WebGPURenderer-DzP4ggSy.js → WebGPURenderer-DZXYsT6D.js} +1 -1
- package/dist-web/assets/annual-summary-time-range-DVLXK1r4.js +1 -0
- package/dist-web/assets/base-DTElkJcC.js +1 -0
- package/dist-web/assets/{browserAll-CAZCK6dd.js → browserAll-ChT6N6a9.js} +1 -1
- package/dist-web/assets/dateFormat-D9WibwOu.js +1 -0
- package/dist-web/assets/{electron-CkPDbAaS.js → electron-CIzyGxH_.js} +1 -1
- package/dist-web/assets/electron-hcWiB7Gg.js +1 -0
- package/dist-web/assets/fetch-Avtnh8cJ.js +3 -0
- package/dist-web/assets/{fetch-DQ9UNNAy.js → fetch-BFnrBahy.js} +1 -1
- package/dist-web/assets/fetch-C9rx2isC.js +31 -0
- package/dist-web/assets/fetch-Ccq_0ecb.js +1 -0
- package/dist-web/assets/{fetch-BIEXkvDq.js → fetch-CuiQUcO_.js} +1 -1
- package/dist-web/assets/{fetch-LX9jrJCC.js → fetch-CyKILLnB.js} +1 -1
- package/dist-web/assets/fetch-Dd6t3p1r.js +6 -0
- package/dist-web/assets/{fetch--UbRoBT7.js → fetch-DnGx-1_t.js} +1 -1
- package/dist-web/assets/{fetch-wqMSiaK3.js → fetch-qC7om4QG.js} +1 -1
- package/dist-web/assets/fetch-wSSfDBdV.js +1 -0
- package/dist-web/assets/index-BH9jI5kV.js +173 -0
- package/dist-web/assets/index-BWtNqcYK.js +22 -0
- package/dist-web/assets/index-BfO_LpDv.css +1 -0
- package/dist-web/assets/index-Bkq7-GBp.js +1 -0
- package/dist-web/assets/index-Bqr-LkS1.css +1 -0
- package/dist-web/assets/index-ByUaiVQK.css +1 -0
- package/dist-web/assets/index-C6qtsaP7.js +1 -0
- package/dist-web/assets/index-C_0GHEcb.css +1 -0
- package/dist-web/assets/index-ChFGuu70.js +1 -0
- package/dist-web/assets/{index-S-YQRH1E.js → index-CiS20iAR.js} +1 -1
- package/dist-web/assets/index-CqD6u57u.js +1 -0
- package/dist-web/assets/index-CzDG8LVr.js +2 -0
- package/dist-web/assets/index-D0Euk-vQ.js +1 -0
- package/dist-web/assets/index-D26BWhHz.js +1 -0
- package/dist-web/assets/index-DXHYzIIj.js +1 -0
- package/dist-web/assets/index-Dq8u7gMb.js +2 -0
- package/dist-web/assets/index-ZsZwPLWy.css +1 -0
- package/dist-web/assets/index-u_UH6rDY.js +64 -0
- package/dist-web/assets/index-y7cxH1Et.css +1 -0
- package/dist-web/assets/{people-page-header-Mupn-U_b.js → people-page-header-BdKM1qhX.js} +1 -1
- package/dist-web/assets/types-CZnACqaB.js +1 -0
- package/dist-web/assets/{vendor-echarts-hJVnODyU.js → vendor-echarts-B-i_56Av.js} +1 -1
- package/dist-web/assets/{vendor-echarts-wordcloud-k5ih2Jl4.js → vendor-echarts-wordcloud-Ca8n6qS6.js} +1 -1
- package/dist-web/assets/{vendor-nuxt-ui-DaLxYaC4.js → vendor-nuxt-ui-CS1uxE9C.js} +2 -2
- package/dist-web/assets/{vendor-reka-ui-CzM4kDQ7.js → vendor-reka-ui-Cta6JPvN.js} +1 -1
- package/dist-web/assets/{web-DbKs6-1b.js → web-BDBdpdK7.js} +1 -1
- package/dist-web/assets/{webworkerAll-Bhv-hBqR.js → webworkerAll-C3dAOQj4.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chunk-36JGKW6K.mjs.map +0 -1
- package/dist/chunk-5EE2EFPE.mjs.map +0 -1
- package/dist/chunk-D3DPCDII.mjs.map +0 -1
- package/dist/chunk-KBSAVUFV.mjs +0 -161
- package/dist/chunk-KBSAVUFV.mjs.map +0 -1
- package/dist/chunk-LVEJHB3X.mjs.map +0 -1
- package/dist/chunk-M2PXDX4G.mjs.map +0 -1
- package/dist/chunk-TCZHG3G7.mjs.map +0 -1
- package/dist/chunk-TEX44HNL.mjs.map +0 -1
- package/dist/chunk-WV5GSRQM.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel-D_lFIW6j.css +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-F4n0zNX2.js +0 -110
- package/dist-web/assets/MessageExportModal-CGcdMOyw.js +0 -1
- package/dist-web/assets/PageHeader-Bbn87QZS.css +0 -1
- package/dist-web/assets/PageHeader-CZaqOdBQ.js +0 -1
- package/dist-web/assets/electron-D9vE5t3H.js +0 -1
- package/dist-web/assets/fetch-1pB-HbYw.js +0 -3
- package/dist-web/assets/fetch-Apd5OLJw.js +0 -5
- package/dist-web/assets/fetch-B8rik0TM.js +0 -17
- package/dist-web/assets/fetch-CF_3ZqRa.js +0 -1
- package/dist-web/assets/fetch-FSNxSnAp.js +0 -1
- package/dist-web/assets/index---rXG1hZ.css +0 -1
- package/dist-web/assets/index-B01uUoHE.js +0 -1
- package/dist-web/assets/index-B4l3rHie.css +0 -1
- package/dist-web/assets/index-BSIyyt0z.js +0 -1
- package/dist-web/assets/index-Bh8z441f.js +0 -2
- package/dist-web/assets/index-C0rya8v4.js +0 -1
- package/dist-web/assets/index-C1p9CbmN.css +0 -1
- package/dist-web/assets/index-COpza1A4.css +0 -1
- package/dist-web/assets/index-CZbZv2fh.js +0 -64
- package/dist-web/assets/index-CqUuHQBQ.js +0 -22
- package/dist-web/assets/index-CzeTP5MJ.js +0 -173
- package/dist-web/assets/index-DgNxTM_8.js +0 -2
- package/dist-web/assets/index-DosG7LmJ.css +0 -1
- /package/dist/{chunk-ULNRUS55.mjs.map → chunk-E6W2RURS.mjs.map} +0 -0
- /package/dist/{chunk-326OCJOT.mjs.map → chunk-ZVWUR7ET.mjs.map} +0 -0
- /package/dist/{http-L4AMELPZ.mjs.map → http-M6NHWJZD.mjs.map} +0 -0
- /package/dist/{import-WWCSXGVS.mjs.map → import-SEYHFXS5.mjs.map} +0 -0
- /package/dist/{src-MPNBTFOE.mjs.map → src-7OD6RD5V.mjs.map} +0 -0
- /package/dist/{stream-import-HIE7PNL4.mjs.map → stream-import-AWEHGQJY.mjs.map} +0 -0
|
@@ -6,13 +6,14 @@ const __filename = __fileURLToPath(import.meta.url);
|
|
|
6
6
|
const __dirname = __pathDirname(__filename);
|
|
7
7
|
import {
|
|
8
8
|
createCliRunAgentStream
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-VOVLPSG6.mjs";
|
|
10
|
+
import "./chunk-3VMKS7PU.mjs";
|
|
11
|
+
import "./chunk-E6W2RURS.mjs";
|
|
12
|
+
import "./chunk-KCPGEILH.mjs";
|
|
13
|
+
import "./chunk-7HBVGVOB.mjs";
|
|
14
|
+
import "./chunk-LJXSUN25.mjs";
|
|
15
|
+
import "./chunk-YAQLYL52.mjs";
|
|
16
|
+
import "./chunk-DQ45LDKZ.mjs";
|
|
16
17
|
import "./chunk-GFHSSCCR.mjs";
|
|
17
18
|
|
|
18
19
|
// src/ai/chat-command.ts
|
|
@@ -305,4 +306,4 @@ export {
|
|
|
305
306
|
runChatCommand,
|
|
306
307
|
runChatTurn
|
|
307
308
|
};
|
|
308
|
-
//# sourceMappingURL=chat-command-
|
|
309
|
+
//# sourceMappingURL=chat-command-MOETAGU5.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ai/chat-command.ts"],"sourcesContent":["import { createInterface } from 'node:readline/promises'\nimport type { Readable, Writable } from 'node:stream'\nimport type {\n DatabaseManager,\n AIChatManager,\n AgentStreamChunk,\n ContentBlock,\n PlanContentBlock,\n PlanDraftContentBlock,\n TokenUsageData,\n} from '@openchatlab/node-runtime'\nimport type { ChartPayload, PathProvider } from '@openchatlab/core'\nimport { createCliRunAgentStream } from './agent-stream-runner'\n\nexport interface ChatCommandOptions {\n sessionId?: string\n aiChatId?: string\n question?: string\n json?: boolean\n stream?: boolean\n locale?: string\n includeEvents?: boolean\n}\n\nexport interface ChatCommandDeps {\n dbManager: DatabaseManager\n pathProvider: PathProvider\n aiChatManager: AIChatManager\n stdout?: Pick<Writable, 'write'>\n stderr?: Pick<Writable, 'write'>\n stdin?: Readable\n createRunAgentStream?: typeof createCliRunAgentStream\n}\n\nexport interface ResolvedAIChatTarget {\n sessionId: string\n aiChatId: string\n assistantId: string\n created: boolean\n}\n\nexport interface ChatTurnResult {\n sessionId: string\n aiChatId: string\n question: string\n answer: string\n events?: AgentStreamChunk[]\n contentBlocks?: ContentBlock[]\n usage: {\n durationMs: number\n tokenUsage: TokenUsageData | null\n }\n}\n\nfunction write(stream: Pick<Writable, 'write'>, text: string): void {\n stream.write(text)\n}\n\nfunction buildTitle(question?: string): string {\n const trimmed = question?.trim()\n if (!trimmed) return 'CLI Chat'\n return trimmed.length > 50 ? `${trimmed.slice(0, 50)}...` : trimmed\n}\n\nfunction createAgentStreamError(error: unknown): Error {\n if (error instanceof Error) return error\n if (typeof error === 'string' && error) return new Error(error)\n if (typeof error === 'object' && error !== null) {\n const record = error as { name?: unknown; message?: unknown; stack?: unknown }\n const streamError = new Error(\n typeof record.message === 'string' && record.message ? record.message : 'Agent stream failed'\n )\n if (typeof record.name === 'string' && record.name) streamError.name = record.name\n if (typeof record.stack === 'string' && record.stack) streamError.stack = record.stack\n return streamError\n }\n return new Error('Agent stream failed')\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction isChartPayload(value: unknown): value is ChartPayload {\n return isRecord(value) && value.version === 1 && isRecord(value.spec) && isRecord(value.dataset)\n}\n\nfunction extractChartPayloads(toolResult: unknown): ChartPayload[] {\n if (!isRecord(toolResult)) return []\n const details = isRecord(toolResult.details) ? toolResult.details : toolResult\n const charts: ChartPayload[] = []\n if (isChartPayload(details.chart)) charts.push(details.chart)\n if (Array.isArray(details.charts)) {\n for (const chart of details.charts) {\n if (isChartPayload(chart)) charts.push(chart)\n }\n }\n return charts\n}\n\nfunction toPersistedChartPayload(chart: ChartPayload): ChartPayload {\n return {\n ...chart,\n dataset: {\n ...chart.dataset,\n rows: [],\n },\n }\n}\n\nfunction resolveSingleSessionId(dbManager: DatabaseManager): string {\n const sessionIds = dbManager.listSessionIds()\n if (sessionIds.length === 1) return sessionIds[0]!\n if (sessionIds.length === 0) {\n throw new Error('No chat sessions found. Import data first or run `chatlab sessions` to verify available sessions.')\n }\n throw new Error('Missing --session-id. Run `chatlab sessions` to choose a session ID.')\n}\n\nfunction assertSessionExists(dbManager: DatabaseManager, sessionId: string): void {\n const db = dbManager.open(sessionId)\n if (!db) {\n throw new Error(`Session ${sessionId} not found`)\n }\n}\n\nexport function resolveAIChatTarget(\n options: Pick<ChatCommandOptions, 'sessionId' | 'aiChatId' | 'question'>,\n deps: Pick<ChatCommandDeps, 'dbManager' | 'aiChatManager'>\n): ResolvedAIChatTarget {\n if (options.aiChatId) {\n const aiChat = deps.aiChatManager.getAIChat(options.aiChatId)\n if (!aiChat) {\n throw new Error(`AI chat ${options.aiChatId} not found`)\n }\n if (options.sessionId && options.sessionId !== aiChat.sessionId) {\n throw new Error(`AI chat ${options.aiChatId} belongs to session ${aiChat.sessionId}, not ${options.sessionId}`)\n }\n assertSessionExists(deps.dbManager, aiChat.sessionId)\n return { sessionId: aiChat.sessionId, aiChatId: aiChat.id, assistantId: aiChat.assistantId, created: false }\n }\n\n const sessionId = options.sessionId ?? resolveSingleSessionId(deps.dbManager)\n assertSessionExists(deps.dbManager, sessionId)\n const aiChat = deps.aiChatManager.createAIChat(sessionId, buildTitle(options.question), 'general_cn')\n return { sessionId, aiChatId: aiChat.id, assistantId: aiChat.assistantId, created: true }\n}\n\nexport async function runChatTurn(\n options: Required<Pick<ChatCommandOptions, 'question'>> &\n Pick<ChatCommandOptions, 'sessionId' | 'aiChatId' | 'json' | 'stream' | 'locale' | 'includeEvents'>,\n deps: ChatCommandDeps\n): Promise<ChatTurnResult> {\n const stdout = deps.stdout ?? process.stdout\n const target = resolveAIChatTarget(options, deps)\n const startedAt = Date.now()\n let answer = ''\n let tokenUsage: TokenUsageData | null = null\n let streamError: Error | null = null\n const events: AgentStreamChunk[] = []\n const contentBlocks: ContentBlock[] = []\n let hasReplayContentBlocks = false\n\n const runAgentStream = (deps.createRunAgentStream ?? createCliRunAgentStream)(deps.dbManager, deps.aiChatManager)\n\n // 中文注释:CLI 历史回放依赖 contentBlocks 的时序;只要出现计划/思考块,\n // 就同步保留后续正文 text block,避免 UI 使用 blocks 渲染时丢失最终回答。\n const appendTextBlock = (text: string) => {\n if (!text) return\n const lastBlock = contentBlocks[contentBlocks.length - 1]\n if (lastBlock?.type === 'text') {\n lastBlock.text += text\n } else {\n contentBlocks.push({ type: 'text', text })\n }\n }\n\n const appendThinkBlock = (text: string, tag = 'thinking', durationMs?: number) => {\n if (!text && durationMs === undefined) return\n const lastBlock = contentBlocks[contentBlocks.length - 1]\n let targetBlock: ContentBlock | undefined\n\n if (lastBlock?.type === 'think' && lastBlock.tag === tag) {\n lastBlock.text += text\n targetBlock = lastBlock\n } else if (text.trim().length > 0) {\n targetBlock = { type: 'think', tag, text }\n contentBlocks.push(targetBlock)\n } else if (durationMs !== undefined) {\n for (let index = contentBlocks.length - 1; index >= 0; index--) {\n const block = contentBlocks[index]\n if (block.type === 'think' && block.tag === tag) {\n targetBlock = block\n break\n }\n }\n }\n\n if (durationMs !== undefined && targetBlock?.type === 'think') {\n targetBlock.durationMs = durationMs\n }\n if (targetBlock?.type === 'think') {\n hasReplayContentBlocks = true\n }\n }\n\n const appendChartBlocks = (charts: ChartPayload[]) => {\n if (charts.length === 0) return\n // 中文注释:图表 block 需要持久化给 CLI 生成的 AI 对话回放;\n // 原始 SQL 行数据可能较大,保存时只保留渲染数据和字段元信息。\n contentBlocks.push(...charts.map((chart) => ({ type: 'chart' as const, chart: toPersistedChartPayload(chart) })))\n hasReplayContentBlocks = true\n }\n\n const appendPlanDraftBlock = (delta: string) => {\n if (!delta) return\n const lastBlock = contentBlocks[contentBlocks.length - 1]\n if (lastBlock?.type === 'plan_draft') {\n lastBlock.text += delta\n } else {\n contentBlocks.push({ type: 'plan_draft', version: 1, status: 'streaming', text: delta } as PlanDraftContentBlock)\n }\n hasReplayContentBlocks = true\n }\n\n const removePlanDraftBlocks = () => {\n for (let index = contentBlocks.length - 1; index >= 0; index--) {\n if (contentBlocks[index]?.type === 'plan_draft') {\n contentBlocks.splice(index, 1)\n }\n }\n }\n\n const appendFinalPlanBlock = (plan: PlanContentBlock) => {\n const planBlock = JSON.parse(JSON.stringify(plan)) as PlanContentBlock\n for (let index = contentBlocks.length - 1; index >= 0; index--) {\n const block = contentBlocks[index]\n if (block?.type === 'plan_draft') {\n const displayText = block.text.trim()\n if (displayText) planBlock.displayText = displayText\n contentBlocks[index] = planBlock\n hasReplayContentBlocks = true\n return\n }\n }\n contentBlocks.push(planBlock)\n hasReplayContentBlocks = true\n }\n\n await runAgentStream(\n {\n userMessage: options.question,\n sessionId: target.sessionId,\n aiChatId: target.aiChatId,\n assistantId: target.assistantId,\n chatType: 'group',\n locale: options.locale ?? 'zh-CN',\n enableAutoSkill: true,\n chartAutoMode: 'suggest',\n },\n (chunk: AgentStreamChunk) => {\n if (options.includeEvents) {\n events.push(JSON.parse(JSON.stringify(chunk)) as AgentStreamChunk)\n }\n if (chunk.type === 'error') {\n removePlanDraftBlocks()\n streamError = createAgentStreamError(chunk.error)\n return\n }\n if (chunk.type === 'plan_delta' && chunk.planDelta) {\n appendPlanDraftBlock(chunk.planDelta)\n return\n }\n if (chunk.type === 'plan' && chunk.plan) {\n appendFinalPlanBlock(chunk.plan)\n return\n }\n if (chunk.type === 'plan_skipped') {\n removePlanDraftBlocks()\n return\n }\n if (chunk.type === 'think') {\n appendThinkBlock(chunk.content ?? '', chunk.thinkTag, chunk.thinkDurationMs)\n return\n }\n if (chunk.type === 'tool_result' && chunk.toolName === 'render_chart') {\n appendChartBlocks(extractChartPayloads(chunk.toolResult))\n return\n }\n if (chunk.type === 'content' && chunk.content) {\n answer += chunk.content\n appendTextBlock(chunk.content)\n if (!options.json && options.stream !== false) write(stdout, chunk.content)\n }\n if (chunk.type === 'done' && chunk.usage) {\n tokenUsage = chunk.usage\n for (let index = contentBlocks.length - 1; index >= 0; index--) {\n const block = contentBlocks[index]\n if (block.type === 'plan') {\n block.status = 'done'\n break\n }\n }\n }\n },\n new AbortController().signal\n )\n\n if (streamError) throw streamError\n\n if (!options.json && options.stream !== false && answer && !answer.endsWith('\\n')) {\n write(stdout, '\\n')\n }\n\n deps.aiChatManager.addMessage(target.aiChatId, 'user', options.question)\n deps.aiChatManager.addMessage(\n target.aiChatId,\n 'assistant',\n answer,\n undefined,\n undefined,\n hasReplayContentBlocks ? contentBlocks : undefined,\n tokenUsage ?? undefined\n )\n\n return {\n sessionId: target.sessionId,\n aiChatId: target.aiChatId,\n question: options.question,\n answer,\n ...(options.includeEvents ? { events } : {}),\n ...(hasReplayContentBlocks ? { contentBlocks } : {}),\n usage: {\n durationMs: Date.now() - startedAt,\n tokenUsage,\n },\n }\n}\n\nexport async function runChatCommand(options: ChatCommandOptions, deps: ChatCommandDeps): Promise<void> {\n const stdout = deps.stdout ?? process.stdout\n const stderr = deps.stderr ?? process.stderr\n\n if (options.question?.trim()) {\n const result = await runChatTurn({ ...options, question: options.question.trim() }, deps)\n if (options.json) {\n write(stdout, `${JSON.stringify(result, null, 2)}\\n`)\n } else if (options.stream === false) {\n write(stdout, `${result.answer}\\n`)\n }\n return\n }\n\n const rl = createInterface({\n input: deps.stdin ?? process.stdin,\n output: stdout as Writable,\n })\n\n try {\n let aiChatId = options.aiChatId\n while (true) {\n const question = (await rl.question('chatlab> ')).trim()\n if (!question || question === 'exit' || question === 'quit') break\n try {\n const result = await runChatTurn({ ...options, aiChatId, question, json: false, stream: true }, deps)\n aiChatId = result.aiChatId\n } catch (error) {\n write(stderr, `${error instanceof Error ? error.message : String(error)}\\n`)\n }\n }\n } finally {\n rl.close()\n }\n}\n"],"mappings":"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","names":["aiChat"]}
|
|
1
|
+
{"version":3,"sources":["../src/ai/chat-command.ts"],"sourcesContent":["import { createInterface } from 'node:readline/promises'\nimport type { Readable, Writable } from 'node:stream'\nimport type {\n DatabaseManager,\n AIChatManager,\n AgentStreamChunk,\n ContentBlock,\n PlanContentBlock,\n PlanDraftContentBlock,\n TokenUsageData,\n} from '@openchatlab/node-runtime'\nimport type { ChartPayload, PathProvider } from '@openchatlab/core'\nimport { createCliRunAgentStream } from './agent-stream-runner'\n\nexport interface ChatCommandOptions {\n sessionId?: string\n aiChatId?: string\n question?: string\n json?: boolean\n stream?: boolean\n locale?: string\n includeEvents?: boolean\n}\n\nexport interface ChatCommandDeps {\n dbManager: DatabaseManager\n pathProvider: PathProvider\n aiChatManager: AIChatManager\n stdout?: Pick<Writable, 'write'>\n stderr?: Pick<Writable, 'write'>\n stdin?: Readable\n createRunAgentStream?: typeof createCliRunAgentStream\n}\n\nexport interface ResolvedAIChatTarget {\n sessionId: string\n aiChatId: string\n assistantId: string\n created: boolean\n}\n\nexport interface ChatTurnResult {\n sessionId: string\n aiChatId: string\n question: string\n answer: string\n events?: AgentStreamChunk[]\n contentBlocks?: ContentBlock[]\n usage: {\n durationMs: number\n tokenUsage: TokenUsageData | null\n }\n}\n\nfunction write(stream: Pick<Writable, 'write'>, text: string): void {\n stream.write(text)\n}\n\nfunction buildTitle(question?: string): string {\n const trimmed = question?.trim()\n if (!trimmed) return 'CLI Chat'\n return trimmed.length > 50 ? `${trimmed.slice(0, 50)}...` : trimmed\n}\n\nfunction createAgentStreamError(error: unknown): Error {\n if (error instanceof Error) return error\n if (typeof error === 'string' && error) return new Error(error)\n if (typeof error === 'object' && error !== null) {\n const record = error as { name?: unknown; message?: unknown; stack?: unknown }\n const streamError = new Error(\n typeof record.message === 'string' && record.message ? record.message : 'Agent stream failed'\n )\n if (typeof record.name === 'string' && record.name) streamError.name = record.name\n if (typeof record.stack === 'string' && record.stack) streamError.stack = record.stack\n return streamError\n }\n return new Error('Agent stream failed')\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction isChartPayload(value: unknown): value is ChartPayload {\n return isRecord(value) && value.version === 1 && isRecord(value.spec) && isRecord(value.dataset)\n}\n\nfunction extractChartPayloads(toolResult: unknown): ChartPayload[] {\n if (!isRecord(toolResult)) return []\n const details = isRecord(toolResult.details) ? toolResult.details : toolResult\n const charts: ChartPayload[] = []\n if (isChartPayload(details.chart)) charts.push(details.chart)\n if (Array.isArray(details.charts)) {\n for (const chart of details.charts) {\n if (isChartPayload(chart)) charts.push(chart)\n }\n }\n return charts\n}\n\nfunction toPersistedChartPayload(chart: ChartPayload): ChartPayload {\n return {\n ...chart,\n dataset: {\n ...chart.dataset,\n rows: [],\n },\n }\n}\n\nfunction resolveSingleSessionId(dbManager: DatabaseManager): string {\n const sessionIds = dbManager.listSessionIds()\n if (sessionIds.length === 1) return sessionIds[0]!\n if (sessionIds.length === 0) {\n throw new Error('No chat sessions found. Import data first or run `chatlab sessions` to verify available sessions.')\n }\n throw new Error('Missing --session-id. Run `chatlab sessions` to choose a session ID.')\n}\n\nfunction assertSessionExists(dbManager: DatabaseManager, sessionId: string): void {\n const db = dbManager.open(sessionId)\n if (!db) {\n throw new Error(`Session ${sessionId} not found`)\n }\n}\n\nexport function resolveAIChatTarget(\n options: Pick<ChatCommandOptions, 'sessionId' | 'aiChatId' | 'question'>,\n deps: Pick<ChatCommandDeps, 'dbManager' | 'aiChatManager'>\n): ResolvedAIChatTarget {\n if (options.aiChatId) {\n const aiChat = deps.aiChatManager.getAIChat(options.aiChatId)\n if (!aiChat) {\n throw new Error(`AI chat ${options.aiChatId} not found`)\n }\n if (options.sessionId && options.sessionId !== aiChat.sessionId) {\n throw new Error(`AI chat ${options.aiChatId} belongs to session ${aiChat.sessionId}, not ${options.sessionId}`)\n }\n assertSessionExists(deps.dbManager, aiChat.sessionId)\n return { sessionId: aiChat.sessionId, aiChatId: aiChat.id, assistantId: aiChat.assistantId, created: false }\n }\n\n const sessionId = options.sessionId ?? resolveSingleSessionId(deps.dbManager)\n assertSessionExists(deps.dbManager, sessionId)\n const aiChat = deps.aiChatManager.createAIChat(sessionId, buildTitle(options.question), 'general_cn')\n return { sessionId, aiChatId: aiChat.id, assistantId: aiChat.assistantId, created: true }\n}\n\nexport async function runChatTurn(\n options: Required<Pick<ChatCommandOptions, 'question'>> &\n Pick<ChatCommandOptions, 'sessionId' | 'aiChatId' | 'json' | 'stream' | 'locale' | 'includeEvents'>,\n deps: ChatCommandDeps\n): Promise<ChatTurnResult> {\n const stdout = deps.stdout ?? process.stdout\n const target = resolveAIChatTarget(options, deps)\n const startedAt = Date.now()\n let answer = ''\n let tokenUsage: TokenUsageData | null = null\n let streamError: Error | null = null\n const events: AgentStreamChunk[] = []\n const contentBlocks: ContentBlock[] = []\n let hasReplayContentBlocks = false\n\n const runAgentStream = (deps.createRunAgentStream ?? createCliRunAgentStream)(deps.dbManager, deps.aiChatManager)\n\n // 中文注释:CLI 历史回放依赖 contentBlocks 的时序;只要出现计划/思考块,\n // 就同步保留后续正文 text block,避免 UI 使用 blocks 渲染时丢失最终回答。\n const appendTextBlock = (text: string) => {\n if (!text) return\n const lastBlock = contentBlocks[contentBlocks.length - 1]\n if (lastBlock?.type === 'text') {\n lastBlock.text += text\n } else {\n contentBlocks.push({ type: 'text', text })\n }\n }\n\n const appendThinkBlock = (text: string, tag = 'thinking', durationMs?: number) => {\n if (!text && durationMs === undefined) return\n const lastBlock = contentBlocks[contentBlocks.length - 1]\n let targetBlock: ContentBlock | undefined\n\n if (lastBlock?.type === 'think' && lastBlock.tag === tag) {\n lastBlock.text += text\n targetBlock = lastBlock\n } else if (text.trim().length > 0) {\n targetBlock = { type: 'think', tag, text }\n contentBlocks.push(targetBlock)\n } else if (durationMs !== undefined) {\n for (let index = contentBlocks.length - 1; index >= 0; index--) {\n const block = contentBlocks[index]\n if (block.type === 'think' && block.tag === tag) {\n targetBlock = block\n break\n }\n }\n }\n\n if (durationMs !== undefined && targetBlock?.type === 'think') {\n targetBlock.durationMs = durationMs\n }\n if (targetBlock?.type === 'think') {\n hasReplayContentBlocks = true\n }\n }\n\n const appendChartBlocks = (charts: ChartPayload[]) => {\n if (charts.length === 0) return\n // 中文注释:图表 block 需要持久化给 CLI 生成的 AI 对话回放;\n // 原始 SQL 行数据可能较大,保存时只保留渲染数据和字段元信息。\n contentBlocks.push(...charts.map((chart) => ({ type: 'chart' as const, chart: toPersistedChartPayload(chart) })))\n hasReplayContentBlocks = true\n }\n\n const appendPlanDraftBlock = (delta: string) => {\n if (!delta) return\n const lastBlock = contentBlocks[contentBlocks.length - 1]\n if (lastBlock?.type === 'plan_draft') {\n lastBlock.text += delta\n } else {\n contentBlocks.push({ type: 'plan_draft', version: 1, status: 'streaming', text: delta } as PlanDraftContentBlock)\n }\n hasReplayContentBlocks = true\n }\n\n const removePlanDraftBlocks = () => {\n for (let index = contentBlocks.length - 1; index >= 0; index--) {\n if (contentBlocks[index]?.type === 'plan_draft') {\n contentBlocks.splice(index, 1)\n }\n }\n }\n\n const appendFinalPlanBlock = (plan: PlanContentBlock) => {\n const planBlock = JSON.parse(JSON.stringify(plan)) as PlanContentBlock\n for (let index = contentBlocks.length - 1; index >= 0; index--) {\n const block = contentBlocks[index]\n if (block?.type === 'plan_draft') {\n const displayText = block.text.trim()\n if (displayText) planBlock.displayText = displayText\n contentBlocks[index] = planBlock\n hasReplayContentBlocks = true\n return\n }\n }\n contentBlocks.push(planBlock)\n hasReplayContentBlocks = true\n }\n\n await runAgentStream(\n {\n userMessage: options.question,\n sessionId: target.sessionId,\n aiChatId: target.aiChatId,\n assistantId: target.assistantId,\n chatType: 'group',\n locale: options.locale ?? 'zh-CN',\n enableAutoSkill: true,\n chartAutoMode: 'suggest',\n },\n (chunk: AgentStreamChunk) => {\n if (options.includeEvents) {\n events.push(JSON.parse(JSON.stringify(chunk)) as AgentStreamChunk)\n }\n if (chunk.type === 'error') {\n removePlanDraftBlocks()\n streamError = createAgentStreamError(chunk.error)\n return\n }\n if (chunk.type === 'plan_delta' && chunk.planDelta) {\n appendPlanDraftBlock(chunk.planDelta)\n return\n }\n if (chunk.type === 'plan' && chunk.plan) {\n appendFinalPlanBlock(chunk.plan)\n return\n }\n if (chunk.type === 'plan_skipped') {\n removePlanDraftBlocks()\n return\n }\n if (chunk.type === 'think') {\n appendThinkBlock(chunk.content ?? '', chunk.thinkTag, chunk.thinkDurationMs)\n return\n }\n if (chunk.type === 'tool_result' && chunk.toolName === 'render_chart') {\n appendChartBlocks(extractChartPayloads(chunk.toolResult))\n return\n }\n if (chunk.type === 'content' && chunk.content) {\n answer += chunk.content\n appendTextBlock(chunk.content)\n if (!options.json && options.stream !== false) write(stdout, chunk.content)\n }\n if (chunk.type === 'done' && chunk.usage) {\n tokenUsage = chunk.usage\n for (let index = contentBlocks.length - 1; index >= 0; index--) {\n const block = contentBlocks[index]\n if (block.type === 'plan') {\n block.status = 'done'\n break\n }\n }\n }\n },\n new AbortController().signal\n )\n\n if (streamError) throw streamError\n\n if (!options.json && options.stream !== false && answer && !answer.endsWith('\\n')) {\n write(stdout, '\\n')\n }\n\n deps.aiChatManager.addMessage(target.aiChatId, 'user', options.question)\n deps.aiChatManager.addMessage(\n target.aiChatId,\n 'assistant',\n answer,\n undefined,\n undefined,\n hasReplayContentBlocks ? contentBlocks : undefined,\n tokenUsage ?? undefined\n )\n\n return {\n sessionId: target.sessionId,\n aiChatId: target.aiChatId,\n question: options.question,\n answer,\n ...(options.includeEvents ? { events } : {}),\n ...(hasReplayContentBlocks ? { contentBlocks } : {}),\n usage: {\n durationMs: Date.now() - startedAt,\n tokenUsage,\n },\n }\n}\n\nexport async function runChatCommand(options: ChatCommandOptions, deps: ChatCommandDeps): Promise<void> {\n const stdout = deps.stdout ?? process.stdout\n const stderr = deps.stderr ?? process.stderr\n\n if (options.question?.trim()) {\n const result = await runChatTurn({ ...options, question: options.question.trim() }, deps)\n if (options.json) {\n write(stdout, `${JSON.stringify(result, null, 2)}\\n`)\n } else if (options.stream === false) {\n write(stdout, `${result.answer}\\n`)\n }\n return\n }\n\n const rl = createInterface({\n input: deps.stdin ?? process.stdin,\n output: stdout as Writable,\n })\n\n try {\n let aiChatId = options.aiChatId\n while (true) {\n const question = (await rl.question('chatlab> ')).trim()\n if (!question || question === 'exit' || question === 'quit') break\n try {\n const result = await runChatTurn({ ...options, aiChatId, question, json: false, stream: true }, deps)\n aiChatId = result.aiChatId\n } catch (error) {\n write(stderr, `${error instanceof Error ? error.message : String(error)}\\n`)\n }\n }\n } finally {\n rl.close()\n }\n}\n"],"mappings":"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","names":["aiChat"]}
|
|
@@ -4,38 +4,46 @@ import { fileURLToPath as __fileURLToPath } from 'url';
|
|
|
4
4
|
const require = __createRequire(import.meta.url);
|
|
5
5
|
const __filename = __fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = __pathDirname(__filename);
|
|
7
|
+
import {
|
|
8
|
+
analyzeAutoImport,
|
|
9
|
+
autoImport
|
|
10
|
+
} from "./chunk-N5AGDT7I.mjs";
|
|
7
11
|
import {
|
|
8
12
|
assertCliDataDirCompatible
|
|
9
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ZVWUR7ET.mjs";
|
|
10
14
|
import {
|
|
11
15
|
getVersion
|
|
12
16
|
} from "./chunk-5ADKYYNA.mjs";
|
|
13
|
-
import {
|
|
14
|
-
resolveCliPath
|
|
15
|
-
} from "./chunk-FJ35V3TE.mjs";
|
|
16
17
|
import {
|
|
17
18
|
NodePathProvider,
|
|
18
19
|
PreferencesManager,
|
|
19
20
|
applyPendingNodeDataDirMigrationIfNeeded,
|
|
20
21
|
getSystemLogsDir,
|
|
21
22
|
hasPendingElectronDataWarning
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-E6W2RURS.mjs";
|
|
23
24
|
import {
|
|
24
25
|
AIChatManager,
|
|
26
|
+
IMPORT_IN_PROGRESS_ERROR_KEY,
|
|
25
27
|
applyPreprocessingPipeline,
|
|
26
28
|
computeWordFrequency,
|
|
27
29
|
desensitizeText,
|
|
30
|
+
detectFormat,
|
|
28
31
|
logNativeParserStatus,
|
|
29
32
|
matchesBlacklist,
|
|
30
33
|
mergeRulesForLocale,
|
|
34
|
+
owner_profile_service_exports,
|
|
31
35
|
preprocessMessages
|
|
32
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-KCPGEILH.mjs";
|
|
37
|
+
import {
|
|
38
|
+
resolveCliPath
|
|
39
|
+
} from "./chunk-FJ35V3TE.mjs";
|
|
33
40
|
import {
|
|
34
41
|
ConfigSetError,
|
|
35
42
|
DEFAULT_API_PORT,
|
|
36
43
|
DatabaseManager,
|
|
37
44
|
appLogger,
|
|
38
45
|
computeResponseTimeStats,
|
|
46
|
+
createDatabaseManagerAdapter,
|
|
39
47
|
executeParameterizedSql,
|
|
40
48
|
executeReadonlySql,
|
|
41
49
|
getChatOverview,
|
|
@@ -65,10 +73,10 @@ import {
|
|
|
65
73
|
searchMessagesLike,
|
|
66
74
|
setConfigField,
|
|
67
75
|
verifyCliDataPath
|
|
68
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-DQ45LDKZ.mjs";
|
|
69
77
|
|
|
70
78
|
// src/cli.ts
|
|
71
|
-
import * as
|
|
79
|
+
import * as fs3 from "fs";
|
|
72
80
|
import { execSync } from "child_process";
|
|
73
81
|
import { Command } from "commander";
|
|
74
82
|
|
|
@@ -2047,6 +2055,150 @@ function registerManifestCommand(program2, version) {
|
|
|
2047
2055
|
});
|
|
2048
2056
|
}
|
|
2049
2057
|
|
|
2058
|
+
// src/import/command.ts
|
|
2059
|
+
import fs2 from "fs";
|
|
2060
|
+
function normalizeImportError(message) {
|
|
2061
|
+
if (message.startsWith("File not found:")) {
|
|
2062
|
+
return {
|
|
2063
|
+
code: "FILE_NOT_FOUND",
|
|
2064
|
+
message,
|
|
2065
|
+
hint: "Pass an absolute path or a path relative to the current working directory."
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
if (message === IMPORT_IN_PROGRESS_ERROR_KEY) {
|
|
2069
|
+
return {
|
|
2070
|
+
code: "IMPORT_IN_PROGRESS",
|
|
2071
|
+
message: "Another import is already in progress.",
|
|
2072
|
+
hint: "Wait for the active import to finish, then retry."
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
if (message === "error.unrecognized_format" || message.toLowerCase().includes("unrecognized")) {
|
|
2076
|
+
return {
|
|
2077
|
+
code: "UNRECOGNIZED_FORMAT",
|
|
2078
|
+
message: "The chat export format could not be recognized.",
|
|
2079
|
+
hint: 'Run "chatlab formats" and retry with --format <id>.'
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
if (message.includes("sessionId contains invalid characters")) {
|
|
2083
|
+
return {
|
|
2084
|
+
code: "INVALID_SESSION_ID",
|
|
2085
|
+
message,
|
|
2086
|
+
hint: "Use only letters, numbers, underscores, and hyphens (maximum 128 characters)."
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
2089
|
+
return { code: "IMPORT_FAILED", message };
|
|
2090
|
+
}
|
|
2091
|
+
function buildImportCommandEnvelope(result, dryRun) {
|
|
2092
|
+
return result.success ? { ok: true, command: "import", data: result, meta: { dryRun, apiVersion: 1 } } : {
|
|
2093
|
+
ok: false,
|
|
2094
|
+
command: "import",
|
|
2095
|
+
error: normalizeImportError(result.error || "Import failed"),
|
|
2096
|
+
meta: { dryRun, apiVersion: 1 }
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
function printHumanResult(result, dryRun) {
|
|
2100
|
+
if (!result.success) {
|
|
2101
|
+
const error = normalizeImportError(result.error || "Import failed");
|
|
2102
|
+
console.error(`
|
|
2103
|
+
|
|
2104
|
+
Import failed: ${error.message}`);
|
|
2105
|
+
if (error.hint) console.error(` Hint: ${error.hint}`);
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2108
|
+
console.log(dryRun ? "\n\nDry run completed." : "\n\nImport succeeded!");
|
|
2109
|
+
console.log(` Mode: ${result.importMode ?? "unknown"}`);
|
|
2110
|
+
if (result.sessionId) console.log(` Session ID: ${result.sessionId}`);
|
|
2111
|
+
if (result.matchedBy) console.log(` Matched by: ${result.matchedBy}`);
|
|
2112
|
+
if (result.createReason) console.log(` Create reason: ${result.createReason}`);
|
|
2113
|
+
if (dryRun && "totalMessageCount" in result && result.totalMessageCount !== void 0) {
|
|
2114
|
+
console.log(` Messages scanned: ${result.totalMessageCount}`);
|
|
2115
|
+
}
|
|
2116
|
+
console.log(` New messages: ${result.newMessageCount ?? 0}`);
|
|
2117
|
+
console.log(` Duplicates skipped: ${result.duplicateCount ?? 0}`);
|
|
2118
|
+
}
|
|
2119
|
+
function printJsonResult(result, dryRun) {
|
|
2120
|
+
process.stdout.write(`${JSON.stringify(buildImportCommandEnvelope(result, dryRun))}
|
|
2121
|
+
`);
|
|
2122
|
+
}
|
|
2123
|
+
async function withJsonDiagnosticsOnStderr(enabled, run2) {
|
|
2124
|
+
if (!enabled) return run2();
|
|
2125
|
+
const originalConsoleLog = console.log;
|
|
2126
|
+
console.log = (...args) => console.error(...args);
|
|
2127
|
+
try {
|
|
2128
|
+
return await run2();
|
|
2129
|
+
} finally {
|
|
2130
|
+
console.log = originalConsoleLog;
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
async function applyOwnerProfile(result, systemDir, dbManager) {
|
|
2134
|
+
if (!result.sessionId) return;
|
|
2135
|
+
try {
|
|
2136
|
+
const applied = owner_profile_service_exports.tryApplyOwnerProfile(
|
|
2137
|
+
createDatabaseManagerAdapter(dbManager),
|
|
2138
|
+
new PreferencesManager(systemDir),
|
|
2139
|
+
result.sessionId
|
|
2140
|
+
);
|
|
2141
|
+
if (applied.applied) console.error(`Owner auto-detected: ${applied.ownerId}`);
|
|
2142
|
+
} catch (error) {
|
|
2143
|
+
console.error(`Owner profile apply skipped: ${error instanceof Error ? error.message : error}`);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
function registerImportCommand(program2) {
|
|
2147
|
+
program2.command("import <file>").description("Import a chat history file (14+ formats: QQ/WeChat/Telegram/WhatsApp/LINE/Discord, etc.)").option("--session-id <id>", "Force an existing session target, or create with this ID if missing").option("--format <id>", "Specify the input format ID (skip auto-detection)").option("--dry-run", "Analyze the target and message counts without writing data").option("--json", "Output one machine-readable JSON envelope").action(async (file, options) => {
|
|
2148
|
+
if (!fs2.existsSync(file)) {
|
|
2149
|
+
const result2 = { success: false, error: `File not found: ${file}` };
|
|
2150
|
+
if (options.json) printJsonResult(result2, Boolean(options.dryRun));
|
|
2151
|
+
else printHumanResult(result2, Boolean(options.dryRun));
|
|
2152
|
+
process.exitCode = 3;
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
const result = await withJsonDiagnosticsOnStderr(Boolean(options.json), async () => {
|
|
2156
|
+
let dbManager;
|
|
2157
|
+
try {
|
|
2158
|
+
const runtime = initRuntime();
|
|
2159
|
+
dbManager = runtime.dbManager;
|
|
2160
|
+
const nativeBinding = resolveNativeBinding();
|
|
2161
|
+
logNativeParserStatus();
|
|
2162
|
+
const detectedFormat = options.format ? void 0 : detectFormat(file);
|
|
2163
|
+
if (!detectedFormat && !options.format) {
|
|
2164
|
+
return { success: false, error: "error.unrecognized_format" };
|
|
2165
|
+
}
|
|
2166
|
+
if (!options.json) {
|
|
2167
|
+
console.log(`${options.dryRun ? "Analyzing" : "Importing"}: ${file}`);
|
|
2168
|
+
if (detectedFormat) console.log(` Format: ${detectedFormat.name} (${detectedFormat.platform})`);
|
|
2169
|
+
else if (options.format) console.log(` Format ID: ${options.format} (explicit)`);
|
|
2170
|
+
}
|
|
2171
|
+
const importOptions = {
|
|
2172
|
+
formatId: options.format,
|
|
2173
|
+
sessionId: options.sessionId,
|
|
2174
|
+
nativeBinding,
|
|
2175
|
+
onProgress: options.json ? void 0 : (progress) => {
|
|
2176
|
+
process.stdout.write(`\r ${progress.stage}: ${progress.progress}%`);
|
|
2177
|
+
}
|
|
2178
|
+
};
|
|
2179
|
+
const importResult = options.dryRun ? await analyzeAutoImport(dbManager, file, importOptions) : await autoImport(dbManager, file, importOptions);
|
|
2180
|
+
if (importResult.success && !options.dryRun) {
|
|
2181
|
+
await applyOwnerProfile(importResult, runtime.pathProvider.getSystemDir(), dbManager);
|
|
2182
|
+
}
|
|
2183
|
+
return importResult;
|
|
2184
|
+
} catch (error) {
|
|
2185
|
+
return {
|
|
2186
|
+
success: false,
|
|
2187
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2188
|
+
};
|
|
2189
|
+
} finally {
|
|
2190
|
+
dbManager?.closeAll();
|
|
2191
|
+
}
|
|
2192
|
+
});
|
|
2193
|
+
if (options.json) printJsonResult(result, Boolean(options.dryRun));
|
|
2194
|
+
else printHumanResult(result, Boolean(options.dryRun));
|
|
2195
|
+
if (!result.success) {
|
|
2196
|
+
if (result.error === "error.unrecognized_format") process.exitCode = 2;
|
|
2197
|
+
else process.exitCode = result.error === IMPORT_IN_PROGRESS_ERROR_KEY ? 4 : 1;
|
|
2198
|
+
}
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2050
2202
|
// src/cli.ts
|
|
2051
2203
|
var program = new Command();
|
|
2052
2204
|
program.name("chatlab").description("ChatLab - Chat history analysis tool").version(getVersion(), "-v, --version");
|
|
@@ -2070,70 +2222,9 @@ program.command("update").description("Update ChatLab CLI to the latest version"
|
|
|
2070
2222
|
});
|
|
2071
2223
|
registerQueryCommands(program);
|
|
2072
2224
|
registerManifestCommand(program, getVersion());
|
|
2073
|
-
program
|
|
2074
|
-
if (!fs2.existsSync(file)) {
|
|
2075
|
-
console.error(`File not found: ${file}`);
|
|
2076
|
-
process.exit(1);
|
|
2077
|
-
}
|
|
2078
|
-
const { streamImport, detectFormat } = await import("./import-WWCSXGVS.mjs");
|
|
2079
|
-
const { dbManager, pathProvider } = initRuntime();
|
|
2080
|
-
const nativeBinding = resolveNativeBinding();
|
|
2081
|
-
logNativeParserStatus();
|
|
2082
|
-
const format = detectFormat(file);
|
|
2083
|
-
if (!format && !options.format) {
|
|
2084
|
-
console.error(`Unrecognized file format: ${file}`);
|
|
2085
|
-
console.error('Use --format <id> to specify manually, or run "chatlab formats" to see supported formats');
|
|
2086
|
-
process.exit(1);
|
|
2087
|
-
}
|
|
2088
|
-
console.log(`Importing: ${file}`);
|
|
2089
|
-
if (format) console.log(` Format: ${format.name} (${format.platform})`);
|
|
2090
|
-
try {
|
|
2091
|
-
const result = await streamImport(dbManager, file, {
|
|
2092
|
-
formatId: options.format,
|
|
2093
|
-
nativeBinding,
|
|
2094
|
-
onProgress: (p) => {
|
|
2095
|
-
process.stdout.write(`\r ${p.stage}: ${p.progress}%`);
|
|
2096
|
-
}
|
|
2097
|
-
});
|
|
2098
|
-
if (result.success) {
|
|
2099
|
-
console.log(`
|
|
2100
|
-
|
|
2101
|
-
Import succeeded!`);
|
|
2102
|
-
console.log(` Session ID: ${result.sessionId}`);
|
|
2103
|
-
console.log(` Messages written: ${result.diagnostics?.messagesWritten ?? 0}`);
|
|
2104
|
-
console.log(` Messages skipped: ${result.diagnostics?.messagesSkipped ?? 0}`);
|
|
2105
|
-
if (result.sessionId) {
|
|
2106
|
-
try {
|
|
2107
|
-
const { PreferencesManager: PreferencesManager2, createDatabaseManagerAdapter, ownerProfileService } = await import("./src-MPNBTFOE.mjs");
|
|
2108
|
-
const applied = ownerProfileService.tryApplyOwnerProfile(
|
|
2109
|
-
createDatabaseManagerAdapter(dbManager),
|
|
2110
|
-
new PreferencesManager2(pathProvider.getSystemDir()),
|
|
2111
|
-
result.sessionId
|
|
2112
|
-
);
|
|
2113
|
-
if (applied.applied) {
|
|
2114
|
-
console.log(` Owner auto-detected: ${applied.ownerId}`);
|
|
2115
|
-
}
|
|
2116
|
-
} catch (ownerErr) {
|
|
2117
|
-
console.warn(` Owner profile apply skipped: ${ownerErr instanceof Error ? ownerErr.message : ownerErr}`);
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
} else {
|
|
2121
|
-
console.error(`
|
|
2122
|
-
|
|
2123
|
-
Import failed: ${result.error}`);
|
|
2124
|
-
process.exit(1);
|
|
2125
|
-
}
|
|
2126
|
-
} catch (err) {
|
|
2127
|
-
console.error(`
|
|
2128
|
-
|
|
2129
|
-
Import error: ${err instanceof Error ? err.message : err}`);
|
|
2130
|
-
process.exit(1);
|
|
2131
|
-
} finally {
|
|
2132
|
-
dbManager.closeAll();
|
|
2133
|
-
}
|
|
2134
|
-
});
|
|
2225
|
+
registerImportCommand(program);
|
|
2135
2226
|
program.command("formats").description("List all supported chat history formats").action(async () => {
|
|
2136
|
-
const { getSupportedFormats } = await import("./import-
|
|
2227
|
+
const { getSupportedFormats } = await import("./import-SEYHFXS5.mjs");
|
|
2137
2228
|
const formats = getSupportedFormats();
|
|
2138
2229
|
console.log(`${formats.length} supported format(s):
|
|
2139
2230
|
`);
|
|
@@ -2142,11 +2233,11 @@ program.command("formats").description("List all supported chat history formats"
|
|
|
2142
2233
|
}
|
|
2143
2234
|
});
|
|
2144
2235
|
program.command("mcp").description("Start MCP Server (stdio transport, for ClaudeCode / Cursor / AI agents)").action(async () => {
|
|
2145
|
-
const { startCliMcpServer } = await import("./mcp-
|
|
2236
|
+
const { startCliMcpServer } = await import("./mcp-MIPFYRLV.mjs");
|
|
2146
2237
|
await startCliMcpServer();
|
|
2147
2238
|
});
|
|
2148
2239
|
program.command("chat").description("Ask ChatLab AI about an imported chat session").option("--session-id <id>", "Source chat session ID").option("--ai-chat-id <id>", "Existing AI chat ID to continue").option("-q, --question <text>", "Question to ask").option("--json", "Output structured JSON").option("--include-events", "Include all agent stream chunks in JSON output").option("--no-stream", "Disable streaming output").option("--locale <locale>", "AI response locale", "zh-CN").action(async (options) => {
|
|
2149
|
-
const { runChatCommand } = await import("./chat-command-
|
|
2240
|
+
const { runChatCommand } = await import("./chat-command-MOETAGU5.mjs");
|
|
2150
2241
|
const { dbManager, pathProvider } = initRuntime();
|
|
2151
2242
|
const aiChatManager = new AIChatManager(pathProvider.getAiDataDir(), { nativeBinding: resolveNativeBinding() });
|
|
2152
2243
|
try {
|
|
@@ -2182,12 +2273,12 @@ program.command("start").description("Start ChatLab (HTTP API + Web UI)").option
|
|
|
2182
2273
|
});
|
|
2183
2274
|
return;
|
|
2184
2275
|
}
|
|
2185
|
-
const { startHttpServer } = await import("./http-
|
|
2276
|
+
const { startHttpServer } = await import("./http-M6NHWJZD.mjs");
|
|
2186
2277
|
const port = parseInt(options.port, 10);
|
|
2187
2278
|
let webRoot;
|
|
2188
2279
|
if (!options.headless) {
|
|
2189
2280
|
const webDir = resolveCliPath("dist-web");
|
|
2190
|
-
if (
|
|
2281
|
+
if (fs3.existsSync(webDir)) {
|
|
2191
2282
|
webRoot = webDir;
|
|
2192
2283
|
} else {
|
|
2193
2284
|
console.warn("Warning: dist-web/ not found, starting in API-only mode");
|
|
@@ -2229,7 +2320,7 @@ Press Ctrl+C to stop.
|
|
|
2229
2320
|
}
|
|
2230
2321
|
const shutdown = async () => {
|
|
2231
2322
|
console.log("\nShutting down...");
|
|
2232
|
-
const { stopHttpServer } = await import("./http-
|
|
2323
|
+
const { stopHttpServer } = await import("./http-M6NHWJZD.mjs");
|
|
2233
2324
|
await stopHttpServer();
|
|
2234
2325
|
process.exit(0);
|
|
2235
2326
|
};
|
|
@@ -2322,4 +2413,4 @@ if (isDirectRun) {
|
|
|
2322
2413
|
export {
|
|
2323
2414
|
run
|
|
2324
2415
|
};
|
|
2325
|
-
//# sourceMappingURL=chunk-
|
|
2416
|
+
//# sourceMappingURL=chunk-2IXPWPLR.mjs.map
|