xiaozhi-client 1.4.0 → 1.5.0-beta.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/README.md +86 -0
- package/dist/cli.js +19 -9
- package/dist/cli.js.map +1 -1
- package/dist/mcpPipe.js +0 -0
- package/dist/mcpServerProxy.js +7 -7
- package/dist/mcpServerProxy.js.map +1 -1
- package/dist/package.json +3 -1
- package/dist/services/mcpServer.d.ts +20 -0
- package/dist/services/mcpServer.js +12 -0
- package/dist/services/mcpServer.js.map +1 -0
- package/docs/images/integrate-to-cherry-studio.png +0 -0
- package/docs/images/integrate-to-cursor.png +0 -0
- package/package.json +22 -20
- package/web/dist/assets/index-FD98vGpI.js.map +1 -1
- package/web/README.md +0 -169
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
|
|
3
|
+
declare class MCPServer extends EventEmitter {
|
|
4
|
+
private app;
|
|
5
|
+
private server;
|
|
6
|
+
private clients;
|
|
7
|
+
private mcpProxy;
|
|
8
|
+
private port;
|
|
9
|
+
constructor(port?: number);
|
|
10
|
+
private setupMiddleware;
|
|
11
|
+
private setupRoutes;
|
|
12
|
+
private forwardToProxy;
|
|
13
|
+
private sendToClient;
|
|
14
|
+
private broadcastToClients;
|
|
15
|
+
start(): Promise<void>;
|
|
16
|
+
private startMCPProxy;
|
|
17
|
+
stop(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { MCPServer };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
var x=Object.defineProperty;var d=(c,t)=>x(c,"name",{value:t,configurable:!0});import{spawn as M}from"child_process";import{EventEmitter as $}from"events";import u from"path";import{fileURLToPath as v}from"url";import{randomUUID as T}from"crypto";import y from"express";import g from"fs";import w from"path";import m from"chalk";import{createConsola as C}from"consola";function I(c){let t=c.getFullYear(),e=String(c.getMonth()+1).padStart(2,"0"),o=String(c.getDate()).padStart(2,"0"),r=String(c.getHours()).padStart(2,"0"),s=String(c.getMinutes()).padStart(2,"0"),n=String(c.getSeconds()).padStart(2,"0");return`${t}-${e}-${o} ${r}:${s}:${n}`}d(I,"formatDateTime");var f=class{static{d(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=C({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let t=this.isDaemonMode;this.consolaInstance.setReporters([{log:d(e=>{let o={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},r={info:m.blue,success:m.green,warn:m.yellow,error:m.red,debug:m.gray,log:d(h=>h,"log")},s=o[e.type]||e.type.toUpperCase(),n=r[e.type]||(h=>h),a=I(new Date),l=n(`[${s}]`),p=`[${a}] ${l} ${e.args.join(" ")}`;if(!t)try{console.error(p)}catch(h){if(h instanceof Error&&h.message?.includes("EPIPE"))return;throw h}},"log")}])}initLogFile(t){this.logFilePath=w.join(t,"xiaozhi.log"),g.existsSync(this.logFilePath)||g.writeFileSync(this.logFilePath,""),this.writeStream=g.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(t,e,...o){if(this.writeStream){let s=`[${new Date().toISOString()}] [${t.toUpperCase()}] ${e}`,n=o.length>0?`${s} ${o.map(a=>typeof a=="object"?JSON.stringify(a):String(a)).join(" ")}`:s;this.writeStream.write(`${n}
|
|
2
|
+
`)}}enableFileLogging(t){t&&!this.writeStream&&this.logFilePath?this.writeStream=g.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"}):!t&&this.writeStream&&(this.writeStream.end(),this.writeStream=null)}info(t,...e){this.consolaInstance.info(t,...e),this.logToFile("info",t,...e)}success(t,...e){this.consolaInstance.success(t,...e),this.logToFile("success",t,...e)}warn(t,...e){this.consolaInstance.warn(t,...e),this.logToFile("warn",t,...e)}error(t,...e){this.consolaInstance.error(t,...e),this.logToFile("error",t,...e)}debug(t,...e){this.consolaInstance.debug(t,...e),this.logToFile("debug",t,...e)}log(t,...e){this.consolaInstance.log(t,...e),this.logToFile("log",t,...e)}withTag(t){return this}close(){this.writeStream&&(this.writeStream.end(),this.writeStream=null)}},P=new f;var E=v(import.meta.url),U=u.dirname(E),i=P.withTag("mcp-server"),S=class extends ${static{d(this,"MCPServer")}app;server=null;clients=new Map;mcpProxy=null;port;constructor(t=3e3){super(),this.port=t,this.app=y(),this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){this.app.use(y.json()),this.app.use(y.urlencoded({extended:!0})),this.app.use((t,e,o)=>{e.header("Access-Control-Allow-Origin","*"),e.header("Access-Control-Allow-Methods","GET, POST, OPTIONS"),e.header("Access-Control-Allow-Headers","Content-Type, Accept"),e.header("Cache-Control","no-cache"),o()})}setupRoutes(){this.app.get("/sse",(t,e)=>{let o=Date.now().toString(),r=T();e.setHeader("Content-Type","text/event-stream"),e.setHeader("Cache-Control","no-cache, no-transform"),e.setHeader("Connection","keep-alive"),e.setHeader("X-Accel-Buffering","no"),this.clients.set(r,{id:o,sessionId:r,response:e}),i.info(`MCP client connected: ${o} (session: ${r})`),e.write(`event: endpoint
|
|
3
|
+
data: /messages?sessionId=${r}
|
|
4
|
+
|
|
5
|
+
`),t.on("close",()=>{this.clients.delete(r),i.info(`MCP client disconnected: ${o} (session: ${r})`)})}),this.app.post("/messages",async(t,e)=>{try{let o=t.query.sessionId,r=t.body;if(i.info(`Received message via SSE transport (session: ${o}):`,JSON.stringify(r)),!o||!this.clients.has(o)){e.status(400).json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid or missing sessionId"},id:r.id});return}if(!this.mcpProxy){e.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP proxy not running"},id:r.id});return}if(r.id===void 0)i.info(`Forwarding notification: ${r.method}`),this.mcpProxy.stdin.write(`${JSON.stringify(r)}
|
|
6
|
+
`),e.status(202).send();else{let s=await this.forwardToProxy(r),n=this.clients.get(o);n&&this.sendToClient(n,s),e.status(202).send()}}catch(o){i.error("SSE message error:",o),e.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:o instanceof Error?o.message:"Internal error"},id:t.body.id})}}),this.app.post("/rpc",async(t,e)=>{try{let o=t.body;if(i.debug("Received RPC message:",o),!this.mcpProxy){e.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP proxy not running"},id:o.id});return}let r=await this.forwardToProxy(o);e.json(r)}catch(o){i.error("RPC error:",o),e.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:o instanceof Error?o.message:"Internal error"},id:t.body.id})}}),this.app.get("/health",(t,e)=>{e.json({status:"ok",mode:"mcp-server",proxy:this.mcpProxy?"running":"stopped",clients:this.clients.size})})}async forwardToProxy(t){return new Promise((e,o)=>{if(!this.mcpProxy||!this.mcpProxy.stdin||!this.mcpProxy.stdout){o(new Error("MCP proxy not available"));return}let r,s=d(n=>{try{let a=n.toString().split(`
|
|
7
|
+
`).filter(l=>l.trim());for(let l of a)try{let p=JSON.parse(l);if(i.debug(`Received response from proxy: ${l}`),p.id===t.id||t.method==="notifications/initialized"&&!p.id){clearTimeout(r),this.mcpProxy?.stdout?.removeListener("data",s),e(p);return}}catch{i.debug(`Non-JSON line from proxy: ${l}`)}}catch(a){clearTimeout(r),o(a)}},"messageHandler");this.mcpProxy.stdout.on("data",s),i.info(`Forwarding message to proxy: ${JSON.stringify(t)}`),this.mcpProxy.stdin.write(`${JSON.stringify(t)}
|
|
8
|
+
`),r=setTimeout(()=>{this.mcpProxy?.stdout?.removeListener("data",s),i.warn(`Request timeout for message id: ${t.id}, method: ${t.method} - This may be normal if the response was already sent via SSE`),e({jsonrpc:"2.0",id:t.id,result:{_timeout:!0,message:"Response may have been sent via SSE"}})},3e4)})}sendToClient(t,e){try{let o=`event: message
|
|
9
|
+
data: ${JSON.stringify(e)}
|
|
10
|
+
|
|
11
|
+
`;t.response.write(o)}catch(o){i.error(`Failed to send to client ${t.id}:`,o),this.clients.delete(t.sessionId)}}broadcastToClients(t){for(let e of this.clients.values())this.sendToClient(e,t)}async start(){try{await this.startMCPProxy(),this.server=this.app.listen(this.port,()=>{i.info(`MCP Server listening on port ${this.port}`),i.info(`SSE endpoint: http://localhost:${this.port}/sse`),i.info(`Messages endpoint: http://localhost:${this.port}/messages`),i.info(`RPC endpoint: http://localhost:${this.port}/rpc`)}),this.emit("started")}catch(t){throw i.error("Failed to start MCP server:",t),t}}async startMCPProxy(){let t=v(import.meta.url),e=u.dirname(t),o=null;for(let r=0;r<5;r++){let s=u.join(e,"mcpServerProxy.js"),n=await import("fs");if(n.existsSync(s)){o=s;break}let a=u.join(e,"dist","mcpServerProxy.js");if(n.existsSync(a)){o=a;break}e=u.dirname(e)}if(!o)throw new Error("Could not find mcpServerProxy.js in the project structure");i.info(`Starting MCP proxy from: ${o}`),this.mcpProxy=M("node",[o],{stdio:["pipe","pipe","pipe"],env:{...process.env,MCP_SERVER_MODE:"true",XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}}),this.mcpProxy.on("error",r=>{i.error("MCP proxy error:",r)}),this.mcpProxy.on("exit",(r,s)=>{i.warn(`MCP proxy exited with code ${r}, signal ${s}`),this.mcpProxy=null}),this.mcpProxy.stderr&&this.mcpProxy.stderr.on("data",r=>{let s=r.toString().trim();s.includes("[ERROR]")||s.includes("Error:")||s.includes("Failed")?i.error("MCP proxy stderr:",s):i.info("MCP proxy output:",s)}),await new Promise((r,s)=>{let n=setTimeout(()=>{s(new Error("MCP proxy startup timeout"))},1e4),a=d(l=>{let p=l.toString();(p.includes("MCP proxy ready")||p.includes("started"))&&(clearTimeout(n),this.mcpProxy?.stdout?.removeListener("data",a),r())},"dataHandler");this.mcpProxy?.stdout?.on("data",a)}),i.info("MCP proxy started successfully")}async stop(){i.info("Stopping MCP server...");for(let t of this.clients.values())try{t.response.end()}catch{}this.clients.clear(),this.server&&(await new Promise(t=>{this.server.close(()=>t())}),this.server=null),this.mcpProxy&&(this.mcpProxy.kill("SIGTERM"),await new Promise(t=>{this.mcpProxy.on("exit",()=>t()),setTimeout(()=>{this.mcpProxy?.kill("SIGKILL"),t()},5e3)}),this.mcpProxy=null),this.emit("stopped"),i.info("MCP server stopped")}};export{S as MCPServer};
|
|
12
|
+
//# sourceMappingURL=mcpServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/mcpServer.ts","../../src/logger.ts"],"sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport type { Server } from \"node:http\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { randomUUID } from \"node:crypto\";\nimport express from \"express\";\nimport { configManager } from \"../configManager.js\";\nimport { logger as globalLogger } from \"../logger.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\nconst logger = globalLogger.withTag(\"mcp-server\");\n\ninterface SSEClient {\n id: string;\n sessionId: string;\n response: express.Response;\n}\n\nexport class MCPServer extends EventEmitter {\n private app: express.Application;\n private server: Server | null = null;\n private clients: Map<string, SSEClient> = new Map();\n private mcpProxy: ChildProcess | null = null;\n private port: number;\n\n constructor(port = 3000) {\n super();\n this.port = port;\n this.app = express();\n this.setupMiddleware();\n this.setupRoutes();\n }\n\n private setupMiddleware(): void {\n this.app.use(express.json());\n this.app.use(express.urlencoded({ extended: true }));\n\n // CORS for MCP clients\n this.app.use((req, res, next) => {\n res.header(\"Access-Control-Allow-Origin\", \"*\");\n res.header(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.header(\"Access-Control-Allow-Headers\", \"Content-Type, Accept\");\n res.header(\"Cache-Control\", \"no-cache\");\n next();\n });\n }\n\n private setupRoutes(): void {\n // SSE endpoint for MCP protocol\n this.app.get(\"/sse\", (req, res) => {\n const clientId = Date.now().toString();\n const sessionId = randomUUID();\n\n // Set SSE headers (matching SDK implementation)\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache, no-transform\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n\n // Register client with sessionId\n this.clients.set(sessionId, { id: clientId, sessionId, response: res });\n logger.info(`MCP client connected: ${clientId} (session: ${sessionId})`);\n\n // Send endpoint event first (SDK standard)\n res.write(`event: endpoint\\ndata: /messages?sessionId=${sessionId}\\n\\n`);\n\n // Handle client disconnect\n req.on(\"close\", () => {\n this.clients.delete(sessionId);\n logger.info(`MCP client disconnected: ${clientId} (session: ${sessionId})`);\n });\n });\n\n // Messages endpoint for SSE transport (MCP SDK standard)\n this.app.post(\"/messages\", async (req, res) => {\n try {\n const sessionId = req.query.sessionId as string;\n const message = req.body;\n \n logger.info(`Received message via SSE transport (session: ${sessionId}):`, JSON.stringify(message));\n\n if (!sessionId || !this.clients.has(sessionId)) {\n res.status(400).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message: \"Invalid or missing sessionId\",\n },\n id: message.id,\n });\n return;\n }\n\n if (!this.mcpProxy) {\n res.status(503).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: \"MCP proxy not running\",\n },\n id: message.id,\n });\n return;\n }\n\n // Check if this is a notification (no id field means it's a notification)\n if (message.id === undefined) {\n // This is a notification, forward it but don't wait for response\n logger.info(`Forwarding notification: ${message.method}`);\n this.mcpProxy!.stdin!.write(`${JSON.stringify(message)}\\n`);\n \n // Send 202 Accepted immediately for notifications\n res.status(202).send();\n } else {\n // This is a request, forward and wait for response\n const response = await this.forwardToProxy(message);\n \n // Send response to specific client via SSE\n const client = this.clients.get(sessionId);\n if (client) {\n this.sendToClient(client, response);\n }\n \n // Send 202 Accepted to acknowledge receipt (SDK standard)\n res.status(202).send();\n }\n } catch (error) {\n logger.error(\"SSE message error:\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: error instanceof Error ? error.message : \"Internal error\",\n },\n id: req.body.id,\n });\n }\n });\n\n // JSON-RPC endpoint for direct RPC communication (legacy)\n this.app.post(\"/rpc\", async (req, res) => {\n try {\n const message = req.body;\n logger.debug(\"Received RPC message:\", message);\n\n if (!this.mcpProxy) {\n res.status(503).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: \"MCP proxy not running\",\n },\n id: message.id,\n });\n return;\n }\n\n // Forward to mcpServerProxy\n const response = await this.forwardToProxy(message);\n res.json(response);\n } catch (error) {\n logger.error(\"RPC error:\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: error instanceof Error ? error.message : \"Internal error\",\n },\n id: req.body.id,\n });\n }\n });\n\n // Health check\n this.app.get(\"/health\", (req, res) => {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\",\n proxy: this.mcpProxy ? \"running\" : \"stopped\",\n clients: this.clients.size,\n });\n });\n }\n\n private async forwardToProxy(message: any): Promise<any> {\n return new Promise((resolve, reject) => {\n if (!this.mcpProxy || !this.mcpProxy.stdin || !this.mcpProxy.stdout) {\n reject(new Error(\"MCP proxy not available\"));\n return;\n }\n\n let timeoutId: NodeJS.Timeout;\n\n const messageHandler = (data: Buffer) => {\n try {\n const lines = data\n .toString()\n .split(\"\\n\")\n .filter((line) => line.trim());\n for (const line of lines) {\n try {\n const response = JSON.parse(line);\n logger.debug(`Received response from proxy: ${line}`);\n // Check if this is a response to our request\n // Notifications don't have id, so we also check for matching method\n if (response.id === message.id || \n (message.method === \"notifications/initialized\" && !response.id)) {\n clearTimeout(timeoutId);\n this.mcpProxy?.stdout?.removeListener(\"data\", messageHandler);\n resolve(response);\n return;\n }\n } catch (e) {\n // Skip invalid JSON lines\n logger.debug(`Non-JSON line from proxy: ${line}`);\n }\n }\n } catch (error) {\n clearTimeout(timeoutId);\n reject(error);\n }\n };\n\n this.mcpProxy.stdout.on(\"data\", messageHandler);\n \n // Log the message being sent\n logger.info(`Forwarding message to proxy: ${JSON.stringify(message)}`);\n this.mcpProxy.stdin.write(`${JSON.stringify(message)}\\n`);\n\n // Timeout after 30 seconds\n timeoutId = setTimeout(() => {\n this.mcpProxy?.stdout?.removeListener(\"data\", messageHandler);\n logger.warn(`Request timeout for message id: ${message.id}, method: ${message.method} - This may be normal if the response was already sent via SSE`);\n // Don't reject with error, just resolve with a timeout indicator\n // This prevents error logs when the response was actually sent successfully\n resolve({ \n jsonrpc: \"2.0\", \n id: message.id,\n result: { _timeout: true, message: \"Response may have been sent via SSE\" }\n });\n }, 30000);\n });\n }\n\n private sendToClient(client: SSEClient, message: any): void {\n try {\n // Use event: message format (SDK standard)\n const data = `event: message\\ndata: ${JSON.stringify(message)}\\n\\n`;\n client.response.write(data);\n } catch (error) {\n logger.error(`Failed to send to client ${client.id}:`, error);\n this.clients.delete(client.sessionId);\n }\n }\n\n private broadcastToClients(message: any): void {\n for (const client of this.clients.values()) {\n this.sendToClient(client, message);\n }\n }\n\n public async start(): Promise<void> {\n try {\n // Start mcpServerProxy\n await this.startMCPProxy();\n\n // Start HTTP server\n this.server = this.app.listen(this.port, () => {\n logger.info(`MCP Server listening on port ${this.port}`);\n logger.info(`SSE endpoint: http://localhost:${this.port}/sse`);\n logger.info(`Messages endpoint: http://localhost:${this.port}/messages`);\n logger.info(`RPC endpoint: http://localhost:${this.port}/rpc`);\n });\n\n this.emit(\"started\");\n } catch (error) {\n logger.error(\"Failed to start MCP server:\", error);\n throw error;\n }\n }\n\n private async startMCPProxy(): Promise<void> {\n // 由于 tsup 打包的原因,import.meta.url 可能不准确\n // 我们需要找到 mcpServerProxy.js 的正确位置\n\n // 方法1:尝试从当前脚本的目录开始查找\n const currentScript = fileURLToPath(import.meta.url);\n let searchDir = path.dirname(currentScript);\n\n // 向上查找直到找到 mcpServerProxy.js\n let mcpProxyPath: string | null = null;\n for (let i = 0; i < 5; i++) {\n // 最多向上查找5级\n const testPath = path.join(searchDir, \"mcpServerProxy.js\");\n const fs = await import(\"node:fs\");\n if (fs.existsSync(testPath)) {\n mcpProxyPath = testPath;\n break;\n }\n // 也检查 dist 目录\n const distPath = path.join(searchDir, \"dist\", \"mcpServerProxy.js\");\n if (fs.existsSync(distPath)) {\n mcpProxyPath = distPath;\n break;\n }\n searchDir = path.dirname(searchDir);\n }\n\n if (!mcpProxyPath) {\n throw new Error(\n \"Could not find mcpServerProxy.js in the project structure\"\n );\n }\n\n logger.info(`Starting MCP proxy from: ${mcpProxyPath}`);\n\n this.mcpProxy = spawn(\"node\", [mcpProxyPath], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: {\n ...process.env,\n MCP_SERVER_MODE: \"true\",\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n this.mcpProxy.on(\"error\", (error) => {\n logger.error(\"MCP proxy error:\", error);\n });\n\n this.mcpProxy.on(\"exit\", (code, signal) => {\n logger.warn(`MCP proxy exited with code ${code}, signal ${signal}`);\n this.mcpProxy = null;\n });\n\n if (this.mcpProxy.stderr) {\n this.mcpProxy.stderr.on(\"data\", (data) => {\n const message = data.toString().trim();\n // mcpServerProxy 使用 logger 输出日志到 stderr,这些不是错误\n // 只有真正的错误信息才应该被标记为 ERROR\n if (message.includes(\"[ERROR]\") || message.includes(\"Error:\") || message.includes(\"Failed\")) {\n logger.error(\"MCP proxy stderr:\", message);\n } else {\n // 将正常的日志信息作为 info 级别输出\n logger.info(\"MCP proxy output:\", message);\n }\n });\n }\n\n // Wait for proxy to be ready\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(\"MCP proxy startup timeout\"));\n }, 10000);\n\n const dataHandler = (data: Buffer) => {\n const message = data.toString();\n if (\n message.includes(\"MCP proxy ready\") ||\n message.includes(\"started\")\n ) {\n clearTimeout(timeout);\n this.mcpProxy?.stdout?.removeListener(\"data\", dataHandler);\n resolve();\n }\n };\n\n this.mcpProxy?.stdout?.on(\"data\", dataHandler);\n });\n\n logger.info(\"MCP proxy started successfully\");\n }\n\n public async stop(): Promise<void> {\n logger.info(\"Stopping MCP server...\");\n\n // Close all SSE connections\n for (const client of this.clients.values()) {\n try {\n client.response.end();\n } catch (error) {\n // Ignore errors when closing\n }\n }\n this.clients.clear();\n\n // Stop HTTP server\n if (this.server) {\n await new Promise<void>((resolve) => {\n this.server!.close(() => resolve());\n });\n this.server = null;\n }\n\n // Stop MCP proxy\n if (this.mcpProxy) {\n this.mcpProxy.kill(\"SIGTERM\");\n await new Promise<void>((resolve) => {\n this.mcpProxy!.on(\"exit\", () => resolve());\n setTimeout(() => {\n this.mcpProxy?.kill(\"SIGKILL\");\n resolve();\n }, 5000);\n });\n this.mcpProxy = null;\n }\n\n this.emit(\"stopped\");\n logger.info(\"MCP server stopped\");\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { type consola, createConsola } from \"consola\";\n\nfunction formatDateTime(date: Date) {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\nexport class Logger {\n private logFilePath: string | null = null;\n private writeStream: fs.WriteStream | null = null;\n private consolaInstance: typeof consola;\n private isDaemonMode: boolean;\n\n constructor() {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n // 创建自定义的 consola 实例,禁用图标并自定义格式\n this.consolaInstance = createConsola({\n formatOptions: {\n date: false,\n colors: true,\n compact: true,\n },\n fancy: false,\n });\n\n // 保存对当前实例的引用,以便在闭包中访问\n const isDaemonMode = this.isDaemonMode;\n\n // 自定义格式化器\n this.consolaInstance.setReporters([\n {\n log: (logObj) => {\n const levelMap: Record<string, string> = {\n info: \"INFO\",\n success: \"SUCCESS\",\n warn: \"WARN\",\n error: \"ERROR\",\n debug: \"DEBUG\",\n log: \"LOG\",\n };\n\n const colorMap: Record<string, (text: string) => string> = {\n info: chalk.blue,\n success: chalk.green,\n warn: chalk.yellow,\n error: chalk.red,\n debug: chalk.gray,\n log: (text: string) => text,\n };\n\n const level = levelMap[logObj.type] || logObj.type.toUpperCase();\n const colorFn = colorMap[logObj.type] || ((text: string) => text);\n const timestamp = formatDateTime(new Date());\n\n // 为级别添加颜色\n const coloredLevel = colorFn(`[${level}]`);\n const message = `[${timestamp}] ${coloredLevel} ${logObj.args.join(\n \" \"\n )}`;\n\n // 守护进程模式下不输出到控制台,只写入文件\n if (!isDaemonMode) {\n // 输出到 stderr(与原来保持一致)\n try {\n console.error(message);\n } catch (error) {\n // 忽略 EPIPE 错误\n if (error instanceof Error && error.message?.includes(\"EPIPE\")) {\n return;\n }\n throw error;\n }\n }\n },\n },\n ]);\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 确保日志文件存在\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n\n // 创建写入流,追加模式\n this.writeStream = fs.createWriteStream(this.logFilePath, {\n flags: \"a\",\n encoding: \"utf8\",\n });\n }\n\n /**\n * 记录日志到文件\n * @param level 日志级别\n * @param message 日志消息\n * @param args 额外参数\n */\n private logToFile(level: string, message: string, ...args: any[]): void {\n if (this.writeStream) {\n const timestamp = new Date().toISOString();\n const formattedMessage = `[${timestamp}] [${level.toUpperCase()}] ${message}`;\n const fullMessage =\n args.length > 0\n ? `${formattedMessage} ${args\n .map((arg) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \")}`\n : formattedMessage;\n\n this.writeStream.write(`${fullMessage}\\n`);\n }\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n if (enable && !this.writeStream && this.logFilePath) {\n this.writeStream = fs.createWriteStream(this.logFilePath, {\n flags: \"a\",\n encoding: \"utf8\",\n });\n } else if (!enable && this.writeStream) {\n this.writeStream.end();\n this.writeStream = null;\n }\n }\n\n /**\n * 日志方法\n */\n info(message: string, ...args: any[]): void {\n this.consolaInstance.info(message, ...args);\n this.logToFile(\"info\", message, ...args);\n }\n\n success(message: string, ...args: any[]): void {\n this.consolaInstance.success(message, ...args);\n this.logToFile(\"success\", message, ...args);\n }\n\n warn(message: string, ...args: any[]): void {\n this.consolaInstance.warn(message, ...args);\n this.logToFile(\"warn\", message, ...args);\n }\n\n error(message: string, ...args: any[]): void {\n this.consolaInstance.error(message, ...args);\n this.logToFile(\"error\", message, ...args);\n }\n\n debug(message: string, ...args: any[]): void {\n this.consolaInstance.debug(message, ...args);\n this.logToFile(\"debug\", message, ...args);\n }\n\n log(message: string, ...args: any[]): void {\n this.consolaInstance.log(message, ...args);\n this.logToFile(\"log\", message, ...args);\n }\n\n /**\n * 创建一个带标签的日志实例(已废弃,直接返回原实例)\n * @param tag 标签(不再使用)\n * @deprecated 标签功能已移除\n */\n withTag(tag: string): Logger {\n // 不再添加标签,直接返回共享实例\n return this;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n if (this.writeStream) {\n this.writeStream.end();\n this.writeStream = null;\n }\n }\n}\n\n// 导出单例实例\nexport const logger = new Logger();\n"],"mappings":"+EAAA,OAA4B,SAAAA,MAAa,gBACzC,OAAS,gBAAAC,MAAoB,SAE7B,OAAOC,MAAU,OACjB,OAAS,iBAAAC,MAAqB,MAC9B,OAAS,cAAAC,MAAkB,SAC3B,OAAOC,MAAa,UCNpB,OAAOC,MAAQ,KACf,OAAOC,MAAU,OACjB,OAAOC,MAAW,QAClB,OAAuB,iBAAAC,MAAqB,UAE5C,SAASC,EAAeC,EAAY,CAClC,IAAMC,EAAOD,EAAK,YAAY,EACxBE,EAAQ,OAAOF,EAAK,SAAS,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,EACnDG,EAAM,OAAOH,EAAK,QAAQ,CAAC,EAAE,SAAS,EAAG,GAAG,EAC5CI,EAAQ,OAAOJ,EAAK,SAAS,CAAC,EAAE,SAAS,EAAG,GAAG,EAC/CK,EAAU,OAAOL,EAAK,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,EACnDM,EAAU,OAAON,EAAK,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,EAEzD,MAAO,GAAGC,CAAI,IAAIC,CAAK,IAAIC,CAAG,IAAIC,CAAK,IAAIC,CAAO,IAAIC,CAAO,EAC/D,CATSC,EAAAR,EAAA,kBAWF,IAAMS,EAAN,KAAa,CAhBpB,MAgBoB,CAAAD,EAAA,eACV,YAA6B,KAC7B,YAAqC,KACrC,gBACA,aAER,aAAc,CAEZ,KAAK,aAAe,QAAQ,IAAI,iBAAmB,OAEnD,KAAK,gBAAkBE,EAAc,CACnC,cAAe,CACb,KAAM,GACN,OAAQ,GACR,QAAS,EACX,EACA,MAAO,EACT,CAAC,EAGD,IAAMC,EAAe,KAAK,aAG1B,KAAK,gBAAgB,aAAa,CAChC,CACE,IAAKH,EAACI,GAAW,CACf,IAAMC,EAAmC,CACvC,KAAM,OACN,QAAS,UACT,KAAM,OACN,MAAO,QACP,MAAO,QACP,IAAK,KACP,EAEMC,EAAqD,CACzD,KAAMC,EAAM,KACZ,QAASA,EAAM,MACf,KAAMA,EAAM,OACZ,MAAOA,EAAM,IACb,MAAOA,EAAM,KACb,IAAKP,EAACQ,GAAiBA,EAAlB,MACP,EAEMC,EAAQJ,EAASD,EAAO,IAAI,GAAKA,EAAO,KAAK,YAAY,EACzDM,EAAUJ,EAASF,EAAO,IAAI,IAAOI,GAAiBA,GACtDG,EAAYnB,EAAe,IAAI,IAAM,EAGrCoB,EAAeF,EAAQ,IAAID,CAAK,GAAG,EACnCI,EAAU,IAAIF,CAAS,KAAKC,CAAY,IAAIR,EAAO,KAAK,KAC5D,GACF,CAAC,GAGD,GAAI,CAACD,EAEH,GAAI,CACF,QAAQ,MAAMU,CAAO,CACvB,OAASC,EAAO,CAEd,GAAIA,aAAiB,OAASA,EAAM,SAAS,SAAS,OAAO,EAC3D,OAEF,MAAMA,CACR,CAEJ,EA1CK,MA2CP,CACF,CAAC,CACH,CAMA,YAAYC,EAA0B,CACpC,KAAK,YAAcC,EAAK,KAAKD,EAAY,aAAa,EAGjDE,EAAG,WAAW,KAAK,WAAW,GACjCA,EAAG,cAAc,KAAK,YAAa,EAAE,EAIvC,KAAK,YAAcA,EAAG,kBAAkB,KAAK,YAAa,CACxD,MAAO,IACP,SAAU,MACZ,CAAC,CACH,CAQQ,UAAUR,EAAeI,KAAoBK,EAAmB,CACtE,GAAI,KAAK,YAAa,CAEpB,IAAMC,EAAmB,IADP,IAAI,KAAK,EAAE,YAAY,CACH,MAAMV,EAAM,YAAY,CAAC,KAAKI,CAAO,GACrEO,EACJF,EAAK,OAAS,EACV,GAAGC,CAAgB,IAAID,EACpB,IAAKG,GACJ,OAAOA,GAAQ,SAAW,KAAK,UAAUA,CAAG,EAAI,OAAOA,CAAG,CAC5D,EACC,KAAK,GAAG,CAAC,GACZF,EAEN,KAAK,YAAY,MAAM,GAAGC,CAAW;AAAA,CAAI,CAC3C,CACF,CAMA,kBAAkBE,EAAuB,CACnCA,GAAU,CAAC,KAAK,aAAe,KAAK,YACtC,KAAK,YAAcL,EAAG,kBAAkB,KAAK,YAAa,CACxD,MAAO,IACP,SAAU,MACZ,CAAC,EACQ,CAACK,GAAU,KAAK,cACzB,KAAK,YAAY,IAAI,EACrB,KAAK,YAAc,KAEvB,CAKA,KAAKT,KAAoBK,EAAmB,CAC1C,KAAK,gBAAgB,KAAKL,EAAS,GAAGK,CAAI,EAC1C,KAAK,UAAU,OAAQL,EAAS,GAAGK,CAAI,CACzC,CAEA,QAAQL,KAAoBK,EAAmB,CAC7C,KAAK,gBAAgB,QAAQL,EAAS,GAAGK,CAAI,EAC7C,KAAK,UAAU,UAAWL,EAAS,GAAGK,CAAI,CAC5C,CAEA,KAAKL,KAAoBK,EAAmB,CAC1C,KAAK,gBAAgB,KAAKL,EAAS,GAAGK,CAAI,EAC1C,KAAK,UAAU,OAAQL,EAAS,GAAGK,CAAI,CACzC,CAEA,MAAML,KAAoBK,EAAmB,CAC3C,KAAK,gBAAgB,MAAML,EAAS,GAAGK,CAAI,EAC3C,KAAK,UAAU,QAASL,EAAS,GAAGK,CAAI,CAC1C,CAEA,MAAML,KAAoBK,EAAmB,CAC3C,KAAK,gBAAgB,MAAML,EAAS,GAAGK,CAAI,EAC3C,KAAK,UAAU,QAASL,EAAS,GAAGK,CAAI,CAC1C,CAEA,IAAIL,KAAoBK,EAAmB,CACzC,KAAK,gBAAgB,IAAIL,EAAS,GAAGK,CAAI,EACzC,KAAK,UAAU,MAAOL,EAAS,GAAGK,CAAI,CACxC,CAOA,QAAQK,EAAqB,CAE3B,OAAO,IACT,CAKA,OAAc,CACR,KAAK,cACP,KAAK,YAAY,IAAI,EACrB,KAAK,YAAc,KAEvB,CACF,EAGaC,EAAS,IAAIvB,ED/L1B,IAAMwB,EAAaC,EAAc,YAAY,GAAG,EAC1CC,EAAYC,EAAK,QAAQH,CAAU,EACnCI,EAASA,EAAa,QAAQ,YAAY,EAQnCC,EAAN,cAAwBC,CAAa,CApB5C,MAoB4C,CAAAC,EAAA,kBAClC,IACA,OAAwB,KACxB,QAAkC,IAAI,IACtC,SAAgC,KAChC,KAER,YAAYC,EAAO,IAAM,CACvB,MAAM,EACN,KAAK,KAAOA,EACZ,KAAK,IAAMC,EAAQ,EACnB,KAAK,gBAAgB,EACrB,KAAK,YAAY,CACnB,CAEQ,iBAAwB,CAC9B,KAAK,IAAI,IAAIA,EAAQ,KAAK,CAAC,EAC3B,KAAK,IAAI,IAAIA,EAAQ,WAAW,CAAE,SAAU,EAAK,CAAC,CAAC,EAGnD,KAAK,IAAI,IAAI,CAACC,EAAKC,EAAKC,IAAS,CAC/BD,EAAI,OAAO,8BAA+B,GAAG,EAC7CA,EAAI,OAAO,+BAAgC,oBAAoB,EAC/DA,EAAI,OAAO,+BAAgC,sBAAsB,EACjEA,EAAI,OAAO,gBAAiB,UAAU,EACtCC,EAAK,CACP,CAAC,CACH,CAEQ,aAAoB,CAE1B,KAAK,IAAI,IAAI,OAAQ,CAACF,EAAKC,IAAQ,CACjC,IAAME,EAAW,KAAK,IAAI,EAAE,SAAS,EAC/BC,EAAYC,EAAW,EAG7BJ,EAAI,UAAU,eAAgB,mBAAmB,EACjDA,EAAI,UAAU,gBAAiB,wBAAwB,EACvDA,EAAI,UAAU,aAAc,YAAY,EACxCA,EAAI,UAAU,oBAAqB,IAAI,EAGvC,KAAK,QAAQ,IAAIG,EAAW,CAAE,GAAID,EAAU,UAAAC,EAAW,SAAUH,CAAI,CAAC,EACtEP,EAAO,KAAK,yBAAyBS,CAAQ,cAAcC,CAAS,GAAG,EAGvEH,EAAI,MAAM;AAAA,4BAA8CG,CAAS;AAAA;AAAA,CAAM,EAGvEJ,EAAI,GAAG,QAAS,IAAM,CACpB,KAAK,QAAQ,OAAOI,CAAS,EAC7BV,EAAO,KAAK,4BAA4BS,CAAQ,cAAcC,CAAS,GAAG,CAC5E,CAAC,CACH,CAAC,EAGD,KAAK,IAAI,KAAK,YAAa,MAAOJ,EAAKC,IAAQ,CAC7C,GAAI,CACF,IAAMG,EAAYJ,EAAI,MAAM,UACtBM,EAAUN,EAAI,KAIpB,GAFAN,EAAO,KAAK,gDAAgDU,CAAS,KAAM,KAAK,UAAUE,CAAO,CAAC,EAE9F,CAACF,GAAa,CAAC,KAAK,QAAQ,IAAIA,CAAS,EAAG,CAC9CH,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAAS,8BACX,EACA,GAAIK,EAAQ,EACd,CAAC,EACD,MACF,CAEA,GAAI,CAAC,KAAK,SAAU,CAClBL,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAAS,uBACX,EACA,GAAIK,EAAQ,EACd,CAAC,EACD,MACF,CAGA,GAAIA,EAAQ,KAAO,OAEjBZ,EAAO,KAAK,4BAA4BY,EAAQ,MAAM,EAAE,EACxD,KAAK,SAAU,MAAO,MAAM,GAAG,KAAK,UAAUA,CAAO,CAAC;AAAA,CAAI,EAG1DL,EAAI,OAAO,GAAG,EAAE,KAAK,MAChB,CAEL,IAAMM,EAAW,MAAM,KAAK,eAAeD,CAAO,EAG5CE,EAAS,KAAK,QAAQ,IAAIJ,CAAS,EACrCI,GACF,KAAK,aAAaA,EAAQD,CAAQ,EAIpCN,EAAI,OAAO,GAAG,EAAE,KAAK,CACvB,CACF,OAASQ,EAAO,CACdf,EAAO,MAAM,qBAAsBe,CAAK,EACxCR,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAASQ,aAAiB,MAAQA,EAAM,QAAU,gBACpD,EACA,GAAIT,EAAI,KAAK,EACf,CAAC,CACH,CACF,CAAC,EAGD,KAAK,IAAI,KAAK,OAAQ,MAAOA,EAAKC,IAAQ,CACxC,GAAI,CACF,IAAMK,EAAUN,EAAI,KAGpB,GAFAN,EAAO,MAAM,wBAAyBY,CAAO,EAEzC,CAAC,KAAK,SAAU,CAClBL,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAAS,uBACX,EACA,GAAIK,EAAQ,EACd,CAAC,EACD,MACF,CAGA,IAAMC,EAAW,MAAM,KAAK,eAAeD,CAAO,EAClDL,EAAI,KAAKM,CAAQ,CACnB,OAASE,EAAO,CACdf,EAAO,MAAM,aAAce,CAAK,EAChCR,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAASQ,aAAiB,MAAQA,EAAM,QAAU,gBACpD,EACA,GAAIT,EAAI,KAAK,EACf,CAAC,CACH,CACF,CAAC,EAGD,KAAK,IAAI,IAAI,UAAW,CAACA,EAAKC,IAAQ,CACpCA,EAAI,KAAK,CACP,OAAQ,KACR,KAAM,aACN,MAAO,KAAK,SAAW,UAAY,UACnC,QAAS,KAAK,QAAQ,IACxB,CAAC,CACH,CAAC,CACH,CAEA,MAAc,eAAeK,EAA4B,CACvD,OAAO,IAAI,QAAQ,CAACI,EAASC,IAAW,CACtC,GAAI,CAAC,KAAK,UAAY,CAAC,KAAK,SAAS,OAAS,CAAC,KAAK,SAAS,OAAQ,CACnEA,EAAO,IAAI,MAAM,yBAAyB,CAAC,EAC3C,MACF,CAEA,IAAIC,EAEEC,EAAiBhB,EAACiB,GAAiB,CACvC,GAAI,CACF,IAAMC,EAAQD,EACX,SAAS,EACT,MAAM;AAAA,CAAI,EACV,OAAQE,GAASA,EAAK,KAAK,CAAC,EAC/B,QAAWA,KAAQD,EACjB,GAAI,CACF,IAAMR,EAAW,KAAK,MAAMS,CAAI,EAIhC,GAHAtB,EAAO,MAAM,iCAAiCsB,CAAI,EAAE,EAGhDT,EAAS,KAAOD,EAAQ,IACvBA,EAAQ,SAAW,6BAA+B,CAACC,EAAS,GAAK,CACpE,aAAaK,CAAS,EACtB,KAAK,UAAU,QAAQ,eAAe,OAAQC,CAAc,EAC5DH,EAAQH,CAAQ,EAChB,MACF,CACF,MAAY,CAEVb,EAAO,MAAM,6BAA6BsB,CAAI,EAAE,CAClD,CAEJ,OAASP,EAAO,CACd,aAAaG,CAAS,EACtBD,EAAOF,CAAK,CACd,CACF,EA5BuB,kBA8BvB,KAAK,SAAS,OAAO,GAAG,OAAQI,CAAc,EAG9CnB,EAAO,KAAK,gCAAgC,KAAK,UAAUY,CAAO,CAAC,EAAE,EACrE,KAAK,SAAS,MAAM,MAAM,GAAG,KAAK,UAAUA,CAAO,CAAC;AAAA,CAAI,EAGxDM,EAAY,WAAW,IAAM,CAC3B,KAAK,UAAU,QAAQ,eAAe,OAAQC,CAAc,EAC5DnB,EAAO,KAAK,mCAAmCY,EAAQ,EAAE,aAAaA,EAAQ,MAAM,gEAAgE,EAGpJI,EAAQ,CACN,QAAS,MACT,GAAIJ,EAAQ,GACZ,OAAQ,CAAE,SAAU,GAAM,QAAS,qCAAsC,CAC3E,CAAC,CACH,EAAG,GAAK,CACV,CAAC,CACH,CAEQ,aAAaE,EAAmBF,EAAoB,CAC1D,GAAI,CAEF,IAAMQ,EAAO;AAAA,QAAyB,KAAK,UAAUR,CAAO,CAAC;AAAA;AAAA,EAC7DE,EAAO,SAAS,MAAMM,CAAI,CAC5B,OAASL,EAAO,CACdf,EAAO,MAAM,4BAA4Bc,EAAO,EAAE,IAAKC,CAAK,EAC5D,KAAK,QAAQ,OAAOD,EAAO,SAAS,CACtC,CACF,CAEQ,mBAAmBF,EAAoB,CAC7C,QAAWE,KAAU,KAAK,QAAQ,OAAO,EACvC,KAAK,aAAaA,EAAQF,CAAO,CAErC,CAEA,MAAa,OAAuB,CAClC,GAAI,CAEF,MAAM,KAAK,cAAc,EAGzB,KAAK,OAAS,KAAK,IAAI,OAAO,KAAK,KAAM,IAAM,CAC7CZ,EAAO,KAAK,gCAAgC,KAAK,IAAI,EAAE,EACvDA,EAAO,KAAK,kCAAkC,KAAK,IAAI,MAAM,EAC7DA,EAAO,KAAK,uCAAuC,KAAK,IAAI,WAAW,EACvEA,EAAO,KAAK,kCAAkC,KAAK,IAAI,MAAM,CAC/D,CAAC,EAED,KAAK,KAAK,SAAS,CACrB,OAASe,EAAO,CACd,MAAAf,EAAO,MAAM,8BAA+Be,CAAK,EAC3CA,CACR,CACF,CAEA,MAAc,eAA+B,CAK3C,IAAMQ,EAAgB1B,EAAc,YAAY,GAAG,EAC/C2B,EAAYzB,EAAK,QAAQwB,CAAa,EAGtCE,EAA8B,KAClC,QAASC,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAE1B,IAAMC,EAAW5B,EAAK,KAAKyB,EAAW,mBAAmB,EACnDI,EAAK,KAAM,QAAO,IAAS,EACjC,GAAIA,EAAG,WAAWD,CAAQ,EAAG,CAC3BF,EAAeE,EACf,KACF,CAEA,IAAME,EAAW9B,EAAK,KAAKyB,EAAW,OAAQ,mBAAmB,EACjE,GAAII,EAAG,WAAWC,CAAQ,EAAG,CAC3BJ,EAAeI,EACf,KACF,CACAL,EAAYzB,EAAK,QAAQyB,CAAS,CACpC,CAEA,GAAI,CAACC,EACH,MAAM,IAAI,MACR,2DACF,EAGFzB,EAAO,KAAK,4BAA4ByB,CAAY,EAAE,EAEtD,KAAK,SAAWK,EAAM,OAAQ,CAACL,CAAY,EAAG,CAC5C,MAAO,CAAC,OAAQ,OAAQ,MAAM,EAC9B,IAAK,CACH,GAAG,QAAQ,IACX,gBAAiB,OACjB,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EAED,KAAK,SAAS,GAAG,QAAUV,GAAU,CACnCf,EAAO,MAAM,mBAAoBe,CAAK,CACxC,CAAC,EAED,KAAK,SAAS,GAAG,OAAQ,CAACgB,EAAMC,IAAW,CACzChC,EAAO,KAAK,8BAA8B+B,CAAI,YAAYC,CAAM,EAAE,EAClE,KAAK,SAAW,IAClB,CAAC,EAEG,KAAK,SAAS,QAChB,KAAK,SAAS,OAAO,GAAG,OAASZ,GAAS,CACxC,IAAMR,EAAUQ,EAAK,SAAS,EAAE,KAAK,EAGjCR,EAAQ,SAAS,SAAS,GAAKA,EAAQ,SAAS,QAAQ,GAAKA,EAAQ,SAAS,QAAQ,EACxFZ,EAAO,MAAM,oBAAqBY,CAAO,EAGzCZ,EAAO,KAAK,oBAAqBY,CAAO,CAE5C,CAAC,EAIH,MAAM,IAAI,QAAc,CAACI,EAASC,IAAW,CAC3C,IAAMgB,EAAU,WAAW,IAAM,CAC/BhB,EAAO,IAAI,MAAM,2BAA2B,CAAC,CAC/C,EAAG,GAAK,EAEFiB,EAAc/B,EAACiB,GAAiB,CACpC,IAAMR,EAAUQ,EAAK,SAAS,GAE5BR,EAAQ,SAAS,iBAAiB,GAClCA,EAAQ,SAAS,SAAS,KAE1B,aAAaqB,CAAO,EACpB,KAAK,UAAU,QAAQ,eAAe,OAAQC,CAAW,EACzDlB,EAAQ,EAEZ,EAVoB,eAYpB,KAAK,UAAU,QAAQ,GAAG,OAAQkB,CAAW,CAC/C,CAAC,EAEDlC,EAAO,KAAK,gCAAgC,CAC9C,CAEA,MAAa,MAAsB,CACjCA,EAAO,KAAK,wBAAwB,EAGpC,QAAWc,KAAU,KAAK,QAAQ,OAAO,EACvC,GAAI,CACFA,EAAO,SAAS,IAAI,CACtB,MAAgB,CAEhB,CAEF,KAAK,QAAQ,MAAM,EAGf,KAAK,SACP,MAAM,IAAI,QAAeE,GAAY,CACnC,KAAK,OAAQ,MAAM,IAAMA,EAAQ,CAAC,CACpC,CAAC,EACD,KAAK,OAAS,MAIZ,KAAK,WACP,KAAK,SAAS,KAAK,SAAS,EAC5B,MAAM,IAAI,QAAeA,GAAY,CACnC,KAAK,SAAU,GAAG,OAAQ,IAAMA,EAAQ,CAAC,EACzC,WAAW,IAAM,CACf,KAAK,UAAU,KAAK,SAAS,EAC7BA,EAAQ,CACV,EAAG,GAAI,CACT,CAAC,EACD,KAAK,SAAW,MAGlB,KAAK,KAAK,SAAS,EACnBhB,EAAO,KAAK,oBAAoB,CAClC,CACF","names":["spawn","EventEmitter","path","fileURLToPath","randomUUID","express","fs","path","chalk","createConsola","formatDateTime","date","year","month","day","hours","minutes","seconds","__name","Logger","createConsola","isDaemonMode","logObj","levelMap","colorMap","chalk","text","level","colorFn","timestamp","coloredLevel","message","error","projectDir","path","fs","args","formattedMessage","fullMessage","arg","enable","tag","logger","__filename","fileURLToPath","__dirname","path","logger","MCPServer","EventEmitter","__name","port","express","req","res","next","clientId","sessionId","randomUUID","message","response","client","error","resolve","reject","timeoutId","messageHandler","data","lines","line","currentScript","searchDir","mcpProxyPath","i","testPath","fs","distPath","spawn","code","signal","timeout","dataHandler"]}
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xiaozhi-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0-beta.0",
|
|
4
4
|
"description": "小智 AI 客户端 命令行工具",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli.js",
|
|
@@ -20,24 +20,6 @@
|
|
|
20
20
|
"xiaozhi": "./dist/cli.js",
|
|
21
21
|
"xiaozhi-client": "./dist/cli.js"
|
|
22
22
|
},
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build": "pnpm run build:web && tsup",
|
|
25
|
-
"build:web": "cd web && pnpm install && pnpm run build",
|
|
26
|
-
"dev": "tsup --watch",
|
|
27
|
-
"test": "vitest run",
|
|
28
|
-
"test:watch": "vitest",
|
|
29
|
-
"test:coverage": "vitest run --coverage",
|
|
30
|
-
"test:ui": "vitest --ui",
|
|
31
|
-
"format": "biome format --write .",
|
|
32
|
-
"lint": "biome lint --write .",
|
|
33
|
-
"type:check": "tsc --noEmit",
|
|
34
|
-
"check": "biome check .",
|
|
35
|
-
"check:write": "biome check --write .",
|
|
36
|
-
"check:all": "pnpm check && pnpm type:check && pnpm spell:check && pnpm duplicate:check",
|
|
37
|
-
"spell:check": "cspell \"src/**/*.ts\" \"*.md\" \"*.json\"",
|
|
38
|
-
"duplicate:check": "jscpd src/",
|
|
39
|
-
"release": "semantic-release"
|
|
40
|
-
},
|
|
41
23
|
"keywords": [
|
|
42
24
|
"xiaozhi",
|
|
43
25
|
"mcp",
|
|
@@ -48,12 +30,14 @@
|
|
|
48
30
|
"license": "MIT",
|
|
49
31
|
"dependencies": {
|
|
50
32
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
33
|
+
"@types/express": "^5.0.3",
|
|
51
34
|
"chalk": "^5.4.1",
|
|
52
35
|
"cli-table3": "^0.6.5",
|
|
53
36
|
"commander": "^14.0.0",
|
|
54
37
|
"consola": "^3.4.2",
|
|
55
38
|
"dotenv": "^16.3.1",
|
|
56
39
|
"eventsource": "^4.0.0",
|
|
40
|
+
"express": "^5.1.0",
|
|
57
41
|
"omelette": "^0.4.17",
|
|
58
42
|
"ora": "^8.2.0",
|
|
59
43
|
"ws": "^8.14.2",
|
|
@@ -83,5 +67,23 @@
|
|
|
83
67
|
"tsup": "^8.5.0",
|
|
84
68
|
"typescript": "^5.8.3",
|
|
85
69
|
"vitest": "^3.2.3"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "pnpm run build:web && tsup",
|
|
73
|
+
"build:web": "cd web && pnpm install && pnpm run build",
|
|
74
|
+
"dev": "tsup --watch",
|
|
75
|
+
"test": "vitest run",
|
|
76
|
+
"test:watch": "vitest",
|
|
77
|
+
"test:coverage": "vitest run --coverage",
|
|
78
|
+
"test:ui": "vitest --ui",
|
|
79
|
+
"format": "biome format --write .",
|
|
80
|
+
"lint": "biome lint --write .",
|
|
81
|
+
"type:check": "tsc --noEmit",
|
|
82
|
+
"check": "biome check .",
|
|
83
|
+
"check:write": "biome check --write .",
|
|
84
|
+
"check:all": "pnpm check && pnpm type:check && pnpm spell:check && pnpm duplicate:check",
|
|
85
|
+
"spell:check": "cspell \"src/**/*.ts\" \"*.md\" \"*.json\"",
|
|
86
|
+
"duplicate:check": "jscpd src/",
|
|
87
|
+
"release": "semantic-release"
|
|
86
88
|
}
|
|
87
|
-
}
|
|
89
|
+
}
|