chatlab-cli 0.25.1 → 0.26.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.
- package/dist/{chat-command-5XMRLXZM.mjs → chat-command-ZP4WJVWC.mjs} +144 -6
- package/dist/chat-command-ZP4WJVWC.mjs.map +1 -0
- package/dist/{chunk-YZYP5ST6.mjs → chunk-6G7AIF7I.mjs} +12 -11
- package/dist/chunk-6G7AIF7I.mjs.map +1 -0
- package/dist/{chunk-WYHGWTA4.mjs → chunk-ILGSSXOG.mjs} +92 -28
- package/dist/chunk-ILGSSXOG.mjs.map +1 -0
- package/dist/{chunk-JE3FOFF7.mjs → chunk-IRZRIHIT.mjs} +49 -12
- package/dist/chunk-IRZRIHIT.mjs.map +1 -0
- package/dist/{chunk-7VG6QGQ2.mjs → chunk-QY67NN65.mjs} +841 -79
- package/dist/chunk-QY67NN65.mjs.map +1 -0
- package/dist/{chunk-GTCTDD2Z.mjs → chunk-SJIOPSMM.mjs} +8 -8
- package/dist/{chunk-PDQFSQO6.mjs → chunk-TC74HESZ.mjs} +2 -2
- package/dist/{chunk-FDK6SPCG.mjs → chunk-UB4XBM4R.mjs} +2 -2
- package/dist/{chunk-CUCDRAY6.mjs → chunk-WXC6RZCX.mjs} +2 -2
- package/dist/cli.mjs +3 -3
- package/dist/{http-C3CGXUBU.mjs → http-J3IOFFIA.mjs} +8 -8
- package/dist/{import-VS7L5JDX.mjs → import-POYG5LOX.mjs} +4 -4
- package/dist/index.mjs +8 -8
- package/dist/{mcp-6VXDPUQK.mjs → mcp-7HH7UMXT.mjs} +4 -4
- package/dist/{stream-import-TFDBNVIW.mjs → stream-import-O3H3FGV2.mjs} +3 -3
- package/dist-web/assets/{DebugToolsPanel-vn-bnUxn.css → DebugToolsPanel-CrqULdXp.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BTJxEma5.js +182 -0
- package/dist-web/assets/{EChartWordcloud-CzhfrEF_.js → EChartWordcloud-B_YisOW5.js} +1 -1
- package/dist-web/assets/{MessageExportModal-B79pPBL9.js → MessageExportModal-C7NgEL8T.js} +1 -1
- package/dist-web/assets/{electron-DRkrjeIl.js → electron-B3DFm1cC.js} +1 -1
- package/dist-web/assets/electron-BMM4Nfty.js +1 -0
- package/dist-web/assets/{fetch-DfgdagMN.js → fetch-ArMjdMcy.js} +1 -1
- package/dist-web/assets/{fetch-BqLy63aj.js → fetch-BFtuJaa1.js} +1 -1
- package/dist-web/assets/{fetch-CDamdvtb.js → fetch-BGfaAqO9.js} +1 -1
- package/dist-web/assets/{fetch-Drk9dLaF.js → fetch-BaJDB31c.js} +1 -1
- package/dist-web/assets/{fetch-BmZIm6mS.js → fetch-BjDJgdN0.js} +1 -1
- package/dist-web/assets/{fetch-DWg-2kOp.js → fetch-C5CLcpQW.js} +1 -1
- package/dist-web/assets/{fetch-ph2_d79v.js → fetch-DQZvdHnG.js} +1 -1
- package/dist-web/assets/{fetch-Y-_WsCuk.js → fetch-Dhfbt1BQ.js} +3 -3
- package/dist-web/assets/{fetch-BstX-wd4.js → fetch-DnEP0uyF.js} +1 -1
- package/dist-web/assets/{fetch-Bvcxe5PI.js → fetch-SYrb-sZe.js} +1 -1
- package/dist-web/assets/index-CWfkrx37.js +173 -0
- package/dist-web/assets/index-D3N4NDFx.css +1 -0
- package/dist-web/assets/{index-DMWf5On7.js → index-D7_ch4zf.js} +1 -1
- package/dist-web/assets/{index-9urfJP1r.js → index-DK9LEEzT.js} +1 -1
- package/dist-web/assets/index-DqDa_on9.js +9 -0
- package/dist-web/assets/{index-D_hHm7bQ.js → index-DrN1G9bl.js} +2 -2
- package/dist-web/assets/{index-deYDOVUa.js → index-MdYeovYo.js} +4 -4
- package/dist-web/assets/{vendor-nuxt-ui-C_8CsH6e.js → vendor-nuxt-ui-Zy8txNdC.js} +1 -1
- package/dist-web/assets/{vendor-reka-ui-CIMXwvEp.js → vendor-reka-ui-mMvma1EP.js} +1 -1
- package/dist-web/assets/{web-XJV6Vj5t.js → web-zEXsvoZW.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chat-command-5XMRLXZM.mjs.map +0 -1
- package/dist/chunk-7VG6QGQ2.mjs.map +0 -1
- package/dist/chunk-JE3FOFF7.mjs.map +0 -1
- package/dist/chunk-WYHGWTA4.mjs.map +0 -1
- package/dist/chunk-YZYP5ST6.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-B1xZmp9r.js +0 -161
- package/dist-web/assets/electron-Dv8jdn_2.js +0 -1
- package/dist-web/assets/index-CfKjh0Jr.js +0 -9
- package/dist-web/assets/index-CprJOAB1.css +0 -1
- package/dist-web/assets/index-MCdpiX_O.js +0 -173
- /package/dist/{chunk-GTCTDD2Z.mjs.map → chunk-SJIOPSMM.mjs.map} +0 -0
- /package/dist/{chunk-PDQFSQO6.mjs.map → chunk-TC74HESZ.mjs.map} +0 -0
- /package/dist/{chunk-FDK6SPCG.mjs.map → chunk-UB4XBM4R.mjs.map} +0 -0
- /package/dist/{chunk-CUCDRAY6.mjs.map → chunk-WXC6RZCX.mjs.map} +0 -0
- /package/dist/{http-C3CGXUBU.mjs.map → http-J3IOFFIA.mjs.map} +0 -0
- /package/dist/{import-VS7L5JDX.mjs.map → import-POYG5LOX.mjs.map} +0 -0
- /package/dist/{mcp-6VXDPUQK.mjs.map → mcp-7HH7UMXT.mjs.map} +0 -0
- /package/dist/{stream-import-TFDBNVIW.mjs.map → stream-import-O3H3FGV2.mjs.map} +0 -0
|
@@ -6,9 +6,9 @@ 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-
|
|
9
|
+
} from "./chunk-ILGSSXOG.mjs";
|
|
10
|
+
import "./chunk-IRZRIHIT.mjs";
|
|
11
|
+
import "./chunk-QY67NN65.mjs";
|
|
12
12
|
import "./chunk-VSOWNKPA.mjs";
|
|
13
13
|
|
|
14
14
|
// src/ai/chat-command.ts
|
|
@@ -35,6 +35,33 @@ function createAgentStreamError(error) {
|
|
|
35
35
|
}
|
|
36
36
|
return new Error("Agent stream failed");
|
|
37
37
|
}
|
|
38
|
+
function isRecord(value) {
|
|
39
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
|
+
}
|
|
41
|
+
function isChartPayload(value) {
|
|
42
|
+
return isRecord(value) && value.version === 1 && isRecord(value.spec) && isRecord(value.dataset);
|
|
43
|
+
}
|
|
44
|
+
function extractChartPayloads(toolResult) {
|
|
45
|
+
if (!isRecord(toolResult)) return [];
|
|
46
|
+
const details = isRecord(toolResult.details) ? toolResult.details : toolResult;
|
|
47
|
+
const charts = [];
|
|
48
|
+
if (isChartPayload(details.chart)) charts.push(details.chart);
|
|
49
|
+
if (Array.isArray(details.charts)) {
|
|
50
|
+
for (const chart of details.charts) {
|
|
51
|
+
if (isChartPayload(chart)) charts.push(chart);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return charts;
|
|
55
|
+
}
|
|
56
|
+
function toPersistedChartPayload(chart) {
|
|
57
|
+
return {
|
|
58
|
+
...chart,
|
|
59
|
+
dataset: {
|
|
60
|
+
...chart.dataset,
|
|
61
|
+
rows: []
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
38
65
|
function resolveSingleSessionId(dbManager) {
|
|
39
66
|
const sessionIds = dbManager.listSessionIds();
|
|
40
67
|
if (sessionIds.length === 1) return sessionIds[0];
|
|
@@ -73,7 +100,82 @@ async function runChatTurn(options, deps) {
|
|
|
73
100
|
let answer = "";
|
|
74
101
|
let tokenUsage = null;
|
|
75
102
|
let streamError = null;
|
|
103
|
+
const events = [];
|
|
104
|
+
const contentBlocks = [];
|
|
105
|
+
let hasReplayContentBlocks = false;
|
|
76
106
|
const runAgentStream = (deps.createRunAgentStream ?? createCliRunAgentStream)(deps.dbManager, deps.aiChatManager);
|
|
107
|
+
const appendTextBlock = (text) => {
|
|
108
|
+
if (!text) return;
|
|
109
|
+
const lastBlock = contentBlocks[contentBlocks.length - 1];
|
|
110
|
+
if (lastBlock?.type === "text") {
|
|
111
|
+
lastBlock.text += text;
|
|
112
|
+
} else {
|
|
113
|
+
contentBlocks.push({ type: "text", text });
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const appendThinkBlock = (text, tag = "thinking", durationMs) => {
|
|
117
|
+
if (!text && durationMs === void 0) return;
|
|
118
|
+
const lastBlock = contentBlocks[contentBlocks.length - 1];
|
|
119
|
+
let targetBlock;
|
|
120
|
+
if (lastBlock?.type === "think" && lastBlock.tag === tag) {
|
|
121
|
+
lastBlock.text += text;
|
|
122
|
+
targetBlock = lastBlock;
|
|
123
|
+
} else if (text.trim().length > 0) {
|
|
124
|
+
targetBlock = { type: "think", tag, text };
|
|
125
|
+
contentBlocks.push(targetBlock);
|
|
126
|
+
} else if (durationMs !== void 0) {
|
|
127
|
+
for (let index = contentBlocks.length - 1; index >= 0; index--) {
|
|
128
|
+
const block = contentBlocks[index];
|
|
129
|
+
if (block.type === "think" && block.tag === tag) {
|
|
130
|
+
targetBlock = block;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (durationMs !== void 0 && targetBlock?.type === "think") {
|
|
136
|
+
targetBlock.durationMs = durationMs;
|
|
137
|
+
}
|
|
138
|
+
if (targetBlock?.type === "think") {
|
|
139
|
+
hasReplayContentBlocks = true;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const appendChartBlocks = (charts) => {
|
|
143
|
+
if (charts.length === 0) return;
|
|
144
|
+
contentBlocks.push(...charts.map((chart) => ({ type: "chart", chart: toPersistedChartPayload(chart) })));
|
|
145
|
+
hasReplayContentBlocks = true;
|
|
146
|
+
};
|
|
147
|
+
const appendPlanDraftBlock = (delta) => {
|
|
148
|
+
if (!delta) return;
|
|
149
|
+
const lastBlock = contentBlocks[contentBlocks.length - 1];
|
|
150
|
+
if (lastBlock?.type === "plan_draft") {
|
|
151
|
+
lastBlock.text += delta;
|
|
152
|
+
} else {
|
|
153
|
+
contentBlocks.push({ type: "plan_draft", version: 1, status: "streaming", text: delta });
|
|
154
|
+
}
|
|
155
|
+
hasReplayContentBlocks = true;
|
|
156
|
+
};
|
|
157
|
+
const removePlanDraftBlocks = () => {
|
|
158
|
+
for (let index = contentBlocks.length - 1; index >= 0; index--) {
|
|
159
|
+
if (contentBlocks[index]?.type === "plan_draft") {
|
|
160
|
+
contentBlocks.splice(index, 1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
const appendFinalPlanBlock = (plan) => {
|
|
165
|
+
const planBlock = JSON.parse(JSON.stringify(plan));
|
|
166
|
+
for (let index = contentBlocks.length - 1; index >= 0; index--) {
|
|
167
|
+
const block = contentBlocks[index];
|
|
168
|
+
if (block?.type === "plan_draft") {
|
|
169
|
+
const displayText = block.text.trim();
|
|
170
|
+
if (displayText) planBlock.displayText = displayText;
|
|
171
|
+
contentBlocks[index] = planBlock;
|
|
172
|
+
hasReplayContentBlocks = true;
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
contentBlocks.push(planBlock);
|
|
177
|
+
hasReplayContentBlocks = true;
|
|
178
|
+
};
|
|
77
179
|
await runAgentStream(
|
|
78
180
|
{
|
|
79
181
|
userMessage: options.question,
|
|
@@ -81,19 +183,53 @@ async function runChatTurn(options, deps) {
|
|
|
81
183
|
aiChatId: target.aiChatId,
|
|
82
184
|
assistantId: target.assistantId,
|
|
83
185
|
chatType: "group",
|
|
84
|
-
locale: options.locale ?? "zh-CN"
|
|
186
|
+
locale: options.locale ?? "zh-CN",
|
|
187
|
+
enableAutoSkill: true,
|
|
188
|
+
chartAutoMode: "suggest"
|
|
85
189
|
},
|
|
86
190
|
(chunk) => {
|
|
191
|
+
if (options.includeEvents) {
|
|
192
|
+
events.push(JSON.parse(JSON.stringify(chunk)));
|
|
193
|
+
}
|
|
87
194
|
if (chunk.type === "error") {
|
|
195
|
+
removePlanDraftBlocks();
|
|
88
196
|
streamError = createAgentStreamError(chunk.error);
|
|
89
197
|
return;
|
|
90
198
|
}
|
|
199
|
+
if (chunk.type === "plan_delta" && chunk.planDelta) {
|
|
200
|
+
appendPlanDraftBlock(chunk.planDelta);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (chunk.type === "plan" && chunk.plan) {
|
|
204
|
+
appendFinalPlanBlock(chunk.plan);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (chunk.type === "plan_skipped") {
|
|
208
|
+
removePlanDraftBlocks();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (chunk.type === "think") {
|
|
212
|
+
appendThinkBlock(chunk.content ?? "", chunk.thinkTag, chunk.thinkDurationMs);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (chunk.type === "tool_result" && chunk.toolName === "render_chart") {
|
|
216
|
+
appendChartBlocks(extractChartPayloads(chunk.toolResult));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
91
219
|
if (chunk.type === "content" && chunk.content) {
|
|
92
220
|
answer += chunk.content;
|
|
221
|
+
appendTextBlock(chunk.content);
|
|
93
222
|
if (!options.json && options.stream !== false) write(stdout, chunk.content);
|
|
94
223
|
}
|
|
95
224
|
if (chunk.type === "done" && chunk.usage) {
|
|
96
225
|
tokenUsage = chunk.usage;
|
|
226
|
+
for (let index = contentBlocks.length - 1; index >= 0; index--) {
|
|
227
|
+
const block = contentBlocks[index];
|
|
228
|
+
if (block.type === "plan") {
|
|
229
|
+
block.status = "done";
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
97
233
|
}
|
|
98
234
|
},
|
|
99
235
|
new AbortController().signal
|
|
@@ -109,7 +245,7 @@ async function runChatTurn(options, deps) {
|
|
|
109
245
|
answer,
|
|
110
246
|
void 0,
|
|
111
247
|
void 0,
|
|
112
|
-
void 0,
|
|
248
|
+
hasReplayContentBlocks ? contentBlocks : void 0,
|
|
113
249
|
tokenUsage ?? void 0
|
|
114
250
|
);
|
|
115
251
|
return {
|
|
@@ -117,6 +253,8 @@ async function runChatTurn(options, deps) {
|
|
|
117
253
|
aiChatId: target.aiChatId,
|
|
118
254
|
question: options.question,
|
|
119
255
|
answer,
|
|
256
|
+
...options.includeEvents ? { events } : {},
|
|
257
|
+
...hasReplayContentBlocks ? { contentBlocks } : {},
|
|
120
258
|
usage: {
|
|
121
259
|
durationMs: Date.now() - startedAt,
|
|
122
260
|
tokenUsage
|
|
@@ -163,4 +301,4 @@ export {
|
|
|
163
301
|
runChatCommand,
|
|
164
302
|
runChatTurn
|
|
165
303
|
};
|
|
166
|
-
//# sourceMappingURL=chat-command-
|
|
304
|
+
//# sourceMappingURL=chat-command-ZP4WJVWC.mjs.map
|
|
@@ -0,0 +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"]}
|
|
@@ -6,7 +6,7 @@ const __filename = __fileURLToPath(import.meta.url);
|
|
|
6
6
|
const __dirname = __pathDirname(__filename);
|
|
7
7
|
import {
|
|
8
8
|
assertCliDataDirCompatible
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-UB4XBM4R.mjs";
|
|
10
10
|
import {
|
|
11
11
|
getVersion
|
|
12
12
|
} from "./chunk-5ADKYYNA.mjs";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
loadConfig,
|
|
27
27
|
searchMessagesLike,
|
|
28
28
|
verifyCliDataPath
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-QY67NN65.mjs";
|
|
30
30
|
import {
|
|
31
31
|
resolveCliPath
|
|
32
32
|
} from "./chunk-FJ35V3TE.mjs";
|
|
@@ -223,7 +223,7 @@ program.command("import <file>").description("Import a chat history file (14+ fo
|
|
|
223
223
|
console.error(`File not found: ${file}`);
|
|
224
224
|
process.exit(1);
|
|
225
225
|
}
|
|
226
|
-
const { streamImport, detectFormat } = await import("./import-
|
|
226
|
+
const { streamImport, detectFormat } = await import("./import-POYG5LOX.mjs");
|
|
227
227
|
const { dbManager } = initRuntime();
|
|
228
228
|
const nativeBinding = resolveNativeBinding();
|
|
229
229
|
const format = detectFormat(file);
|
|
@@ -265,7 +265,7 @@ Import error: ${err instanceof Error ? err.message : err}`);
|
|
|
265
265
|
}
|
|
266
266
|
});
|
|
267
267
|
program.command("formats").description("List all supported chat history formats").action(async () => {
|
|
268
|
-
const { getSupportedFormats } = await import("./import-
|
|
268
|
+
const { getSupportedFormats } = await import("./import-POYG5LOX.mjs");
|
|
269
269
|
const formats = getSupportedFormats();
|
|
270
270
|
console.log(`${formats.length} supported format(s):
|
|
271
271
|
`);
|
|
@@ -274,11 +274,11 @@ program.command("formats").description("List all supported chat history formats"
|
|
|
274
274
|
}
|
|
275
275
|
});
|
|
276
276
|
program.command("mcp").description("Start MCP Server (stdio transport, for ClaudeCode / Cursor / AI agents)").action(async () => {
|
|
277
|
-
const { startCliMcpServer } = await import("./mcp-
|
|
277
|
+
const { startCliMcpServer } = await import("./mcp-7HH7UMXT.mjs");
|
|
278
278
|
await startCliMcpServer();
|
|
279
279
|
});
|
|
280
|
-
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("--no-stream", "Disable streaming output").option("--locale <locale>", "AI response locale", "zh-CN").action(async (options) => {
|
|
281
|
-
const { runChatCommand } = await import("./chat-command-
|
|
280
|
+
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) => {
|
|
281
|
+
const { runChatCommand } = await import("./chat-command-ZP4WJVWC.mjs");
|
|
282
282
|
const { dbManager, pathProvider } = initRuntime();
|
|
283
283
|
const aiChatManager = new AIChatManager(pathProvider.getAiDataDir(), { nativeBinding: resolveNativeBinding() });
|
|
284
284
|
try {
|
|
@@ -289,7 +289,8 @@ program.command("chat").description("Ask ChatLab AI about an imported chat sessi
|
|
|
289
289
|
question: options.question,
|
|
290
290
|
json: !!options.json,
|
|
291
291
|
stream: options.stream,
|
|
292
|
-
locale: options.locale
|
|
292
|
+
locale: options.locale,
|
|
293
|
+
includeEvents: !!options.includeEvents
|
|
293
294
|
},
|
|
294
295
|
{ dbManager, pathProvider, aiChatManager }
|
|
295
296
|
);
|
|
@@ -313,7 +314,7 @@ program.command("start").description("Start ChatLab (HTTP API + Web UI)").option
|
|
|
313
314
|
});
|
|
314
315
|
return;
|
|
315
316
|
}
|
|
316
|
-
const { startHttpServer } = await import("./http-
|
|
317
|
+
const { startHttpServer } = await import("./http-J3IOFFIA.mjs");
|
|
317
318
|
const port = parseInt(options.port, 10);
|
|
318
319
|
let webRoot;
|
|
319
320
|
if (!options.headless) {
|
|
@@ -360,7 +361,7 @@ Press Ctrl+C to stop.
|
|
|
360
361
|
}
|
|
361
362
|
const shutdown = async () => {
|
|
362
363
|
console.log("\nShutting down...");
|
|
363
|
-
const { stopHttpServer } = await import("./http-
|
|
364
|
+
const { stopHttpServer } = await import("./http-J3IOFFIA.mjs");
|
|
364
365
|
await stopHttpServer();
|
|
365
366
|
process.exit(0);
|
|
366
367
|
};
|
|
@@ -504,4 +505,4 @@ if (isDirectRun) {
|
|
|
504
505
|
export {
|
|
505
506
|
run
|
|
506
507
|
};
|
|
507
|
-
//# sourceMappingURL=chunk-
|
|
508
|
+
//# sourceMappingURL=chunk-6G7AIF7I.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/http/port.ts"],"sourcesContent":["/**\n * ChatLab CLI entry point\n *\n * Dev: pnpm --filter chatlab-cli run cli -- sessions\n */\n\nimport * as fs from 'fs'\nimport { execSync } from 'child_process'\nimport { Command } from 'commander'\nimport { DEFAULT_API_PORT, loadConfig, getConfigPath } from '@openchatlab/config'\nimport {\n NodePathProvider,\n DatabaseManager,\n AIChatManager,\n applyPendingNodeDataDirMigrationIfNeeded,\n hasPendingElectronDataWarning,\n verifyCliDataPath,\n} from '@openchatlab/node-runtime'\nimport {\n getSessionMeta,\n getSessionOverview,\n getMemberActivity,\n searchMessagesLike,\n getMembers,\n executeReadonlySql,\n} from '@openchatlab/core'\nimport { getVersion } from './version'\nimport { resolveCliPath } from './paths'\nimport { isPortAvailable, formatPortInUseError } from './http/port'\nimport { assertCliDataDirCompatible } from './runtime-compat'\n\nconst program = new Command()\n\nprogram.name('chatlab').description('ChatLab - Chat history analysis tool').version(getVersion(), '-v, --version')\n\nprogram.hook('preAction', async (_thisCommand, actionCommand) => {\n if (actionCommand.name() === 'update') return\n const { checkForUpdatesInteractive } = await import('./update-checker')\n await checkForUpdatesInteractive()\n})\n\nprogram\n .command('update')\n .description('Update ChatLab CLI to the latest version')\n .action(async () => {\n const { performCliSelfUpdate } = await import('./update-checker')\n const result = await performCliSelfUpdate({\n write: (text) => process.stderr.write(text),\n })\n\n if (result.success) {\n console.error(' Updated successfully. Please restart chatlab to use the new version.\\n')\n return\n }\n\n console.error(` Update failed: ${result.error || 'unknown error'}\\n`)\n process.exitCode = 1\n })\n\nprogram\n .command('sessions')\n .description('List all imported chat sessions')\n .option('--format <format>', 'Output format (table|json)', 'table')\n .action((options) => {\n const { dbManager } = initRuntime()\n const sessionIds = dbManager.listSessionIds()\n\n if (sessionIds.length === 0) {\n console.log('No chat sessions found.')\n console.log(`Data directory: ${dbManager['pathProvider'].getUserDataDir()}`)\n dbManager.closeAll()\n return\n }\n\n const sessions = sessionIds\n .map((id) => {\n const db = dbManager.open(id)\n if (!db) return null\n const meta = getSessionMeta(db)\n if (!meta) return null\n const overview = getSessionOverview(db)\n return { id, ...meta, ...overview }\n })\n .filter(Boolean)\n\n if (options.format === 'json') {\n console.log(JSON.stringify(sessions, null, 2))\n } else {\n console.log(`${sessions.length} session(s) found:\\n`)\n for (const s of sessions) {\n if (!s) continue\n const timeRange = formatTimeRange(s.firstMessageTs, s.lastMessageTs)\n console.log(` ${s.name}`)\n console.log(` ID: ${s.id}`)\n console.log(\n ` Platform: ${s.platform} | Type: ${s.type} | Members: ${s.totalMembers} | Messages: ${s.totalMessages}`\n )\n if (timeRange) console.log(` Range: ${timeRange}`)\n console.log()\n }\n }\n\n dbManager.closeAll()\n })\n\nprogram\n .command('stats <session-id>')\n .description('Show session statistics overview')\n .option('--format <format>', 'Output format (table|json)', 'table')\n .option('--top <n>', 'Show top N active members', '10')\n .action((sessionId, options) => {\n const { dbManager } = initRuntime()\n const db = dbManager.open(sessionId)\n if (!db) {\n console.error(`Session ${sessionId} not found`)\n process.exit(1)\n }\n\n const meta = getSessionMeta(db)\n const overview = getSessionOverview(db)\n const topMembers = getMemberActivity(db).slice(0, parseInt(options.top))\n\n if (options.format === 'json') {\n console.log(JSON.stringify({ meta, overview, topMembers }, null, 2))\n } else {\n console.log(`\\nSession: ${meta?.name}`)\n console.log(`Platform: ${meta?.platform} | Type: ${meta?.type}`)\n console.log(`Total messages: ${overview.totalMessages}`)\n console.log(`Total members: ${overview.totalMembers}`)\n console.log(`Time range: ${formatTimeRange(overview.firstMessageTs, overview.lastMessageTs)}`)\n\n if (topMembers.length > 0) {\n console.log(`\\nActivity ranking (Top ${options.top}):`)\n for (const [i, m] of topMembers.entries()) {\n console.log(` ${i + 1}. ${m.name} - ${m.messageCount} messages (${m.percentage}%)`)\n }\n }\n }\n\n dbManager.closeAll()\n })\n\nprogram\n .command('search <session-id> <keyword>')\n .description('Search messages by keyword')\n .option('--limit <n>', 'Max results to return', '20')\n .option('--format <format>', 'Output format (table|json)', 'table')\n .action((sessionId, keyword, options) => {\n const { dbManager } = initRuntime()\n const db = dbManager.open(sessionId)\n if (!db) {\n console.error(`Session ${sessionId} not found`)\n process.exit(1)\n }\n\n const limit = parseInt(options.limit)\n const result = searchMessagesLike(db, keyword, { limit })\n\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2))\n } else {\n console.log(\n `Search \"${keyword}\" - ${result.total} result(s)${result.hasMore ? ' (showing first ' + limit + ')' : ''}:\\n`\n )\n for (const msg of result.messages) {\n const time = new Date(msg.timestamp * 1000).toLocaleString()\n console.log(` [${time}] ${msg.senderName}: ${msg.content}`)\n }\n }\n\n dbManager.closeAll()\n })\n\nprogram\n .command('members <session-id>')\n .description('List session members')\n .option('--format <format>', 'Output format (table|json)', 'table')\n .action((sessionId, options) => {\n const { dbManager } = initRuntime()\n const db = dbManager.open(sessionId)\n if (!db) {\n console.error(`Session ${sessionId} not found`)\n process.exit(1)\n }\n\n const members = getMembers(db)\n\n if (options.format === 'json') {\n console.log(JSON.stringify(members, null, 2))\n } else {\n console.log(`${members.length} member(s):\\n`)\n for (const [i, m] of members.entries()) {\n console.log(` ${i + 1}. ${m.name} (${m.platformId}) - ${m.messageCount} messages`)\n }\n }\n\n dbManager.closeAll()\n })\n\nprogram\n .command('query <session-id>')\n .description('Execute a read-only SQL query on a session database')\n .requiredOption('--sql <sql>', 'SQL query statement')\n .option('--format <format>', 'Output format (table|json)', 'table')\n .action((sessionId, options) => {\n const { dbManager } = initRuntime()\n const db = dbManager.open(sessionId)\n if (!db) {\n console.error(`Session ${sessionId} not found`)\n process.exit(1)\n }\n\n try {\n const result = executeReadonlySql(db, options.sql)\n if (options.format === 'json') {\n console.log(JSON.stringify(result, null, 2))\n } else {\n if (result.rows.length === 0) {\n console.log('No results.')\n } else {\n printTable(result.columns, result.rows)\n console.log(`\\n${result.rowCount} row(s)${result.truncated ? ' (truncated)' : ''}`)\n }\n }\n } catch (err) {\n console.error(`SQL error: ${err instanceof Error ? err.message : err}`)\n process.exit(1)\n }\n\n dbManager.closeAll()\n })\n\nprogram\n .command('import <file>')\n .description('Import a chat history file (14+ formats: QQ/WeChat/Telegram/WhatsApp/LINE/Discord/Instagram, etc.)')\n .option('--session-id <id>', 'Specify session ID (auto-generated if omitted)')\n .option('--format <id>', 'Specify format ID (skip auto-detection)')\n .action(async (file, options) => {\n if (!fs.existsSync(file)) {\n console.error(`File not found: ${file}`)\n process.exit(1)\n }\n\n const { streamImport, detectFormat } = await import('./import')\n const { dbManager } = initRuntime()\n const nativeBinding = resolveNativeBinding()\n\n const format = detectFormat(file)\n if (!format && !options.format) {\n console.error(`Unrecognized file format: ${file}`)\n console.error('Use --format <id> to specify manually, or run \"chatlab formats\" to see supported formats')\n process.exit(1)\n }\n\n console.log(`Importing: ${file}`)\n if (format) console.log(` Format: ${format.name} (${format.platform})`)\n\n try {\n const result = await streamImport(dbManager, file, {\n formatId: options.format,\n nativeBinding,\n onProgress: (p) => {\n process.stdout.write(`\\r ${p.stage}: ${p.progress}%`)\n },\n })\n\n if (result.success) {\n console.log(`\\n\\nImport succeeded!`)\n console.log(` Session ID: ${result.sessionId}`)\n console.log(` Messages written: ${result.diagnostics?.messagesWritten ?? 0}`)\n console.log(` Messages skipped: ${result.diagnostics?.messagesSkipped ?? 0}`)\n } else {\n console.error(`\\n\\nImport failed: ${result.error}`)\n process.exit(1)\n }\n } catch (err) {\n console.error(`\\n\\nImport error: ${err instanceof Error ? err.message : err}`)\n process.exit(1)\n } finally {\n dbManager.closeAll()\n }\n })\n\nprogram\n .command('formats')\n .description('List all supported chat history formats')\n .action(async () => {\n const { getSupportedFormats } = await import('./import')\n const formats = getSupportedFormats()\n console.log(`${formats.length} supported format(s):\\n`)\n for (const f of formats) {\n console.log(` ${f.id.padEnd(30)} ${f.name} (${f.platform}) [${f.extensions.join(', ')}]`)\n }\n })\n\nprogram\n .command('mcp')\n .description('Start MCP Server (stdio transport, for ClaudeCode / Cursor / AI agents)')\n .action(async () => {\n const { startCliMcpServer } = await import('./mcp')\n await startCliMcpServer()\n })\n\nprogram\n .command('chat')\n .description('Ask ChatLab AI about an imported chat session')\n .option('--session-id <id>', 'Source chat session ID')\n .option('--ai-chat-id <id>', 'Existing AI chat ID to continue')\n .option('-q, --question <text>', 'Question to ask')\n .option('--json', 'Output structured JSON')\n .option('--include-events', 'Include all agent stream chunks in JSON output')\n .option('--no-stream', 'Disable streaming output')\n .option('--locale <locale>', 'AI response locale', 'zh-CN')\n .action(async (options) => {\n const { runChatCommand } = await import('./ai/chat-command')\n const { dbManager, pathProvider } = initRuntime()\n const aiChatManager = new AIChatManager(pathProvider.getAiDataDir(), { nativeBinding: resolveNativeBinding() })\n\n try {\n await runChatCommand(\n {\n sessionId: options.sessionId,\n aiChatId: options.aiChatId,\n question: options.question,\n json: !!options.json,\n stream: options.stream,\n locale: options.locale,\n includeEvents: !!options.includeEvents,\n },\n { dbManager, pathProvider, aiChatManager }\n )\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n process.exitCode = 1\n } finally {\n aiChatManager.close()\n dbManager.closeAll()\n }\n })\n\nprogram\n .command('start')\n .description('Start ChatLab (HTTP API + Web UI)')\n .option('--port <port>', 'Server port', String(DEFAULT_API_PORT))\n .option('--host <host>', 'Listen address', '127.0.0.1')\n .option('--token <token>', 'Custom Bearer Token (reads from config or auto-generates if omitted)')\n .option('--headless', 'API-only mode, do not serve the Web UI')\n .option('--require-auth', 'Require Bearer token for all routes including /_web/*')\n .option('--no-open', 'Do not auto-open the browser')\n .option('--daemon', 'Run as a resident system service (auto-start on login, macOS/Linux)')\n .action(async (options) => {\n // --daemon: install as system service and exit\n if (options.daemon) {\n const { serviceInstall } = await import('./daemon/service')\n serviceInstall({\n port: parseInt(options.port, 10),\n host: options.host,\n token: options.token || undefined,\n headless: options.headless,\n requireAuth: options.requireAuth || undefined,\n })\n return\n }\n\n const { startHttpServer } = await import('./http')\n const port = parseInt(options.port, 10)\n\n let webRoot: string | undefined\n if (!options.headless) {\n const webDir = resolveCliPath('dist-web')\n if (fs.existsSync(webDir)) {\n webRoot = webDir\n } else {\n console.warn('Warning: dist-web/ not found, starting in API-only mode')\n }\n }\n\n try {\n // 启动前预检端口,快速失败,避免无谓的初始化后再报 EADDRINUSE;\n // 置于 try 内确保非 EADDRINUSE 错误(EACCES/EADDRNOTAVAIL 等)\n // 也能走到统一的 Startup failed 错误处理路径。\n if (!(await isPortAvailable(port, options.host))) {\n console.error(formatPortInUseError(port))\n process.exit(1)\n }\n\n const info = await startHttpServer({\n port,\n host: options.host,\n token: options.token || undefined,\n webRoot,\n requireAuth: options.requireAuth || undefined,\n })\n\n const { startPeriodicUpdateCheck } = await import('./update-checker')\n startPeriodicUpdateCheck()\n\n const displayHost = info.host === '0.0.0.0' ? '127.0.0.1' : info.host\n const url = `http://${displayHost}:${info.port}`\n\n console.log(`\\nChatLab v${getVersion()}`)\n if (webRoot) console.log(` Web UI: ${url}/`)\n console.log(` API: ${url}`)\n console.log(` Token: ${info.token}`)\n console.log(`\\nExample:`)\n console.log(` curl -H \"Authorization: Bearer ${info.token}\" ${url}/api/v1/status`)\n\n if (webRoot && options.open) {\n openBrowser(url)\n console.log(`\\nBrowser opened. Press Ctrl+C to stop.\\n`)\n } else {\n console.log(`\\nPress Ctrl+C to stop.\\n`)\n }\n\n const shutdown = async () => {\n console.log('\\nShutting down...')\n const { stopHttpServer } = await import('./http')\n await stopHttpServer()\n process.exit(0)\n }\n\n process.on('SIGINT', shutdown)\n process.on('SIGTERM', shutdown)\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n if (message.includes('EADDRINUSE')) {\n // 极低概率的 TOCTOU 竞态(预检通过后端口被占),复用统一文案\n console.error(formatPortInUseError(port))\n } else {\n console.error(`Startup failed: ${message}`)\n }\n process.exit(1)\n }\n })\n\nconst configCmd = program.command('config').description('Configuration management')\n\nconfigCmd\n .command('path')\n .description('Show config file path')\n .action(() => {\n console.log(getConfigPath())\n })\n\nconfigCmd\n .command('show')\n .description('Show current configuration')\n .action(() => {\n const config = loadConfig()\n console.log(JSON.stringify(config, null, 2))\n })\n\nprogram\n .command('stop')\n .description('Stop the resident service and remove auto-start (reverse of start --daemon)')\n .action(async () => {\n const { serviceUninstall } = await import('./daemon/service')\n serviceUninstall()\n })\n\nprogram\n .command('status')\n .description('Show resident service status')\n .action(async () => {\n const { getServiceStatus } = await import('./daemon/service')\n const svc = getServiceStatus()\n\n console.log('\\nChatLab Status')\n console.log('─'.repeat(36))\n\n if (svc.installed) {\n const portStr = svc.port ? `http://${svc.host ?? '127.0.0.1'}:${svc.port}` : ''\n console.log(` Service: ${svc.running ? 'running' : 'installed (not running)'}`)\n if (portStr) console.log(` Address: ${portStr}`)\n console.log(` Auto-start: enabled`)\n console.log(`\\n Use \\`chatlab stop\\` to remove the service.\\n`)\n } else {\n console.log(` Service: not installed`)\n console.log(` Auto-start: disabled`)\n console.log(`\\n Use \\`chatlab start --daemon\\` to install as a system service.\\n`)\n }\n })\n\n// --- 工具函数 ---\n\nfunction openBrowser(url: string): void {\n try {\n const cmd =\n process.platform === 'darwin'\n ? `open \"${url}\"`\n : process.platform === 'win32'\n ? `start \"\" \"${url}\"`\n : `xdg-open \"${url}\"`\n execSync(cmd, { stdio: 'ignore' })\n } catch {\n console.log(` Open manually: ${url}`)\n }\n}\n\n/**\n * Resolve standalone better-sqlite3 native module path.\n * Used in non-Electron environments to avoid electron-rebuild conflicts.\n */\nfunction resolveNativeBinding(): string | undefined {\n if (process.versions.electron) return undefined\n const nativePath = resolveCliPath('native/better_sqlite3.node')\n if (fs.existsSync(nativePath)) return nativePath\n return undefined\n}\n\nfunction initRuntime() {\n let config = loadConfig()\n const pendingMigration = applyPendingNodeDataDirMigrationIfNeeded()\n if (!pendingMigration.skipped) {\n if (pendingMigration.success) {\n console.log('[Migration] Pending data directory migration completed')\n config = loadConfig()\n } else {\n console.error('[Migration] Pending data directory migration failed:', pendingMigration.error)\n }\n }\n const userDataDir = config.data.user_data_dir || undefined\n const pathProvider = new NodePathProvider(userDataDir)\n pathProvider.ensureAllDirs()\n const runtime = assertCliDataDirCompatible(pathProvider, 'cli')\n\n if (hasPendingElectronDataWarning() || !verifyCliDataPath(pathProvider.getDatabaseDir())) {\n printElectronDataError()\n process.exit(1)\n }\n\n const nativeBinding = resolveNativeBinding()\n const dbManager = new DatabaseManager(pathProvider, { nativeBinding, runtime })\n return { config, pathProvider, dbManager }\n}\n\nfunction printElectronDataError(): void {\n console.error('\\n' + '='.repeat(68))\n console.error(' ChatLab: Electron desktop data not found')\n console.error('='.repeat(68))\n console.error('')\n console.error(' Detected that ChatLab desktop app was installed on this machine,')\n console.error(' but could not locate your chat databases.')\n console.error('')\n console.error(' This usually means you changed the data directory in desktop settings.')\n console.error('')\n console.error(' To fix this, choose one of:')\n console.error('')\n console.error(' 1. Open ChatLab desktop app — it will auto-migrate your data')\n console.error(' 2. Set the data directory manually:')\n console.error(' export CHATLAB_DATA_DIR=\"/path/to/your/data\"')\n console.error(' 3. Edit ~/.chatlab/config.toml:')\n console.error(' [data]')\n console.error(' user_data_dir = \"/path/to/your/data\"')\n console.error('')\n console.error('='.repeat(68) + '\\n')\n}\n\nfunction formatTimeRange(first: number | null, last: number | null): string {\n if (!first || !last) return 'Unknown'\n const from = new Date(first * 1000).toLocaleDateString()\n const to = new Date(last * 1000).toLocaleDateString()\n return `${from} ~ ${to}`\n}\n\nfunction printTable(columns: string[], rows: Record<string, unknown>[]): void {\n const widths = columns.map((col) => {\n const maxData = rows.reduce((max, row) => {\n const val = String(row[col] ?? '')\n return Math.max(max, val.length)\n }, 0)\n return Math.max(col.length, Math.min(maxData, 40))\n })\n\n const header = columns.map((col, i) => col.padEnd(widths[i])).join(' | ')\n const separator = widths.map((w) => '-'.repeat(w)).join('-+-')\n console.log(header)\n console.log(separator)\n\n for (const row of rows) {\n const line = columns\n .map((col, i) => {\n const val = String(row[col] ?? '')\n return val.length > 40 ? val.slice(0, 37) + '...' : val.padEnd(widths[i])\n })\n .join(' | ')\n console.log(line)\n }\n}\n\n/** CLI entry function */\nexport function run(argv?: string[]): void {\n program.parse(argv)\n}\n\n// Auto-execute when run directly as a script\nconst isDirectRun = process.argv[1]?.endsWith('cli.ts') || process.argv[1]?.endsWith('cli.js')\nif (isDirectRun) {\n run()\n}\n","/**\n * 端口可用性检测与错误文案\n */\n\nimport * as net from 'net'\n\n/**\n * 检测指定端口在给定 host 上是否可用。\n * 使用 net.createServer() 试探性绑定,无副作用(成功后立即释放)。\n */\nexport function isPortAvailable(port: number, host: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n const server = net.createServer()\n server.once('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n resolve(false)\n } else {\n reject(err)\n }\n })\n server.once('listening', () => server.close(() => resolve(true)))\n server.listen(port, host)\n })\n}\n\n/**\n * 返回端口被占用时统一的友好报错文案。\n */\nexport function formatPortInUseError(port: number): string {\n return [\n ``,\n ` ✖ Error: port ${port} is already in use.`,\n ``,\n ` Another process (possibly a ChatLab instance) is using this port. You can:`,\n ` • Use another port: chatlab start --port <port>`,\n ` • Find the process: lsof -iTCP:${port} -sTCP:LISTEN`,\n ``,\n ].join('\\n')\n}\n"],"mappings":"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","names":[]}
|
|
@@ -7,7 +7,7 @@ const __dirname = __pathDirname(__filename);
|
|
|
7
7
|
import {
|
|
8
8
|
AGENT_TOOL_REGISTRY,
|
|
9
9
|
CoreDataProvider
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-IRZRIHIT.mjs";
|
|
11
11
|
import {
|
|
12
12
|
AgentEventHandler,
|
|
13
13
|
AiLogger,
|
|
@@ -17,16 +17,23 @@ import {
|
|
|
17
17
|
applyPreprocessingPipeline,
|
|
18
18
|
batchSegmentWithFrequency,
|
|
19
19
|
buildPiModel,
|
|
20
|
+
buildPlanGuidance,
|
|
20
21
|
buildSkillMenuWithBuiltinChart,
|
|
21
22
|
buildSystemPrompt,
|
|
22
23
|
checkAndCompress,
|
|
23
24
|
createActivateSkillTool,
|
|
24
25
|
createAiTranslate,
|
|
26
|
+
createAnalysisPlanner,
|
|
25
27
|
createChartSchemaGateState,
|
|
26
28
|
createCompressionLlmAdapter,
|
|
29
|
+
createDataSnapshotFromOverview,
|
|
30
|
+
createLlmRouteDecider,
|
|
31
|
+
createPlanContentBlock,
|
|
32
|
+
decideRequestRoute,
|
|
27
33
|
formatAIError,
|
|
28
34
|
getAllowedBuiltinToolsForChartAutoSkill,
|
|
29
35
|
getChartCapabilitySkill,
|
|
36
|
+
getChartPlannerCapabilityForMessage,
|
|
30
37
|
getChatOverview,
|
|
31
38
|
getSkillConfigWithBuiltinChart,
|
|
32
39
|
initTokenizer,
|
|
@@ -35,8 +42,9 @@ import {
|
|
|
35
42
|
resolveApiKey,
|
|
36
43
|
resolveChartRuntimeForRequest,
|
|
37
44
|
runAgentCore,
|
|
45
|
+
shouldUseChartCapabilityForMessage,
|
|
38
46
|
wrapWithChartSchemaGate
|
|
39
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-QY67NN65.mjs";
|
|
40
48
|
|
|
41
49
|
// src/ai/logger.ts
|
|
42
50
|
var logger = null;
|
|
@@ -215,7 +223,8 @@ async function runServerAgent(options) {
|
|
|
215
223
|
ownerInfo,
|
|
216
224
|
mentionedMembers,
|
|
217
225
|
dataSnapshot,
|
|
218
|
-
thinkingLevel
|
|
226
|
+
thinkingLevel,
|
|
227
|
+
chartAutoMode = "suggest"
|
|
219
228
|
} = options;
|
|
220
229
|
const aiLogger = getServerAiLogger();
|
|
221
230
|
await initTokenizer();
|
|
@@ -292,12 +301,77 @@ async function runServerAgent(options) {
|
|
|
292
301
|
handler.emitStatus("preparing", [], { pendingUserMessage: userMessage, force: true });
|
|
293
302
|
const steerMessage = t("ai.agent.answerWithoutTools");
|
|
294
303
|
let cachedMessages = [];
|
|
304
|
+
const effectiveTools = chartAutoMode === "explicit" && !shouldUseChartCapabilityForMessage(userMessage) ? tools.filter((tool) => tool.name !== "render_chart") : tools;
|
|
295
305
|
try {
|
|
306
|
+
const routeInput = {
|
|
307
|
+
userMessage,
|
|
308
|
+
chatType,
|
|
309
|
+
locale,
|
|
310
|
+
dataSnapshot,
|
|
311
|
+
availableTools: effectiveTools.map((tool) => tool.name),
|
|
312
|
+
availableCapabilities: [
|
|
313
|
+
getChartPlannerCapabilityForMessage({
|
|
314
|
+
userMessage,
|
|
315
|
+
locale,
|
|
316
|
+
availableTools: effectiveTools.map((tool) => tool.name),
|
|
317
|
+
chartAutoMode
|
|
318
|
+
})
|
|
319
|
+
].filter((capability) => capability !== null),
|
|
320
|
+
skillSummary: skillDef?.name ?? (skillMenu ? "auto_skill_menu" : void 0)
|
|
321
|
+
};
|
|
322
|
+
const routeStartedAt = Date.now();
|
|
323
|
+
const routeDecision = await decideRequestRoute(routeInput, {
|
|
324
|
+
llmRouter: createLlmRouteDecider({
|
|
325
|
+
piModel,
|
|
326
|
+
apiKey: llmConfig.apiKey,
|
|
327
|
+
abortSignal
|
|
328
|
+
})
|
|
329
|
+
});
|
|
330
|
+
aiLogger?.info("Router", "Shadow route decision", {
|
|
331
|
+
...routeDecision,
|
|
332
|
+
elapsedMs: Date.now() - routeStartedAt,
|
|
333
|
+
availableToolCount: tools.length,
|
|
334
|
+
shadowOnly: true
|
|
335
|
+
});
|
|
336
|
+
onEvent({ type: "route", routeDecision });
|
|
337
|
+
let effectiveSystemPrompt = systemPrompt;
|
|
338
|
+
if (routeDecision.route === "planned_execution") {
|
|
339
|
+
const planStartedAt = Date.now();
|
|
340
|
+
const planner = createAnalysisPlanner({
|
|
341
|
+
piModel,
|
|
342
|
+
apiKey: llmConfig.apiKey,
|
|
343
|
+
onPlanDelta: (delta) => onEvent({ type: "plan_delta", planDelta: delta }),
|
|
344
|
+
onThinkingDelta: (delta) => onEvent({ type: "think", content: delta, thinkTag: "thinking" }),
|
|
345
|
+
onThinkingEnd: (durationMs) => onEvent({ type: "think", content: "", thinkTag: "thinking", thinkDurationMs: durationMs }),
|
|
346
|
+
onValidationDelta: (delta) => onEvent({ type: "think", content: delta, thinkTag: "plan_validation" }),
|
|
347
|
+
onValidationEnd: (durationMs) => onEvent({ type: "think", content: "", thinkTag: "plan_validation", thinkDurationMs: durationMs })
|
|
348
|
+
});
|
|
349
|
+
const plan = await planner(routeInput, abortSignal);
|
|
350
|
+
if (plan) {
|
|
351
|
+
const planBlock = createPlanContentBlock(plan);
|
|
352
|
+
onEvent({ type: "plan", plan: planBlock });
|
|
353
|
+
effectiveSystemPrompt = `${systemPrompt}
|
|
354
|
+
|
|
355
|
+
${buildPlanGuidance(plan)}`;
|
|
356
|
+
aiLogger?.info("Planner", "Plan generated", {
|
|
357
|
+
title: plan.title,
|
|
358
|
+
steps: plan.steps.length,
|
|
359
|
+
successCriteria: plan.successCriteria.length,
|
|
360
|
+
elapsedMs: Date.now() - planStartedAt
|
|
361
|
+
});
|
|
362
|
+
} else {
|
|
363
|
+
aiLogger?.warn("Planner", "Plan generation skipped or failed", {
|
|
364
|
+
elapsedMs: Date.now() - planStartedAt,
|
|
365
|
+
route: routeDecision.route
|
|
366
|
+
});
|
|
367
|
+
onEvent({ type: "plan_skipped" });
|
|
368
|
+
}
|
|
369
|
+
}
|
|
296
370
|
const result = await runAgentCore({
|
|
297
371
|
piModel,
|
|
298
372
|
apiKey: llmConfig.apiKey,
|
|
299
|
-
systemPrompt,
|
|
300
|
-
tools,
|
|
373
|
+
systemPrompt: effectiveSystemPrompt,
|
|
374
|
+
tools: effectiveTools,
|
|
301
375
|
history,
|
|
302
376
|
userMessage,
|
|
303
377
|
maxToolRounds: DEFAULT_MAX_TOOL_ROUNDS,
|
|
@@ -366,6 +440,7 @@ function createCliRunAgentStream(dbManager, aiChatManager) {
|
|
|
366
440
|
assistantId,
|
|
367
441
|
skillId,
|
|
368
442
|
enableAutoSkill,
|
|
443
|
+
chartAutoMode,
|
|
369
444
|
compressionConfig,
|
|
370
445
|
ownerInfo,
|
|
371
446
|
mentionedMembers,
|
|
@@ -386,14 +461,17 @@ function createCliRunAgentStream(dbManager, aiChatManager) {
|
|
|
386
461
|
const contextWindow = llmConfig ? buildPiModel2(llmConfig).contextWindow ?? 128e3 : 128e3;
|
|
387
462
|
const maxToolResultTokens = Math.floor(contextWindow * (maxToolResultPercent / 100));
|
|
388
463
|
const db = dbManager.open?.(sessionId);
|
|
464
|
+
const resolvedChartAutoMode = chartAutoMode ?? "suggest";
|
|
389
465
|
const chartRuntime = resolveChartRuntimeForRequest({
|
|
390
466
|
skillId,
|
|
391
467
|
userMessage,
|
|
392
468
|
locale,
|
|
393
|
-
assistantAllowedTools
|
|
469
|
+
assistantAllowedTools,
|
|
470
|
+
enableAutoDetection: enableAutoSkill === true,
|
|
471
|
+
chartAutoMode: resolvedChartAutoMode
|
|
394
472
|
});
|
|
395
473
|
const isChartCapability = chartRuntime.isChartCapability;
|
|
396
|
-
const autoSkillAllowedTools = !skillId && enableAutoSkill ? getAllowedBuiltinToolsForChartAutoSkill(assistantAllowedTools) : assistantAllowedTools;
|
|
474
|
+
const autoSkillAllowedTools = !skillId && enableAutoSkill && resolvedChartAutoMode !== "explicit" ? getAllowedBuiltinToolsForChartAutoSkill(assistantAllowedTools) : assistantAllowedTools;
|
|
397
475
|
const allowedToolSet = getAllowedToolSet(
|
|
398
476
|
isChartCapability,
|
|
399
477
|
isChartCapability ? chartRuntime.allowedBuiltinTools : autoSkillAllowedTools
|
|
@@ -412,11 +490,8 @@ function createCliRunAgentStream(dbManager, aiChatManager) {
|
|
|
412
490
|
const def = skillMgr.getSkillConfig(skillId);
|
|
413
491
|
if (def) resolvedSkillDef = { name: def.name, prompt: def.prompt };
|
|
414
492
|
} else if (enableAutoSkill) {
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
locale,
|
|
418
|
-
toolNames
|
|
419
|
-
);
|
|
493
|
+
const baseMenu = skillMgr.getSkillMenu(chatType ?? "group", toolNames);
|
|
494
|
+
const menu = resolvedChartAutoMode === "aggressive" ? buildSkillMenuWithBuiltinChart(baseMenu, locale, toolNames) : baseMenu;
|
|
420
495
|
if (menu) resolvedSkillMenu = menu;
|
|
421
496
|
}
|
|
422
497
|
if (resolvedSkillMenu) {
|
|
@@ -425,7 +500,7 @@ function createCliRunAgentStream(dbManager, aiChatManager) {
|
|
|
425
500
|
allowedTools: toolNames,
|
|
426
501
|
coreToolNames: new Set(CHART_CAPABILITY_CORE_TOOLS),
|
|
427
502
|
locale,
|
|
428
|
-
getSkillConfig: (id) => getSkillConfigWithBuiltinChart(id, locale, (skillConfigId) => skillMgr.getSkillConfig(skillConfigId))
|
|
503
|
+
getSkillConfig: (id) => resolvedChartAutoMode === "aggressive" ? getSkillConfigWithBuiltinChart(id, locale, (skillConfigId) => skillMgr.getSkillConfig(skillConfigId)) : skillMgr.getSkillConfig(id)
|
|
429
504
|
});
|
|
430
505
|
agentTools.push(activateSkillTool);
|
|
431
506
|
}
|
|
@@ -438,19 +513,7 @@ function createCliRunAgentStream(dbManager, aiChatManager) {
|
|
|
438
513
|
let dataSnapshot;
|
|
439
514
|
if (db) {
|
|
440
515
|
try {
|
|
441
|
-
|
|
442
|
-
if (overview) {
|
|
443
|
-
dataSnapshot = {
|
|
444
|
-
name: overview.name,
|
|
445
|
-
platform: overview.platform,
|
|
446
|
-
type: overview.type,
|
|
447
|
-
totalMessages: overview.totalMessages,
|
|
448
|
-
totalMembers: overview.totalMembers,
|
|
449
|
-
firstMessageTs: overview.firstMessageTs,
|
|
450
|
-
lastMessageTs: overview.lastMessageTs,
|
|
451
|
-
capturedAt: Math.floor(Date.now() / 1e3)
|
|
452
|
-
};
|
|
453
|
-
}
|
|
516
|
+
dataSnapshot = createDataSnapshotFromOverview(getChatOverview(db, 10));
|
|
454
517
|
} catch {
|
|
455
518
|
}
|
|
456
519
|
}
|
|
@@ -472,7 +535,8 @@ function createCliRunAgentStream(dbManager, aiChatManager) {
|
|
|
472
535
|
ownerInfo,
|
|
473
536
|
mentionedMembers,
|
|
474
537
|
dataSnapshot,
|
|
475
|
-
thinkingLevel
|
|
538
|
+
thinkingLevel,
|
|
539
|
+
chartAutoMode: resolvedChartAutoMode
|
|
476
540
|
});
|
|
477
541
|
};
|
|
478
542
|
}
|
|
@@ -482,4 +546,4 @@ export {
|
|
|
482
546
|
closeServerAiLogger,
|
|
483
547
|
createCliRunAgentStream
|
|
484
548
|
};
|
|
485
|
-
//# sourceMappingURL=chunk-
|
|
549
|
+
//# sourceMappingURL=chunk-ILGSSXOG.mjs.map
|