xiaozhi-client 1.5.0-beta.0 → 1.5.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcpPipe.js DELETED
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env node
2
- var y=Object.defineProperty;var g=(c,e)=>y(c,"name",{value:e,configurable:!0});import{spawn as A}from"child_process";import i from"process";import{fileURLToPath as D}from"url";import{config as N}from"dotenv";import d from"ws";import{copyFileSync as M,existsSync as I,readFileSync as $,writeFileSync as R}from"fs";import{dirname as U,resolve as P}from"path";import{fileURLToPath as x}from"url";var k=U(x(import.meta.url)),C={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},b=class c{static{g(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=P(k,"xiaozhi.config.default.json")}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return P(e,"xiaozhi.config.json")}static getInstance(){return c.instance||(c.instance=new c),c.instance}configExists(){let e=this.getConfigFilePath();return I(e)}initConfig(){if(!I(this.defaultConfigPath))throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.default.json \u4E0D\u5B58\u5728");if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let e=this.getConfigFilePath();M(this.defaultConfigPath,e),this.config=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let e=this.getConfigFilePath(),t=$(e,"utf8"),o=JSON.parse(t);return this.validateConfig(o),o}catch(e){throw e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let t=e;if(!t.mcpEndpoint||typeof t.mcpEndpoint!="string")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(!t.mcpServers||typeof t.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[o,r]of Object.entries(t.mcpServers)){if(!r||typeof r!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o} \u65E0\u6548`);let s=r;if(s.type==="sse"){if(!s.url||typeof s.url!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.url \u65E0\u6548`)}else{if(!s.command||typeof s.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.command \u65E0\u6548`);if(!Array.isArray(s.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.args \u5FC5\u987B\u662F\u6570\u7EC4`);if(s.env&&typeof s.env!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.env \u5FC5\u987B\u662F\u5BF9\u8C61`)}}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMcpEndpoint(){return this.getConfig().mcpEndpoint}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,t){return this.getServerToolsConfig(e)[t]?.enable!==!1}updateMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let o={...this.getConfig(),mcpEndpoint:e};this.saveConfig(o)}updateMcpServer(e,t){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if("type"in t&&t.type==="sse"){if(!t.url||typeof t.url!="string")throw new Error("SSE \u670D\u52A1\u914D\u7F6E\u7684 url \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else{let s=t;if(!s.command||typeof s.command!="string")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 command \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!Array.isArray(s.args))throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4");if(s.env&&typeof s.env!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61")}let o=this.getConfig(),r={...o,mcpServers:{...o.mcpServers,[e]:t}};this.saveConfig(r)}removeMcpServer(e){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getConfig();if(!t.mcpServers[e])throw new Error(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728`);let o={...t.mcpServers};delete o[e];let r={...t,mcpServers:o};this.saveConfig(r)}updateServerToolsConfig(e,t){let r={...this.getConfig()};r.mcpServerConfig||(r.mcpServerConfig={}),r.mcpServerConfig[e]={tools:t},this.saveConfig(r)}setToolEnabled(e,t,o,r){let a={...this.getConfig()};a.mcpServerConfig||(a.mcpServerConfig={}),a.mcpServerConfig[e]||(a.mcpServerConfig[e]={tools:{}}),a.mcpServerConfig[e].tools[t]={enable:o,...r&&{description:r}},this.saveConfig(a)}saveConfig(e){try{this.validateConfig(e);let t=this.getConfigFilePath(),o=JSON.stringify(e,null,2);R(t,o,"utf8"),this.config=e}catch(t){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}reloadConfig(){this.config=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let t=this.getConfig().connection||{};return{heartbeatInterval:t.heartbeatInterval??C.heartbeatInterval,heartbeatTimeout:t.heartbeatTimeout??C.heartbeatTimeout,reconnectInterval:t.reconnectInterval??C.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let t=this.getConfig(),r={...t.connection||{},...e},s={...t,connection:r};this.saveConfig(s)}setHeartbeatInterval(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatInterval:e})}setHeartbeatTimeout(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatTimeout:e})}setReconnectInterval(e){if(e<=0)throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({reconnectInterval:e})}getModelScopeConfig(){return this.getConfig().modelscope||{}}getModelScopeApiKey(){return this.getModelScopeConfig().apiKey||process.env.MODELSCOPE_API_TOKEN}updateModelScopeConfig(e){let t=this.getConfig(),r={...t.modelscope||{},...e},s={...t,modelscope:r};this.saveConfig(s)}setModelScopeApiKey(e){if(!e||typeof e!="string")throw new Error("API Key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");this.updateModelScopeConfig({apiKey:e})}getWebUIConfig(){return this.getConfig().webUI||{}}getWebUIPort(){return this.getWebUIConfig().port??9999}updateWebUIConfig(e){let t=this.getConfig(),r={...t.webUI||{},...e},s={...t,webUI:r};this.saveConfig(s)}setWebUIPort(e){if(!Number.isInteger(e)||e<=0||e>65535)throw new Error("\u7AEF\u53E3\u53F7\u5FC5\u987B\u662F 1-65535 \u4E4B\u95F4\u7684\u6574\u6570");this.updateWebUIConfig({port:e})}},l=b.getInstance();import u from"fs";import O from"path";import p from"chalk";import{createConsola as F}from"consola";function W(c){let e=c.getFullYear(),t=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"),a=String(c.getSeconds()).padStart(2,"0");return`${e}-${t}-${o} ${r}:${s}:${a}`}g(W,"formatDateTime");var v=class{static{g(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=F({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:g(t=>{let o={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},r={info:p.blue,success:p.green,warn:p.yellow,error:p.red,debug:p.gray,log:g(f=>f,"log")},s=o[t.type]||t.type.toUpperCase(),a=r[t.type]||(f=>f),h=W(new Date),T=a(`[${s}]`),E=`[${h}] ${T} ${t.args.join(" ")}`;if(!e)try{console.error(E)}catch(f){if(f instanceof Error&&f.message?.includes("EPIPE"))return;throw f}},"log")}])}initLogFile(e){this.logFilePath=O.join(e,"xiaozhi.log"),u.existsSync(this.logFilePath)||u.writeFileSync(this.logFilePath,""),this.writeStream=u.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(e,t,...o){if(this.writeStream){let s=`[${new Date().toISOString()}] [${e.toUpperCase()}] ${t}`,a=o.length>0?`${s} ${o.map(h=>typeof h=="object"?JSON.stringify(h):String(h)).join(" ")}`:s;this.writeStream.write(`${a}
3
- `)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=u.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"}):!e&&this.writeStream&&(this.writeStream.end(),this.writeStream=null)}info(e,...t){this.consolaInstance.info(e,...t),this.logToFile("info",e,...t)}success(e,...t){this.consolaInstance.success(e,...t),this.logToFile("success",e,...t)}warn(e,...t){this.consolaInstance.warn(e,...t),this.logToFile("warn",e,...t)}error(e,...t){this.consolaInstance.error(e,...t),this.logToFile("error",e,...t)}debug(e,...t){this.consolaInstance.debug(e,...t),this.logToFile("debug",e,...t)}log(e,...t){this.consolaInstance.log(e,...t),this.logToFile("log",e,...t)}withTag(e){return this}close(){this.writeStream&&(this.writeStream.end(),this.writeStream=null)}},m=new v;N();var n=m.withTag("MCP_PIPE");i.env.XIAOZHI_DAEMON==="true"&&i.env.XIAOZHI_CONFIG_DIR&&(m.initLogFile(i.env.XIAOZHI_CONFIG_DIR),m.enableFileLogging(!0));var S=0,w=class{static{g(this,"MCPPipe")}mcpScript;endpointUrl;process;websocket;shouldReconnect;isConnected;shutdownResolve;heartbeatTimer;heartbeatTimeoutTimer;reconnectTimer;mcpProcessRestartAttempts;stdoutBuffer;connectionConfig;constructor(e,t){this.mcpScript=e,this.endpointUrl=t,this.process=null,this.websocket=null,this.shouldReconnect=!0,this.isConnected=!1,this.mcpProcessRestartAttempts=0,this.stdoutBuffer="";try{this.connectionConfig=l.getConnectionConfig(),n.info(`\u8FDE\u63A5\u914D\u7F6E: \u5FC3\u8DF3\u95F4\u9694=${this.connectionConfig.heartbeatInterval}ms, \u5FC3\u8DF3\u8D85\u65F6=${this.connectionConfig.heartbeatTimeout}ms, \u91CD\u8FDE\u95F4\u9694=${this.connectionConfig.reconnectInterval}ms`)}catch(o){this.connectionConfig={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},n.warn(`\u65E0\u6CD5\u83B7\u53D6\u8FDE\u63A5\u914D\u7F6E\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C: ${o instanceof Error?o.message:String(o)}`)}}async start(){return this.startMCPProcess(),await this.connectToServer(),this.reportStatusToWebUI(),new Promise(e=>{this.shutdownResolve=e})}async connectToServer(){this.isConnected||(n.info("\u6B63\u5728\u8FDE\u63A5 WebSocket \u670D\u52A1\u5668..."),this.websocket=new d(this.endpointUrl),this.websocket.on("open",()=>{n.info("\u6210\u529F\u8FDE\u63A5\u5230 WebSocket \u670D\u52A1\u5668"),this.isConnected=!0,this.reportStatusToWebUI(),S=0,this.mcpProcessRestartAttempts=0,this.startHeartbeat()}),this.websocket.on("message",e=>{let t=e.toString();n.info(`<< WebSocket\u6536\u5230\u6D88\u606F: ${t}`),this.process?.stdin&&!this.process.stdin.destroyed&&this.process.stdin.write(`${t}
4
- `)}),this.websocket.on("close",(e,t)=>{n.error(`WebSocket \u8FDE\u63A5\u5DF2\u5173\u95ED: ${e} ${t}`),this.isConnected=!1,this.websocket=null,this.stopHeartbeat(),this.reportStatusToWebUI(),this.shouldReconnect&&e!==4004&&this.scheduleReconnect()}),this.websocket.on("error",e=>{n.error(`WebSocket \u9519\u8BEF: ${e.message}`),this.isConnected=!1,this.stopHeartbeat()}),this.websocket.on("pong",()=>{this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=void 0)}))}scheduleReconnect(){this.shouldReconnect&&(this.reconnectTimer&&clearTimeout(this.reconnectTimer),S++,n.info(`\u8BA1\u5212\u5728 ${(this.connectionConfig.reconnectInterval/1e3).toFixed(2)} \u79D2\u540E\u8FDB\u884C\u7B2C ${S} \u6B21\u91CD\u8FDE\u5C1D\u8BD5...`),this.reconnectTimer=setTimeout(()=>{this.shouldReconnect&&((!this.process||this.process.killed)&&(n.info("MCP \u8FDB\u7A0B\u672A\u8FD0\u884C\uFF0C\u6B63\u5728\u5C1D\u8BD5\u91CD\u542F..."),this.restartMCPProcess()),this.connectToServer())},this.connectionConfig.reconnectInterval))}startHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(()=>{this.websocket&&this.websocket.readyState===d.OPEN&&(this.websocket.ping(),this.heartbeatTimeoutTimer=setTimeout(()=>{n.warn("\u5FC3\u8DF3\u8D85\u65F6\uFF0C\u8FDE\u63A5\u53EF\u80FD\u5DF2\u65AD\u5F00"),this.websocket&&this.websocket.terminate()},this.connectionConfig.heartbeatTimeout),this.reportStatusToWebUI())},this.connectionConfig.heartbeatInterval)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0),this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=void 0)}restartMCPProcess(){if(this.mcpProcessRestartAttempts>=3){n.error("MCP \u8FDB\u7A0B\u91CD\u542F\u5C1D\u8BD5\u6B21\u6570\u8D85\u9650\uFF0C\u653E\u5F03\u91CD\u542F");return}if(this.mcpProcessRestartAttempts++,n.info(`\u6B63\u5728\u5C1D\u8BD5\u91CD\u542F MCP \u8FDB\u7A0B\uFF08\u7B2C ${this.mcpProcessRestartAttempts} \u6B21\u5C1D\u8BD5\uFF09`),this.process){try{this.process.kill("SIGTERM")}catch(e){n.warn(`\u7EC8\u6B62\u73B0\u6709 MCP \u8FDB\u7A0B\u65F6\u51FA\u9519: ${e}`)}this.process=null}this.startMCPProcess()}startMCPProcess(){if(this.process){n.info(`${this.mcpScript} \u8FDB\u7A0B\u5DF2\u5728\u8FD0\u884C`);return}n.info(`\u6B63\u5728\u542F\u52A8 ${this.mcpScript} \u8FDB\u7A0B`),this.process=A("node",[this.mcpScript],{stdio:["pipe","pipe","pipe"]}),this.process.stdout?.on("data",e=>{this.stdoutBuffer+=e.toString();let t=this.stdoutBuffer.split(`
5
- `);this.stdoutBuffer=t.pop()||"";for(let o of t)if(o.trim()&&(n.info(`>> mcpServerProxy\u53D1\u9001\u6D88\u606F\u957F\u5EA6: ${o.length} \u5B57\u8282`),n.info(`>> mcpServerProxy\u53D1\u9001\u6D88\u606F: ${o.substring(0,500)}...`),this.websocket&&this.websocket.readyState===d.OPEN))try{this.websocket.send(`${o}
6
- `),n.info(">> \u6210\u529F\u53D1\u9001\u6D88\u606F\u5230 WebSocket")}catch(r){n.error(`>> \u53D1\u9001\u6D88\u606F\u5230 WebSocket \u5931\u8D25: ${r}`)}}),this.process.stderr?.on("data",e=>{if(i.env.XIAOZHI_DAEMON!=="true")try{i.stderr.write(e)}catch{}}),this.process.on("exit",(e,t)=>{n.warn(`${this.mcpScript} \u8FDB\u7A0B\u5DF2\u9000\u51FA\uFF0C\u9000\u51FA\u7801: ${e}, \u4FE1\u53F7: ${t}`),this.process=null,this.shouldReconnect&&t!=="SIGTERM"&&t!=="SIGKILL"&&n.info("MCP \u8FDB\u7A0B\u610F\u5916\u9000\u51FA\uFF0C\u5C06\u5728\u4E0B\u6B21\u91CD\u8FDE\u65F6\u5C1D\u8BD5\u91CD\u542F")}),this.process.on("error",e=>{n.error(`\u8FDB\u7A0B\u9519\u8BEF: ${e.message}`),this.process=null,this.shouldReconnect&&n.info("MCP \u8FDB\u7A0B\u53D1\u751F\u9519\u8BEF\uFF0C\u5C06\u5728\u4E0B\u6B21\u91CD\u8FDE\u65F6\u5C1D\u8BD5\u91CD\u542F")})}cleanup(){if(this.stopHeartbeat(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.stdoutBuffer="",this.process){n.info(`\u6B63\u5728\u7EC8\u6B62 ${this.mcpScript} \u8FDB\u7A0B`);try{this.process.kill("SIGTERM"),setTimeout(()=>{this.process&&!this.process.killed&&this.process.kill("SIGKILL")},5e3)}catch(e){n.error(`\u7EC8\u6B62\u8FDB\u7A0B\u65F6\u51FA\u9519: ${e instanceof Error?e.message:String(e)}`)}this.process=null}if(this.websocket){try{this.websocket.close()}catch(e){n.warn(`\u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${e}`)}this.websocket=null}this.isConnected=!1}sleep(e){return new Promise(t=>setTimeout(t,e))}shutdown(){n.info("\u6B63\u5728\u5173\u95ED MCP Pipe..."),this.shouldReconnect=!1,this.isConnected=!1,this.reportStatusToWebUI(),this.cleanup(),this.websocket&&this.websocket.close(),this.shutdownResolve&&this.shutdownResolve(),setTimeout(()=>{i.exit(0)},100)}async reportStatusToWebUI(){if(!(i.env.NODE_ENV==="test"||i.env.VITEST==="true"))try{let e=l.getWebUIPort(),t=new d(`ws://localhost:${e}`);t.on("open",()=>{let o={type:"clientStatus",data:{status:this.isConnected?"connected":"disconnected",mcpEndpoint:this.endpointUrl,activeMCPServers:[],lastHeartbeat:Date.now()}};t.send(JSON.stringify(o)),n.debug("\u5DF2\u5411 Web UI \u62A5\u544A\u72B6\u6001"),setTimeout(()=>{t.close()},1e3)}),t.on("error",o=>{n.debug(`Web UI \u8FDE\u63A5\u5931\u8D25\uFF08\u53EF\u80FD\u672A\u8FD0\u884C\uFF09: ${o.message}`)})}catch(e){n.debug(`\u5411 Web UI \u62A5\u544A\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}};function _(c){let e=i.env.XIAOZHI_DAEMON==="true";i.on("SIGINT",()=>{n.info("\u6536\u5230\u4E2D\u65AD\u4FE1\u53F7\uFF0C\u6B63\u5728\u5173\u95ED..."),c.shutdown()}),i.on("SIGTERM",()=>{n.info("\u6536\u5230\u7EC8\u6B62\u4FE1\u53F7\uFF0C\u6B63\u5728\u5173\u95ED..."),c.shutdown()}),e&&(i.on("SIGHUP",()=>{n.info("\u6536\u5230 SIGHUP \u4FE1\u53F7\uFF08\u7EC8\u7AEF\u5DF2\u5173\u95ED\uFF09\uFF0C\u7EE7\u7EED\u5728\u5B88\u62A4\u8FDB\u7A0B\u6A21\u5F0F\u4E0B\u8FD0\u884C...")}),i.on("uncaughtException",t=>{if(!t.message?.includes("EPIPE"))try{n.error(`\u5B88\u62A4\u8FDB\u7A0B\u6A21\u5F0F\u4E0B\u7684\u672A\u6355\u83B7\u5F02\u5E38: ${t.message}`),n.error(t.stack||"No stack trace available")}catch{}}),i.on("unhandledRejection",(t,o)=>{n.error(`\u5B88\u62A4\u8FDB\u7A0B\u6A21\u5F0F\u4E0B\u7684\u672A\u5904\u7406 Promise \u62D2\u7EDD: ${t}`),n.error(`Promise: ${o}`)}),n.info("\u5B88\u62A4\u8FDB\u7A0B\u6A21\u5F0F\u4FE1\u53F7\u5904\u7406\u5668\u5DF2\u521D\u59CB\u5316"))}g(_,"setupSignalHandlers");async function H(){i.argv.length<3&&(n.error("\u7528\u6CD5: node mcp_pipe.js <mcp_script>"),i.exit(1));let c=i.argv[2],e;try{if(i.env.XIAOZHI_DAEMON!=="true")try{i.stderr.write(`[DEBUG] XIAOZHI_CONFIG_DIR: ${i.env.XIAOZHI_CONFIG_DIR}
7
- `),i.stderr.write(`[DEBUG] process.cwd(): ${i.cwd()}
8
- `),i.stderr.write(`[DEBUG] configManager.getConfigPath(): ${l.getConfigPath()}
9
- `),i.stderr.write(`[DEBUG] configManager.configExists(): ${l.configExists()}
10
- `)}catch{}l.configExists()?(e=l.getMcpEndpoint(),n.info("\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\u4E2D\u7684 MCP \u7AEF\u70B9")):(e=i.env.MCP_ENDPOINT||"",e||(n.error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\u4E14\u672A\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF"),n.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),i.exit(1)),n.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\uFF08\u5EFA\u8BAE\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\uFF09"))}catch(o){n.error(`\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`),e=i.env.MCP_ENDPOINT||"",e||(n.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),i.exit(1)),n.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\u4F5C\u4E3A\u5907\u7528\u65B9\u6848")}(!e||e.includes("<\u8BF7\u586B\u5199"))&&(n.error("MCP \u7AEF\u70B9\u672A\u914D\u7F6E\u6216\u914D\u7F6E\u65E0\u6548"),n.error('\u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9'),i.exit(1));let t=new w(c,e);_(t);try{await t.start()}catch(o){n.error(`\u7A0B\u5E8F\u6267\u884C\u9519\u8BEF: ${o instanceof Error?o.message:String(o)}`),i.exit(1)}}g(H,"main");var G=import.meta.url,L=D(G),j=i.argv[1];L===j&&H().catch(c=>{n.error(`\u672A\u5904\u7406\u7684\u9519\u8BEF: ${c instanceof Error?c.message:String(c)}`),i.exit(1)});export{w as MCPPipe,_ as setupSignalHandlers};
11
- //# sourceMappingURL=mcpPipe.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/mcpPipe.ts","../src/configManager.ts","../src/logger.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Pipe - JavaScript Implementation\n * Connects to MCP server and pipes input/output to WebSocket endpoint\n * d\n * Version: 0.2.0\n *\n * Usage:\n * export MCP_ENDPOINT=<mcp_endpoint>\n * node mcp_pipe.js <mcp_script>\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\nimport { config } from \"dotenv\";\nimport WebSocket from \"ws\";\nimport { configManager } from \"./configManager\";\nimport { logger as globalLogger } from \"./logger\";\n\n// Load environment variables\nconfig();\n\n// 为 MCP_PIPE 创建带标签的 logger\nconst logger = globalLogger.withTag(\"MCP_PIPE\");\n\n// 如果在守护进程模式下运行,初始化日志文件\nif (process.env.XIAOZHI_DAEMON === \"true\" && process.env.XIAOZHI_CONFIG_DIR) {\n globalLogger.initLogFile(process.env.XIAOZHI_CONFIG_DIR);\n globalLogger.enableFileLogging(true);\n}\n\n// Reconnection settings - 从配置文件读取,有默认值兜底\nlet reconnectAttempt = 0;\n\nexport class MCPPipe {\n private mcpScript: string;\n private endpointUrl: string;\n private process: ChildProcess | null;\n private websocket: WebSocket | null;\n private shouldReconnect: boolean;\n private isConnected: boolean;\n private shutdownResolve?: () => void;\n private heartbeatTimer?: NodeJS.Timeout;\n private heartbeatTimeoutTimer?: NodeJS.Timeout;\n private reconnectTimer?: NodeJS.Timeout;\n private mcpProcessRestartAttempts: number;\n private stdoutBuffer: string; // 添加缓冲区来处理分片消息\n private connectionConfig: {\n heartbeatInterval: number;\n heartbeatTimeout: number;\n reconnectInterval: number;\n };\n\n constructor(mcpScript: string, endpointUrl: string) {\n this.mcpScript = mcpScript;\n this.endpointUrl = endpointUrl;\n this.process = null;\n this.websocket = null;\n this.shouldReconnect = true;\n this.isConnected = false;\n this.mcpProcessRestartAttempts = 0;\n this.stdoutBuffer = \"\"; // 初始化缓冲区\n\n // 获取连接配置,如果配置文件不存在则使用默认值\n try {\n this.connectionConfig = configManager.getConnectionConfig();\n logger.info(\n `连接配置: 心跳间隔=${this.connectionConfig.heartbeatInterval}ms, ` +\n `心跳超时=${this.connectionConfig.heartbeatTimeout}ms, ` +\n `重连间隔=${this.connectionConfig.reconnectInterval}ms`\n );\n } catch (error) {\n // 如果无法获取配置(如配置文件不存在),使用默认值\n this.connectionConfig = {\n heartbeatInterval: 30000,\n heartbeatTimeout: 10000,\n reconnectInterval: 5000,\n };\n logger.warn(\n `无法获取连接配置,使用默认值: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n async start() {\n // Start MCP script process\n this.startMCPProcess();\n\n // Start WebSocket connection\n await this.connectToServer();\n\n // Report status to web UI\n this.reportStatusToWebUI();\n\n // Keep the process running\n return new Promise<void>((resolve) => {\n // This promise will only resolve when shutdown is called\n this.shutdownResolve = resolve;\n });\n }\n\n async connectToServer() {\n if (this.isConnected) {\n return;\n }\n\n logger.info(\"正在连接 WebSocket 服务器...\");\n\n this.websocket = new WebSocket(this.endpointUrl);\n\n this.websocket.on(\"open\", () => {\n logger.info(\"成功连接到 WebSocket 服务器\");\n this.isConnected = true;\n\n // Report status to web UI when connected\n this.reportStatusToWebUI();\n\n // Reset reconnection counter\n reconnectAttempt = 0;\n this.mcpProcessRestartAttempts = 0;\n\n // 启动心跳检测\n this.startHeartbeat();\n });\n\n this.websocket.on(\"message\", (data: WebSocket.Data) => {\n const message = data.toString();\n logger.info(`<< WebSocket收到消息: ${message}`);\n\n // Write to process stdin\n if (this.process?.stdin && !this.process.stdin.destroyed) {\n this.process.stdin.write(`${message}\\n`);\n }\n });\n\n this.websocket.on(\"close\", (code: number, reason: Buffer) => {\n logger.error(`WebSocket 连接已关闭: ${code} ${reason}`);\n this.isConnected = false;\n this.websocket = null;\n\n // 停止心跳检测\n this.stopHeartbeat();\n\n // Report disconnected status to web UI\n this.reportStatusToWebUI();\n\n // Only reconnect if we should and it's not a permanent error\n if (this.shouldReconnect && code !== 4004) {\n this.scheduleReconnect();\n }\n });\n\n this.websocket.on(\"error\", (error: Error) => {\n logger.error(`WebSocket 错误: ${error.message}`);\n this.isConnected = false;\n\n // 网络错误时停止心跳检测\n this.stopHeartbeat();\n });\n\n // 添加 pong 响应处理\n this.websocket.on(\"pong\", () => {\n // 收到 pong 响应,清除心跳超时定时器\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer);\n this.heartbeatTimeoutTimer = undefined;\n }\n });\n }\n\n scheduleReconnect() {\n if (!this.shouldReconnect) return;\n\n // 清除之前的重连定时器\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n }\n\n reconnectAttempt++;\n\n logger.info(\n `计划在 ${(this.connectionConfig.reconnectInterval / 1000).toFixed(\n 2\n )} 秒后进行第 ${reconnectAttempt} 次重连尝试...`\n );\n\n this.reconnectTimer = setTimeout(() => {\n if (this.shouldReconnect) {\n // 如果MCP进程不存在,先尝试重启\n if (!this.process || this.process.killed) {\n logger.info(\"MCP 进程未运行,正在尝试重启...\");\n this.restartMCPProcess();\n }\n this.connectToServer();\n }\n }, this.connectionConfig.reconnectInterval);\n }\n\n // 心跳检测机制\n private startHeartbeat() {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n }\n\n this.heartbeatTimer = setInterval(() => {\n if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {\n // 发送 ping 并设置超时检测\n this.websocket.ping();\n\n // 设置心跳超时检测\n this.heartbeatTimeoutTimer = setTimeout(() => {\n logger.warn(\"心跳超时,连接可能已断开\");\n // 心跳超时,主动关闭连接触发重连\n if (this.websocket) {\n this.websocket.terminate();\n }\n }, this.connectionConfig.heartbeatTimeout);\n\n // Report status to web UI periodically\n this.reportStatusToWebUI();\n }\n }, this.connectionConfig.heartbeatInterval);\n }\n\n private stopHeartbeat() {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer);\n this.heartbeatTimeoutTimer = undefined;\n }\n }\n\n // MCP进程重启功能\n private restartMCPProcess() {\n if (this.mcpProcessRestartAttempts >= 3) {\n logger.error(\"MCP 进程重启尝试次数超限,放弃重启\");\n return;\n }\n\n this.mcpProcessRestartAttempts++;\n logger.info(\n `正在尝试重启 MCP 进程(第 ${this.mcpProcessRestartAttempts} 次尝试)`\n );\n\n // 清理现有进程\n if (this.process) {\n try {\n this.process.kill(\"SIGTERM\");\n } catch (error) {\n logger.warn(`终止现有 MCP 进程时出错: ${error}`);\n }\n this.process = null;\n }\n\n // 重新启动进程\n this.startMCPProcess();\n }\n\n startMCPProcess() {\n if (this.process) {\n logger.info(`${this.mcpScript} 进程已在运行`);\n return;\n }\n\n logger.info(`正在启动 ${this.mcpScript} 进程`);\n\n this.process = spawn(\"node\", [this.mcpScript], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n // Handle process stdout - send to WebSocket\n this.process.stdout?.on(\"data\", (data: Buffer) => {\n // 将数据添加到缓冲区\n this.stdoutBuffer += data.toString();\n\n // 按换行符分割消息\n const lines = this.stdoutBuffer.split(\"\\n\");\n this.stdoutBuffer = lines.pop() || \"\"; // 保留最后一个不完整的行\n\n // 处理每个完整的消息\n for (const line of lines) {\n if (line.trim()) {\n logger.info(`>> mcpServerProxy发送消息长度: ${line.length} 字节`);\n logger.info(\n `>> mcpServerProxy发送消息: ${line.substring(0, 500)}...`\n );\n\n if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {\n try {\n // 发送完整的消息行(包含换行符)\n this.websocket.send(`${line}\\n`);\n logger.info(\">> 成功发送消息到 WebSocket\");\n } catch (error) {\n logger.error(`>> 发送消息到 WebSocket 失败: ${error}`);\n }\n }\n }\n }\n });\n\n // Handle process stderr - print to terminal\n this.process.stderr?.on(\"data\", (data: Buffer) => {\n // 在守护进程模式下,避免写入已关闭的 stderr\n if (process.env.XIAOZHI_DAEMON !== \"true\") {\n try {\n process.stderr.write(data);\n } catch (error) {\n // 忽略 EPIPE 错误\n }\n }\n });\n\n // Handle process exit\n this.process.on(\n \"exit\",\n (code: number | null, signal: NodeJS.Signals | null) => {\n logger.warn(\n `${this.mcpScript} 进程已退出,退出码: ${code}, 信号: ${signal}`\n );\n this.process = null;\n\n // 如果不是主动关闭且应该重连,则尝试重启MCP进程\n if (\n this.shouldReconnect &&\n signal !== \"SIGTERM\" &&\n signal !== \"SIGKILL\"\n ) {\n logger.info(\"MCP 进程意外退出,将在下次重连时尝试重启\");\n // 不立即重启,而是在下次重连时处理\n }\n }\n );\n\n // Handle process error\n this.process.on(\"error\", (error: Error) => {\n logger.error(`进程错误: ${error.message}`);\n this.process = null;\n\n // 进程错误时不停止重连,让重连机制处理\n if (this.shouldReconnect) {\n logger.info(\"MCP 进程发生错误,将在下次重连时尝试重启\");\n }\n });\n }\n\n cleanup() {\n // 停止心跳检测\n this.stopHeartbeat();\n\n // 清除重连定时器\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n // 清空缓冲区\n this.stdoutBuffer = \"\";\n\n if (this.process) {\n logger.info(`正在终止 ${this.mcpScript} 进程`);\n try {\n this.process.kill(\"SIGTERM\");\n\n // Force kill after timeout\n setTimeout(() => {\n if (this.process && !this.process.killed) {\n this.process.kill(\"SIGKILL\");\n }\n }, 5000);\n } catch (error) {\n logger.error(\n `终止进程时出错: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n this.process = null;\n }\n\n if (this.websocket) {\n try {\n this.websocket.close();\n } catch (error) {\n logger.warn(`关闭 WebSocket 时出错: ${error}`);\n }\n this.websocket = null;\n }\n\n this.isConnected = false;\n }\n\n sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n shutdown() {\n logger.info(\"正在关闭 MCP Pipe...\");\n this.shouldReconnect = false;\n\n // Report disconnected status before shutting down\n this.isConnected = false;\n this.reportStatusToWebUI();\n\n this.cleanup();\n if (this.websocket) {\n this.websocket.close();\n }\n if (this.shutdownResolve) {\n this.shutdownResolve();\n }\n\n // Give a moment for the status report to be sent\n setTimeout(() => {\n process.exit(0);\n }, 100);\n }\n\n // Report status to web UI server\n private async reportStatusToWebUI() {\n // Skip in test environment\n if (process.env.NODE_ENV === \"test\" || process.env.VITEST === \"true\") {\n return;\n }\n\n try {\n // 从配置获取 WebUI 端口\n const port = configManager.getWebUIPort();\n const statusWs = new WebSocket(`ws://localhost:${port}`);\n\n statusWs.on(\"open\", () => {\n const status = {\n type: \"clientStatus\",\n data: {\n status: this.isConnected ? \"connected\" : \"disconnected\",\n mcpEndpoint: this.endpointUrl,\n activeMCPServers: [], // This will be filled by mcpServerProxy\n lastHeartbeat: Date.now(),\n },\n };\n statusWs.send(JSON.stringify(status));\n logger.debug(\"已向 Web UI 报告状态\");\n\n // Close connection after sending status\n setTimeout(() => {\n statusWs.close();\n }, 1000);\n });\n\n statusWs.on(\"error\", (error) => {\n logger.debug(`Web UI 连接失败(可能未运行): ${error.message}`);\n });\n } catch (error) {\n logger.debug(\n `向 Web UI 报告状态失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n}\n\n// Signal handlers\nexport function setupSignalHandlers(mcpPipe: MCPPipe): void {\n // 检查是否为守护进程模式\n const isDaemon = process.env.XIAOZHI_DAEMON === \"true\";\n\n process.on(\"SIGINT\", () => {\n logger.info(\"收到中断信号,正在关闭...\");\n mcpPipe.shutdown();\n });\n\n process.on(\"SIGTERM\", () => {\n logger.info(\"收到终止信号,正在关闭...\");\n mcpPipe.shutdown();\n });\n\n // 守护进程模式下的额外信号处理\n if (isDaemon) {\n // 忽略 SIGHUP 信号(终端关闭)\n process.on(\"SIGHUP\", () => {\n logger.info(\n \"收到 SIGHUP 信号(终端已关闭),继续在守护进程模式下运行...\"\n );\n // 守护进程不应该因为终端关闭而退出\n });\n\n // 处理未捕获的异常\n process.on(\"uncaughtException\", (error) => {\n // 如果是 EPIPE 错误(通常是因为终端关闭),静默处理\n if (error.message?.includes(\"EPIPE\")) {\n // EPIPE 错误在守护进程模式下是正常的,不需要记录\n return;\n }\n\n // 其他错误正常记录\n try {\n logger.error(`守护进程模式下的未捕获异常: ${error.message}`);\n logger.error(error.stack || \"No stack trace available\");\n } catch (logError) {\n // 如果日志记录失败(可能因为另一个 EPIPE 错误),则忽略\n }\n // 守护进程遇到未捕获的异常时不退出,而是继续运行\n });\n\n // 处理未处理的 Promise 拒绝\n process.on(\"unhandledRejection\", (reason, promise) => {\n logger.error(`守护进程模式下的未处理 Promise 拒绝: ${reason}`);\n logger.error(`Promise: ${promise}`);\n // 守护进程遇到未处理的 Promise 拒绝时不退出\n });\n\n logger.info(\"守护进程模式信号处理器已初始化\");\n }\n}\n\n// Main execution\nasync function main() {\n // Check command line arguments\n if (process.argv.length < 3) {\n logger.error(\"用法: node mcp_pipe.js <mcp_script>\");\n process.exit(1);\n }\n\n const mcpScript = process.argv[2];\n\n // Get endpoint URL from config file or environment variable (fallback)\n let endpointUrl: string;\n\n try {\n // 调试信息 - 只在非守护进程模式下输出\n if (process.env.XIAOZHI_DAEMON !== \"true\") {\n try {\n process.stderr.write(\n `[DEBUG] XIAOZHI_CONFIG_DIR: ${process.env.XIAOZHI_CONFIG_DIR}\\n`\n );\n process.stderr.write(`[DEBUG] process.cwd(): ${process.cwd()}\\n`);\n process.stderr.write(\n `[DEBUG] configManager.getConfigPath(): ${configManager.getConfigPath()}\\n`\n );\n process.stderr.write(\n `[DEBUG] configManager.configExists(): ${configManager.configExists()}\\n`\n );\n } catch (error) {\n // 忽略写入错误\n }\n }\n\n // 首先尝试从配置文件读取\n if (configManager.configExists()) {\n endpointUrl = configManager.getMcpEndpoint();\n logger.info(\"使用配置文件中的 MCP 端点\");\n } else {\n // 如果配置文件不存在,尝试从环境变量读取(向后兼容)\n endpointUrl = process.env.MCP_ENDPOINT || \"\";\n if (!endpointUrl) {\n logger.error(\"配置文件不存在且未设置 MCP_ENDPOINT 环境变量\");\n logger.error(\n '请运行 \"xiaozhi init\" 初始化配置,或设置 MCP_ENDPOINT 环境变量'\n );\n process.exit(1);\n }\n logger.info(\"使用环境变量中的 MCP 端点(建议使用配置文件)\");\n }\n } catch (error) {\n logger.error(\n `读取配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n\n // 尝试从环境变量读取作为备用方案\n endpointUrl = process.env.MCP_ENDPOINT || \"\";\n if (!endpointUrl) {\n logger.error(\n '请运行 \"xiaozhi init\" 初始化配置,或设置 MCP_ENDPOINT 环境变量'\n );\n process.exit(1);\n }\n logger.info(\"使用环境变量中的 MCP 端点作为备用方案\");\n }\n\n // 验证端点 URL\n if (!endpointUrl || endpointUrl.includes(\"<请填写\")) {\n logger.error(\"MCP 端点未配置或配置无效\");\n logger.error(\n '请运行 \"xiaozhi config mcpEndpoint <your-endpoint-url>\" 设置端点'\n );\n process.exit(1);\n }\n\n // Create MCP Pipe instance\n const mcpPipe = new MCPPipe(mcpScript, endpointUrl);\n\n // Setup signal handlers\n setupSignalHandlers(mcpPipe);\n\n // Start the MCP pipe\n try {\n await mcpPipe.start();\n } catch (error) {\n logger.error(\n `程序执行错误: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n}\n\n// Run if this file is executed directly\n// Use fileURLToPath to properly handle Windows paths\nconst currentFileUrl = import.meta.url;\nconst scriptPath = fileURLToPath(currentFileUrl);\nconst argv1Path = process.argv[1];\n\nif (scriptPath === argv1Path) {\n main().catch((error) => {\n logger.error(\n `未处理的错误: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n });\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 默认连接配置\nconst DEFAULT_CONNECTION_CONFIG: Required<ConnectionConfig> = {\n heartbeatInterval: 30000, // 30秒心跳间隔\n heartbeatTimeout: 10000, // 10秒心跳超时\n reconnectInterval: 5000, // 5秒重连间隔\n};\n\n// 配置文件接口定义\n// 本地 MCP 服务配置\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\n// ModelScope SSE MCP 服务配置\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\n// 统一的 MCP 服务配置\nexport type MCPServerConfig = LocalMCPServerConfig | SSEMCPServerConfig;\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface ConnectionConfig {\n heartbeatInterval?: number; // 心跳检测间隔(毫秒),默认30000\n heartbeatTimeout?: number; // 心跳超时时间(毫秒),默认10000\n reconnectInterval?: number; // 重连间隔(毫秒),默认5000\n}\n\nexport interface ModelScopeConfig {\n apiKey?: string; // ModelScope API 密钥\n}\n\nexport interface WebUIConfig {\n port?: number; // Web UI 端口号,默认 9999\n}\n\nexport interface AppConfig {\n mcpEndpoint: string;\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n connection?: ConnectionConfig; // 连接配置(可选,用于向后兼容)\n modelscope?: ModelScopeConfig; // ModelScope 配置(可选)\n webUI?: WebUIConfig; // Web UI 配置(可选)\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n\n private constructor() {\n this.defaultConfigPath = resolve(__dirname, \"xiaozhi.config.default.json\");\n }\n\n /**\n * 获取配置文件路径(动态计算)\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n const configPath = this.getConfigFilePath();\n return existsSync(configPath);\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n */\n public initConfig(): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(\"默认配置文件 xiaozhi.config.default.json 不存在\");\n }\n\n if (this.configExists()) {\n throw new Error(\"配置文件 xiaozhi.config.json 已存在,无需重复初始化\");\n }\n\n const configPath = this.getConfigFilePath();\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\n \"配置文件 xiaozhi.config.json 不存在,请先运行 xiaozhi init 初始化配置\"\n );\n }\n\n try {\n const configPath = this.getConfigFilePath();\n const configData = readFileSync(configPath, \"utf8\");\n const config = JSON.parse(configData) as AppConfig;\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (!configObj.mcpEndpoint || typeof configObj.mcpEndpoint !== \"string\") {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n const sc = serverConfig as Record<string, unknown>;\n\n // 检查是否是 SSE 类型\n if (sc.type === \"sse\") {\n // SSE 类型的验证\n if (!sc.url || typeof sc.url !== \"string\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.url 无效`\n );\n }\n } else {\n // 本地类型的验证\n if (!sc.command || typeof sc.command !== \"string\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.command 无效`\n );\n }\n\n if (!Array.isArray(sc.args)) {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.args 必须是数组`\n );\n }\n\n if (sc.env && typeof sc.env !== \"object\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.env 必须是对象`\n );\n }\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取 MCP 端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n return config.mcpEndpoint;\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点\n */\n public updateMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getConfig();\n const newConfig = { ...config, mcpEndpoint: endpoint };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 验证服务配置\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n // SSE 类型的验证\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n throw new Error(\"SSE 服务配置的 url 字段必须是非空字符串\");\n }\n } else {\n // 本地类型的验证\n const localConfig = serverConfig as LocalMCPServerConfig;\n if (!localConfig.command || typeof localConfig.command !== \"string\") {\n throw new Error(\"服务配置的 command 字段必须是非空字符串\");\n }\n\n if (!Array.isArray(localConfig.args)) {\n throw new Error(\"服务配置的 args 字段必须是数组\");\n }\n\n if (localConfig.env && typeof localConfig.env !== \"object\") {\n throw new Error(\"服务配置的 env 字段必须是对象\");\n }\n }\n\n const config = this.getConfig();\n const newConfig = {\n ...config,\n mcpServers: {\n ...config.mcpServers,\n [serverName]: serverConfig,\n },\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getConfig();\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n const newMcpServers = { ...config.mcpServers };\n delete newMcpServers[serverName];\n\n const newConfig = {\n ...config,\n mcpServers: newMcpServers,\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 更新指定服务的工具配置\n newConfig.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!newConfig.mcpServerConfig[serverName]) {\n newConfig.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n newConfig.mcpServerConfig[serverName].tools[toolName] = {\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 保存配置到文件\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 格式化 JSON 并保存\n const configPath = this.getConfigFilePath();\n const configJson = JSON.stringify(config, null, 2);\n writeFileSync(configPath, configJson, \"utf8\");\n\n // 更新缓存\n this.config = config;\n } catch (error) {\n throw new Error(\n `保存配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n\n /**\n * 获取连接配置(包含默认值)\n */\n public getConnectionConfig(): Required<ConnectionConfig> {\n const config = this.getConfig();\n const connectionConfig = config.connection || {};\n\n return {\n heartbeatInterval:\n connectionConfig.heartbeatInterval ??\n DEFAULT_CONNECTION_CONFIG.heartbeatInterval,\n heartbeatTimeout:\n connectionConfig.heartbeatTimeout ??\n DEFAULT_CONNECTION_CONFIG.heartbeatTimeout,\n reconnectInterval:\n connectionConfig.reconnectInterval ??\n DEFAULT_CONNECTION_CONFIG.reconnectInterval,\n };\n }\n\n /**\n * 获取心跳检测间隔(毫秒)\n */\n public getHeartbeatInterval(): number {\n return this.getConnectionConfig().heartbeatInterval;\n }\n\n /**\n * 获取心跳超时时间(毫秒)\n */\n public getHeartbeatTimeout(): number {\n return this.getConnectionConfig().heartbeatTimeout;\n }\n\n /**\n * 获取重连间隔(毫秒)\n */\n public getReconnectInterval(): number {\n return this.getConnectionConfig().reconnectInterval;\n }\n\n /**\n * 更新连接配置\n */\n public updateConnectionConfig(\n connectionConfig: Partial<ConnectionConfig>\n ): void {\n const config = this.getConfig();\n const currentConnectionConfig = config.connection || {};\n\n const newConnectionConfig = {\n ...currentConnectionConfig,\n ...connectionConfig,\n };\n\n const newConfig = {\n ...config,\n connection: newConnectionConfig,\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 设置心跳检测间隔\n */\n public setHeartbeatInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"心跳检测间隔必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatInterval: interval });\n }\n\n /**\n * 设置心跳超时时间\n */\n public setHeartbeatTimeout(timeout: number): void {\n if (timeout <= 0) {\n throw new Error(\"心跳超时时间必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatTimeout: timeout });\n }\n\n /**\n * 设置重连间隔\n */\n public setReconnectInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"重连间隔必须大于0\");\n }\n this.updateConnectionConfig({ reconnectInterval: interval });\n }\n\n /**\n * 获取 ModelScope 配置\n */\n public getModelScopeConfig(): Readonly<ModelScopeConfig> {\n const config = this.getConfig();\n return config.modelscope || {};\n }\n\n /**\n * 获取 ModelScope API Key\n * 优先从配置文件读取,其次从环境变量读取\n */\n public getModelScopeApiKey(): string | undefined {\n const modelScopeConfig = this.getModelScopeConfig();\n return modelScopeConfig.apiKey || process.env.MODELSCOPE_API_TOKEN;\n }\n\n /**\n * 更新 ModelScope 配置\n */\n public updateModelScopeConfig(\n modelScopeConfig: Partial<ModelScopeConfig>\n ): void {\n const config = this.getConfig();\n const currentModelScopeConfig = config.modelscope || {};\n\n const newModelScopeConfig = {\n ...currentModelScopeConfig,\n ...modelScopeConfig,\n };\n\n const newConfig = {\n ...config,\n modelscope: newModelScopeConfig,\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 设置 ModelScope API Key\n */\n public setModelScopeApiKey(apiKey: string): void {\n if (!apiKey || typeof apiKey !== \"string\") {\n throw new Error(\"API Key 必须是非空字符串\");\n }\n this.updateModelScopeConfig({ apiKey });\n }\n\n /**\n * 获取 Web UI 配置\n */\n public getWebUIConfig(): Readonly<WebUIConfig> {\n const config = this.getConfig();\n return config.webUI || {};\n }\n\n /**\n * 获取 Web UI 端口号\n */\n public getWebUIPort(): number {\n const webUIConfig = this.getWebUIConfig();\n return webUIConfig.port ?? 9999; // 默认端口 9999\n }\n\n /**\n * 更新 Web UI 配置\n */\n public updateWebUIConfig(webUIConfig: Partial<WebUIConfig>): void {\n const config = this.getConfig();\n const currentWebUIConfig = config.webUI || {};\n\n const newWebUIConfig = {\n ...currentWebUIConfig,\n ...webUIConfig,\n };\n\n const newConfig = {\n ...config,\n webUI: newWebUIConfig,\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 设置 Web UI 端口号\n */\n public setWebUIPort(port: number): void {\n if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n throw new Error(\"端口号必须是 1-65535 之间的整数\");\n }\n this.updateWebUIConfig({ port });\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\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":"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","names":["spawn","process","fileURLToPath","config","WebSocket","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","__dirname","dirname","fileURLToPath","DEFAULT_CONNECTION_CONFIG","ConfigManager","_ConfigManager","__name","resolve","configDir","configPath","existsSync","copyFileSync","configData","readFileSync","config","error","configObj","serverName","serverConfig","sc","toolName","endpoint","newConfig","localConfig","newMcpServers","toolsConfig","enabled","description","configJson","writeFileSync","connectionConfig","newConnectionConfig","interval","timeout","modelScopeConfig","newModelScopeConfig","apiKey","webUIConfig","newWebUIConfig","port","configManager","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","config","logger","process","reconnectAttempt","MCPPipe","__name","mcpScript","endpointUrl","configManager","error","resolve","WebSocket","data","message","code","reason","spawn","lines","line","signal","ms","port","statusWs","status","setupSignalHandlers","mcpPipe","isDaemon","promise","main","currentFileUrl","scriptPath","fileURLToPath","argv1Path"]}