xiaozhi-client 1.6.0-beta.2 → 1.6.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +98 -0
  2. package/dist/adaptiveMCPPipe.js +10 -10
  3. package/dist/adaptiveMCPPipe.js.map +1 -1
  4. package/dist/autoCompletion.js +1 -1
  5. package/dist/autoCompletion.js.map +1 -1
  6. package/dist/cli.js +19 -19
  7. package/dist/cli.js.map +1 -1
  8. package/dist/configManager.d.ts +12 -1
  9. package/dist/configManager.js +1 -1
  10. package/dist/configManager.js.map +1 -1
  11. package/dist/mcpCommands.js +1 -1
  12. package/dist/mcpCommands.js.map +1 -1
  13. package/dist/mcpServerProxy.js +7 -7
  14. package/dist/mcpServerProxy.js.map +1 -1
  15. package/dist/modelScopeMCPClient.js +2 -2
  16. package/dist/modelScopeMCPClient.js.map +1 -1
  17. package/dist/multiEndpointMCPPipe.js +6 -6
  18. package/dist/multiEndpointMCPPipe.js.map +1 -1
  19. package/dist/package.json +14 -2
  20. package/dist/services/mcpServer.js +9 -9
  21. package/dist/services/mcpServer.js.map +1 -1
  22. package/dist/streamableHttpMCPClient.js +2 -2
  23. package/dist/streamableHttpMCPClient.js.map +1 -1
  24. package/dist/templates/docker/mcpServers/calculator.js +106 -0
  25. package/dist/templates/docker/mcpServers/datetime.js +390 -0
  26. package/dist/templates/docker/package.json +13 -0
  27. package/dist/templates/docker/xiaozhi.config.json +21 -0
  28. package/dist/templates/modelscope/xiaozhi.config.json +20 -0
  29. package/dist/webServer.d.ts +6 -2
  30. package/dist/webServer.js +19 -19
  31. package/dist/webServer.js.map +1 -1
  32. package/docs/images/web-ui-preview.png +0 -0
  33. package/package.json +12 -2
  34. package/templates/docker/mcpServers/calculator.js +106 -0
  35. package/templates/docker/mcpServers/datetime.js +390 -0
  36. package/templates/docker/package.json +13 -0
  37. package/templates/docker/xiaozhi.config.json +21 -0
  38. package/templates/modelscope/xiaozhi.config.json +20 -0
  39. package/web/dist/assets/index-Da0jgqOv.css +1 -0
  40. package/web/dist/assets/index-DaMLY0Ce.js +236 -0
  41. package/web/dist/assets/index-DaMLY0Ce.js.map +1 -0
  42. package/web/dist/index.html +2 -2
  43. package/web/dist/assets/index-LtUI_xx4.css +0 -1
  44. package/web/dist/assets/index-lAiGa4ms.js +0 -169
  45. package/web/dist/assets/index-lAiGa4ms.js.map +0 -1
package/dist/webServer.js CHANGED
@@ -1,25 +1,25 @@
1
- var te=Object.defineProperty;var g=(r,e)=>te(r,"name",{value:e,configurable:!0});var D=(r,e)=>()=>(r&&(e=r(r=0)),e);var xe=(r,e)=>{for(var o in e)te(r,o,{get:e[o],enumerable:!0})};import{copyFileSync as Ee,existsSync as U,readFileSync as Te,writeFileSync as $e}from"fs";import{dirname as Me,resolve as T}from"path";import{fileURLToPath as je}from"url";import Re from"json5";import*as ne from"jsonc-parser";var Oe,X,B,l,E=D(()=>{"use strict";Oe=Me(je(import.meta.url)),X={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},B=class r{static{g(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=T(Oe,"xiaozhi.config.default.json")}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),o=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let t of o){let n=T(e,t);if(U(n))return n}return T(e,"xiaozhi.config.json")}getConfigFileFormat(e){return e.endsWith(".json5")?"json5":e.endsWith(".jsonc")?"jsonc":"json"}static getInstance(){return r.instance||(r.instance=new r),r.instance}configExists(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),o=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let t of o){let n=T(e,t);if(U(n))return!0}return!1}initConfig(e="json"){if(!U(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\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let o=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=`xiaozhi.config.${e}`,n=T(o,t);Ee(this.defaultConfigPath,n),this.config=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let e=this.getConfigFilePath(),o=this.getConfigFileFormat(e),t=Te(e,"utf8"),n;switch(o){case"json5":n=Re.parse(t);break;case"jsonc":n=ne.parse(t);break;default:n=JSON.parse(t);break}return this.validateConfig(n),n}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 o=e;if(o.mcpEndpoint===void 0||o.mcpEndpoint===null)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(typeof o.mcpEndpoint!="string")if(Array.isArray(o.mcpEndpoint)){if(o.mcpEndpoint.length===0)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E0D\u80FD\u4E3A\u7A7A");for(let t of o.mcpEndpoint)if(typeof t!="string"||t.trim()==="")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5B57\u7B26\u4E32\u6570\u7EC4");if(!o.mcpServers||typeof o.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[t,n]of Object.entries(o.mcpServers)){if(!n||typeof n!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t} \u65E0\u6548`);let s=n;if(s.url&&typeof s.url=="string"){if(s.type&&s.type!=="sse"&&s.type!=="streamable-http")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.type \u5FC5\u987B\u662F "sse" \u6216 "streamable-http"`)}else{if(!s.command||typeof s.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.command \u65E0\u6548`);if(!Array.isArray(s.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.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.${t}.env \u5FC5\u987B\u662F\u5BF9\u8C61`)}}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMcpEndpoint(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?e.mcpEndpoint[0]||"":e.mcpEndpoint}getMcpEndpoints(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?[...e.mcpEndpoint]:e.mcpEndpoint?[e.mcpEndpoint]:[]}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,o){return this.getServerToolsConfig(e)[o]?.enable!==!1}updateMcpEndpoint(e){if(Array.isArray(e)){if(e.length===0)throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E0D\u80FD\u4E3A\u7A7A");for(let n of e)if(!n||typeof n!="string")throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t={...this.getConfig(),mcpEndpoint:e};this.saveConfig(t)}addMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let o=this.getConfig(),t=this.getMcpEndpoints();if(t.includes(e))throw new Error(`MCP \u7AEF\u70B9 ${e} \u5DF2\u5B58\u5728`);let n=[...t,e],s={...o,mcpEndpoint:n};this.saveConfig(s)}removeMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let o=this.getConfig(),t=this.getMcpEndpoints();if(t.indexOf(e)===-1)throw new Error(`MCP \u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728`);if(t.length===1)throw new Error("\u4E0D\u80FD\u5220\u9664\u6700\u540E\u4E00\u4E2A MCP \u7AEF\u70B9");let s=t.filter(a=>a!==e),c={...o,mcpEndpoint:s};this.saveConfig(c)}updateMcpServer(e,o){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if("type"in o&&o.type==="sse"){if(!o.url||typeof o.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=o;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 t=this.getConfig(),n={...t,mcpServers:{...t.mcpServers,[e]:o}};this.saveConfig(n)}removeMcpServer(e){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let o=this.getConfig();if(!o.mcpServers[e])throw new Error(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728`);let t={...o.mcpServers};delete t[e];let n={...o,mcpServers:t};this.saveConfig(n)}updateServerToolsConfig(e,o){let n={...this.getConfig()};n.mcpServerConfig||(n.mcpServerConfig={}),Object.keys(o).length===0?delete n.mcpServerConfig[e]:n.mcpServerConfig[e]={tools:o},this.saveConfig(n)}removeServerToolsConfig(e){let t={...this.getConfig()};t.mcpServerConfig&&(delete t.mcpServerConfig[e],this.saveConfig(t))}setToolEnabled(e,o,t,n){let c={...this.getConfig()};c.mcpServerConfig||(c.mcpServerConfig={}),c.mcpServerConfig[e]||(c.mcpServerConfig[e]={tools:{}}),c.mcpServerConfig[e].tools[o]={enable:t,...n&&{description:n}},this.saveConfig(c)}saveConfig(e){try{this.validateConfig(e);let o=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=T(o,"xiaozhi.config.json"),n=JSON.stringify(e,null,2);$e(t,n,"utf8"),this.config=e}catch(o){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}reloadConfig(){this.config=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let o=this.getConfig().connection||{};return{heartbeatInterval:o.heartbeatInterval??X.heartbeatInterval,heartbeatTimeout:o.heartbeatTimeout??X.heartbeatTimeout,reconnectInterval:o.reconnectInterval??X.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let o=this.getConfig(),n={...o.connection||{},...e},s={...o,connection:n};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 o=this.getConfig(),n={...o.modelscope||{},...e},s={...o,modelscope:n};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 o=this.getConfig(),n={...o.webUI||{},...e},s={...o,webUI:n};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 W from"fs";import ze from"path";import O from"chalk";import{createConsola as _e}from"consola";function He(r){let e=r.getFullYear(),o=String(r.getMonth()+1).padStart(2,"0"),t=String(r.getDate()).padStart(2,"0"),n=String(r.getHours()).padStart(2,"0"),s=String(r.getMinutes()).padStart(2,"0"),c=String(r.getSeconds()).padStart(2,"0");return`${e}-${o}-${t} ${n}:${s}:${c}`}var k,I,A=D(()=>{"use strict";g(He,"formatDateTime");k=class{static{g(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=_e({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:g(o=>{let t={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},n={info:O.blue,success:O.green,warn:O.yellow,error:O.red,debug:O.gray,log:g(y=>y,"log")},s=t[o.type]||o.type.toUpperCase(),c=n[o.type]||(y=>y),a=He(new Date),m=c(`[${s}]`),u=`[${a}] ${m} ${o.args.join(" ")}`;if(!e)try{console.error(u)}catch(y){if(y instanceof Error&&y.message?.includes("EPIPE"))return;throw y}},"log")}])}initLogFile(e){this.logFilePath=ze.join(e,"xiaozhi.log"),W.existsSync(this.logFilePath)||W.writeFileSync(this.logFilePath,""),this.writeStream=W.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(e,o,...t){if(this.writeStream){let s=`[${new Date().toISOString()}] [${e.toUpperCase()}] ${o}`,c=t.length>0?`${s} ${t.map(a=>typeof a=="object"?JSON.stringify(a):String(a)).join(" ")}`:s;this.writeStream.write(`${c}
2
- `)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=W.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"}):!e&&this.writeStream&&(this.writeStream.end(),this.writeStream=null)}info(e,...o){this.consolaInstance.info(e,...o),this.logToFile("info",e,...o)}success(e,...o){this.consolaInstance.success(e,...o),this.logToFile("success",e,...o)}warn(e,...o){this.consolaInstance.warn(e,...o),this.logToFile("warn",e,...o)}error(e,...o){this.consolaInstance.error(e,...o),this.logToFile("error",e,...o)}debug(e,...o){this.consolaInstance.debug(e,...o),this.logToFile("debug",e,...o)}log(e,...o){this.consolaInstance.log(e,...o),this.logToFile("log",e,...o)}withTag(e){return this}close(){this.writeStream&&(this.writeStream.end(),this.writeStream=null)}},I=new k});import{spawn as Fe}from"child_process";import x from"process";import N from"ws";var fe,d,G,de=D(()=>{"use strict";E();A();fe=g(()=>x.env.NODE_ENV==="test"||x.env.VITEST==="true","isTestEnvironment"),d=I.withTag("MULTI_MCP_PIPE");x.env.XIAOZHI_DAEMON==="true"&&x.env.XIAOZHI_CONFIG_DIR&&(I.initLogFile(x.env.XIAOZHI_CONFIG_DIR),I.enableFileLogging(!0));G=class{static{g(this,"MultiEndpointMCPPipe")}mcpScript;endpoints;shouldReconnect;shutdownResolve;connectionConfig;constructor(e,o){this.mcpScript=e,this.endpoints=new Map,this.shouldReconnect=!0,d.info(o.length===1?`\u521D\u59CB\u5316\u5355\u7AEF\u70B9\u8FDE\u63A5: ${o[0]}`:`\u521D\u59CB\u5316\u591A\u7AEF\u70B9\u8FDE\u63A5\uFF08${o.length} \u4E2A\u7AEF\u70B9\uFF09`);for(let t of o)this.endpoints.set(t,{url:t,websocket:null,isConnected:!1,reconnectAttempt:0,maxReconnectAttempts:5,process:null,stdoutBuffer:""});try{this.connectionConfig=l.getConnectionConfig(),d.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(t){this.connectionConfig={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},d.warn(`\u65E0\u6CD5\u83B7\u53D6\u8FDE\u63A5\u914D\u7F6E\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C: ${t instanceof Error?t.message:String(t)}`)}}async start(){return await this.connectToAllEndpoints(),this.reportStatusToWebUI(),new Promise(e=>{this.shutdownResolve=e})}async connectToAllEndpoints(){let e=[];for(let[o,t]of this.endpoints)e.push(this.connectToEndpoint(o));await Promise.allSettled(e)}async connectToEndpoint(e){let o=this.endpoints.get(e);if(!o||o.isConnected)return;this.startMCPProcessForEndpoint(e),d.info(`\u6B63\u5728\u8FDE\u63A5\u5230 WebSocket \u670D\u52A1\u5668: ${e}`);let t=new N(e);o.websocket=t,t.on("open",()=>{d.info(`\u6210\u529F\u8FDE\u63A5\u5230 WebSocket \u670D\u52A1\u5668: ${e}`),o.isConnected=!0,o.reconnectAttempt=0,o.reconnectTimer&&(clearTimeout(o.reconnectTimer),o.reconnectTimer=void 0),this.reportStatusToWebUI(),this.startHeartbeat(e)}),t.on("message",n=>{let s=n.toString();d.info(`<< [${e}] WebSocket\u6536\u5230\u6D88\u606F: ${s}`);try{let c=JSON.parse(s);(c.method==="notifications/initialized"||c.method==="tools/list"&&c.id||c?.result?.tools)&&setTimeout(()=>{this.reportStatusToWebUI()},1e3)}catch{}o.process?.stdin&&!o.process.stdin.destroyed&&o.process.stdin.write(`${s}
3
- `)}),t.on("close",(n,s)=>{d.error(`[${e}] WebSocket \u8FDE\u63A5\u5DF2\u5173\u95ED: ${n} ${s}`),o.isConnected=!1,o.websocket=null,this.stopHeartbeat(e),this.reportStatusToWebUI(),this.shouldReconnect&&(n===4004?o.reconnectAttempt<o.maxReconnectAttempts?(d.warn(`[${e}] \u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF(4004)\uFF0C\u5C06\u8FDB\u884C\u7B2C ${o.reconnectAttempt+1} \u6B21\u91CD\u8FDE\u5C1D\u8BD5\uFF08\u6700\u591A ${o.maxReconnectAttempts} \u6B21\uFF09`),this.scheduleReconnect(e)):d.error(`[${e}] \u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF(4004)\uFF0C\u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8FDE\u6B21\u6570(${o.maxReconnectAttempts})\uFF0C\u505C\u6B62\u91CD\u8FDE`):this.scheduleReconnect(e))}),t.on("error",n=>{d.error(`[${e}] WebSocket \u9519\u8BEF: ${n.message}`),o.isConnected=!1,this.stopHeartbeat(e)}),t.on("pong",()=>{o.heartbeatTimeoutTimer&&(clearTimeout(o.heartbeatTimeoutTimer),o.heartbeatTimeoutTimer=void 0)})}scheduleReconnect(e){let o=this.endpoints.get(e);if(!o||!this.shouldReconnect)return;o.reconnectTimer&&clearTimeout(o.reconnectTimer),o.reconnectAttempt++;let t=this.connectionConfig.reconnectInterval,s=Math.min(t*2**(o.reconnectAttempt-1),6e4);d.info(`[${e}] \u8BA1\u5212\u5728 ${(s/1e3).toFixed(2)} \u79D2\u540E\u8FDB\u884C\u7B2C ${o.reconnectAttempt} \u6B21\u91CD\u8FDE\u5C1D\u8BD5...`),o.reconnectTimer=setTimeout(async()=>{this.shouldReconnect&&(await this.cleanupEndpointResources(e),(!o.process||o.process.killed)&&d.info(`[${e}] MCP \u8FDB\u7A0B\u672A\u8FD0\u884C\uFF0C\u5C06\u5728\u91CD\u8FDE\u65F6\u542F\u52A8...`),this.connectToEndpoint(e))},s)}startMCPProcessForEndpoint(e){let o=this.endpoints.get(e);if(!o){d.error(`\u7AEF\u70B9\u4E0D\u5B58\u5728: ${e}`);return}if(o.process){d.info(`[${e}] MCP \u8FDB\u7A0B\u5DF2\u5728\u8FD0\u884C`);return}d.info(`[${e}] \u6B63\u5728\u542F\u52A8 MCP \u8FDB\u7A0B`),o.process=Fe("node",[this.mcpScript],{stdio:["pipe","pipe","pipe"]}),o.process.stdout?.on("data",t=>{o.stdoutBuffer+=t.toString();let n=o.stdoutBuffer.split(`
4
- `);o.stdoutBuffer=n.pop()||"";for(let s of n)s.trim()&&this.handleMCPMessage(e,s)}),o.process.stderr?.on("data",t=>{if(x.env.XIAOZHI_DAEMON!=="true")try{x.stderr.write(t)}catch{}}),o.process.on("exit",(t,n)=>{d.warn(`[${e}] MCP \u8FDB\u7A0B\u5DF2\u9000\u51FA\uFF0C\u9000\u51FA\u7801: ${t}, \u4FE1\u53F7: ${n}`),o.process=null,this.shouldReconnect&&n!=="SIGTERM"&&n!=="SIGKILL"&&d.info(`[${e}] MCP \u8FDB\u7A0B\u610F\u5916\u9000\u51FA\uFF0C\u5C06\u5728\u4E0B\u6B21\u91CD\u8FDE\u65F6\u5C1D\u8BD5\u91CD\u542F`)}),o.process.on("error",t=>{d.error(`[${e}] \u8FDB\u7A0B\u9519\u8BEF: ${t.message}`),o.process=null,this.shouldReconnect&&d.info(`[${e}] MCP \u8FDB\u7A0B\u53D1\u751F\u9519\u8BEF\uFF0C\u5C06\u5728\u4E0B\u6B21\u91CD\u8FDE\u65F6\u5C1D\u8BD5\u91CD\u542F`)})}handleMCPMessage(e,o){d.info(`>> [${e}] mcpServerProxy\u53D1\u9001\u6D88\u606F\u957F\u5EA6: ${o.length} \u5B57\u8282`),d.info(`>> [${e}] mcpServerProxy\u53D1\u9001\u6D88\u606F: ${o.substring(0,500)}...`),this.sendToEndpoint(e,o)}sendToEndpoint(e,o){let t=this.endpoints.get(e);if(!t||!t.websocket||t.websocket.readyState!==N.OPEN){d.warn(`[${e}] \u7AEF\u70B9\u4E0D\u53EF\u7528\uFF0C\u6D88\u606F\u65E0\u6CD5\u53D1\u9001`);return}try{t.websocket.send(`${o}
5
- `),d.info(`>> [${e}] \u6210\u529F\u53D1\u9001\u6D88\u606F\u5230 WebSocket`)}catch(n){d.error(`>> [${e}] \u53D1\u9001\u6D88\u606F\u5230 WebSocket \u5931\u8D25: ${n}`)}}startHeartbeat(e){let o=this.endpoints.get(e);o&&(this.stopHeartbeat(e),o.heartbeatTimer=setInterval(()=>{o.websocket&&o.websocket.readyState===N.OPEN&&(o.websocket.ping(),o.heartbeatTimeoutTimer=setTimeout(()=>{d.warn(`[${e}] \u5FC3\u8DF3\u8D85\u65F6\uFF0C\u65AD\u5F00\u8FDE\u63A5`),o.websocket?.close()},this.connectionConfig.heartbeatTimeout),this.reportStatusToWebUI())},this.connectionConfig.heartbeatInterval))}stopHeartbeat(e){let o=this.endpoints.get(e);o&&(o.heartbeatTimer&&(clearInterval(o.heartbeatTimer),o.heartbeatTimer=void 0),o.heartbeatTimeoutTimer&&(clearTimeout(o.heartbeatTimeoutTimer),o.heartbeatTimeoutTimer=void 0))}async cleanupEndpointResources(e){let o=this.endpoints.get(e);if(o){if(d.debug(`[${e}] \u6E05\u7406\u7AEF\u70B9\u8D44\u6E90...`),this.stopHeartbeat(e),o.reconnectTimer&&(clearTimeout(o.reconnectTimer),o.reconnectTimer=void 0),o.websocket){try{o.websocket.readyState===N.OPEN&&o.websocket.close()}catch(t){d.debug(`[${e}] \u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${t}`)}o.websocket=null}if(o.process&&!o.process.killed){try{d.debug(`[${e}] \u7EC8\u6B62 MCP \u8FDB\u7A0B...`),o.process.kill("SIGTERM"),await new Promise(t=>{let n=setTimeout(()=>{o.process&&!o.process.killed&&(d.warn(`[${e}] MCP \u8FDB\u7A0B\u672A\u80FD\u6B63\u5E38\u9000\u51FA\uFF0C\u5F3A\u5236\u7EC8\u6B62`),o.process.kill("SIGKILL")),t()},2e3);o.process?.on("exit",()=>{clearTimeout(n),t()})})}catch(t){d.warn(`[${e}] \u7EC8\u6B62 MCP \u8FDB\u7A0B\u65F6\u51FA\u9519: ${t}`)}o.process=null}o.stdoutBuffer="",o.isConnected=!1,d.debug(`[${e}] \u7AEF\u70B9\u8D44\u6E90\u6E05\u7406\u5B8C\u6210`)}}cleanup(){for(let e of this.endpoints.keys())this.stopHeartbeat(e);for(let[e,o]of this.endpoints){if(o.reconnectTimer&&(clearTimeout(o.reconnectTimer),o.reconnectTimer=void 0),o.stdoutBuffer="",o.process){d.info(`[${e}] \u6B63\u5728\u7EC8\u6B62 MCP \u8FDB\u7A0B`);try{o.process.kill("SIGTERM"),setTimeout(()=>{o.process&&!o.process.killed&&o.process.kill("SIGKILL")},5e3)}catch(t){d.error(`[${e}] \u7EC8\u6B62\u8FDB\u7A0B\u65F6\u51FA\u9519: ${t instanceof Error?t.message:String(t)}`)}o.process=null}if(o.websocket){try{o.websocket.close()}catch(t){d.warn(`[${e}] \u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${t}`)}o.websocket=null}}}shutdown(){d.info("\u6B63\u5728\u5173\u95ED Multi-Endpoint MCP Pipe..."),this.shouldReconnect=!1;for(let e of this.endpoints.values())e.isConnected=!1;this.reportStatusToWebUI(),this.cleanup(),this.shutdownResolve&&this.shutdownResolve(),fe()||setTimeout(()=>{x.exit(0)},100)}async reportStatusToWebUI(){if(!fe())try{let e=l.getWebUIPort(),o=new N(`ws://localhost:${e}`);o.on("open",()=>{let t=[];for(let[s,c]of this.endpoints)t.push({url:s,connected:c.isConnected});let n={type:"clientStatus",data:{status:this.hasAnyConnection()?"connected":"disconnected",mcpEndpoints:t,activeMCPServers:[],lastHeartbeat:Date.now()}};o.send(JSON.stringify(n)),d.debug("\u5DF2\u5411 Web UI \u62A5\u544A\u72B6\u6001"),setTimeout(()=>{o.close()},1e3)}),o.on("error",t=>{d.debug(`Web UI \u8FDE\u63A5\u5931\u8D25\uFF08\u53EF\u80FD\u672A\u8FD0\u884C\uFF09: ${t.message}`)})}catch(e){d.debug(`\u5411 Web UI \u62A5\u544A\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}hasAnyConnection(){for(let e of this.endpoints.values())if(e.isConnected)return!0;return!1}}});var he={};xe(he,{MCPServer:()=>K});import{spawn as De}from"child_process";import{randomUUID as We}from"crypto";import{EventEmitter as Ge}from"events";import L from"fs";import Le from"os";import w from"path";import{fileURLToPath as me}from"url";import V from"express";var Je,z,h,_,K,ue=D(()=>{"use strict";E();A();de();Je=me(import.meta.url),z=w.dirname(Je),h=I.withTag("mcp-server"),_="mcpServerProxy.js",K=class extends Ge{static{g(this,"MCPServer")}app;server=null;clients=new Map;mcpProxy=null;mcpClient=null;mcpProxyPath=null;port;constructor(e=3e3){super(),this.port=e,this.app=V(),this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){this.app.use(V.json()),this.app.use(V.urlencoded({extended:!0})),this.app.use((e,o,t)=>{o.header("Access-Control-Allow-Origin","*"),o.header("Access-Control-Allow-Methods","GET, POST, OPTIONS"),o.header("Access-Control-Allow-Headers","Content-Type, Accept"),o.header("Cache-Control","no-cache"),t()})}setupRoutes(){this.app.get("/sse",(e,o)=>{let t=Date.now().toString(),n=We();o.setHeader("Content-Type","text/event-stream"),o.setHeader("Cache-Control","no-cache, no-transform"),o.setHeader("Connection","keep-alive"),o.setHeader("X-Accel-Buffering","no"),this.clients.set(n,{id:t,sessionId:n,response:o}),h.info(`MCP\u5BA2\u6237\u7AEF\u5DF2\u8FDE\u63A5: ${t} (\u4F1A\u8BDD: ${n})`),o.write(`event: endpoint
1
+ var se=Object.defineProperty;var p=(r,e)=>se(r,"name",{value:e,configurable:!0});var R=(r,e)=>()=>(r&&(e=r(r=0)),e);var Te=(r,e)=>{for(var t in e)se(r,t,{get:e[t],enumerable:!0})};function je(r){if(!r||typeof r!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u6709\u6548\u7684\u5BF9\u8C61");if("command"in r&&typeof r.command=="string")return"stdio";if("type"in r&&r.type==="sse")return"sse";if("type"in r&&r.type==="streamable-http"||"url"in r&&typeof r.url=="string")return"streamable-http";throw new Error("\u65E0\u6CD5\u8BC6\u522B\u7684 MCP \u670D\u52A1\u914D\u7F6E\u7C7B\u578B\u3002\u914D\u7F6E\u5FC5\u987B\u5305\u542B command \u5B57\u6BB5\uFF08stdio\uFF09\u3001type: 'sse' \u5B57\u6BB5\uFF08sse\uFF09\u6216 url \u5B57\u6BB5\uFF08streamable-http\uFF09")}function X(r,e){if(!e||typeof e!="object")return{valid:!1,error:`\u670D\u52A1 "${r}" \u7684\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61`};try{switch(je(e)){case"stdio":if(!e.command||typeof e.command!="string")return{valid:!1,error:`\u670D\u52A1 "${r}" \u7F3A\u5C11\u5FC5\u9700\u7684 command \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(!Array.isArray(e.args))return{valid:!1,error:`\u670D\u52A1 "${r}" \u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4`};if(e.env&&typeof e.env!="object")return{valid:!1,error:`\u670D\u52A1 "${r}" \u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;case"sse":if(e.type!=="sse")return{valid:!1,error:`\u670D\u52A1 "${r}" \u7684 type \u5B57\u6BB5\u5FC5\u987B\u662F "sse"`};if(!e.url||typeof e.url!="string")return{valid:!1,error:`\u670D\u52A1 "${r}" \u7F3A\u5C11\u5FC5\u9700\u7684 url \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};break;case"streamable-http":if(!e.url||typeof e.url!="string")return{valid:!1,error:`\u670D\u52A1 "${r}" \u7F3A\u5C11\u5FC5\u9700\u7684 url \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(e.type&&e.type!=="streamable-http")return{valid:!1,error:`\u670D\u52A1 "${r}" \u7684 type \u5B57\u6BB5\u5982\u679C\u5B58\u5728\uFF0C\u5FC5\u987B\u662F "streamable-http"`};break;default:return{valid:!1,error:`\u670D\u52A1 "${r}" \u7684\u914D\u7F6E\u7C7B\u578B\u65E0\u6CD5\u8BC6\u522B`}}return{valid:!0}}catch(t){return{valid:!1,error:`\u670D\u52A1 "${r}" \u7684\u914D\u7F6E\u65E0\u6548: ${t instanceof Error?t.message:"\u672A\u77E5\u9519\u8BEF"}`}}}var ie=R(()=>{"use strict";p(je,"getMcpServerCommunicationType");p(X,"validateMcpServerConfig")});import{copyFileSync as Re,existsSync as B,readFileSync as Oe,writeFileSync as ke}from"fs";import{dirname as Ae,resolve as O}from"path";import{fileURLToPath as We}from"url";import*as H from"comment-json";import Z from"json5";import*as ce from"json5-writer";var _e,V,q,a,M=R(()=>{"use strict";ie();_e=Ae(We(import.meta.url)),V={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},q=class r{static{p(this,"ConfigManager")}static instance;defaultConfigPath;config=null;currentConfigPath=null;json5Writer=null;constructor(){this.defaultConfigPath=O(_e,"xiaozhi.config.default.json")}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let o of t){let n=O(e,o);if(B(n))return n}return O(e,"xiaozhi.config.json")}getConfigFileFormat(e){return e.endsWith(".json5")?"json5":e.endsWith(".jsonc")?"jsonc":"json"}static getInstance(){return r.instance||(r.instance=new r),r.instance}configExists(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let o of t){let n=O(e,o);if(B(n))return!0}return!1}initConfig(e="json"){if(!B(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\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let t=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),o=`xiaozhi.config.${e}`,n=O(t,o);Re(this.defaultConfigPath,n),this.config=null,this.json5Writer=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let e=this.getConfigFilePath();this.currentConfigPath=e;let t=this.getConfigFileFormat(e),o=Oe(e,"utf8"),n;switch(t){case"json5":n=Z.parse(o),this.json5Writer=ce.load(o);break;case"jsonc":n=H.parse(o);break;default:n=JSON.parse(o);break}return this.validateConfig(n),n}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===void 0||t.mcpEndpoint===null)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(typeof t.mcpEndpoint!="string")if(Array.isArray(t.mcpEndpoint)){if(t.mcpEndpoint.length===0)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E0D\u80FD\u4E3A\u7A7A");for(let o of t.mcpEndpoint)if(typeof o!="string"||o.trim()==="")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5B57\u7B26\u4E32\u6570\u7EC4");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,n]of Object.entries(t.mcpServers)){if(!n||typeof n!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o} \u65E0\u6548`);let s=X(o,n);if(!s.valid)throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A${s.error}`)}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMutableConfig(){return this.config||(this.config=this.loadConfig()),this.config}getMcpEndpoint(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?e.mcpEndpoint[0]||"":e.mcpEndpoint}getMcpEndpoints(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?[...e.mcpEndpoint]:e.mcpEndpoint?[e.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(Array.isArray(e)){if(e.length===0)throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E0D\u80FD\u4E3A\u7A7A");for(let o of e)if(!o||typeof o!="string")throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig();t.mcpEndpoint=e,this.saveConfig(t)}addMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig(),o=this.getMcpEndpoints();if(o.includes(e))throw new Error(`MCP \u7AEF\u70B9 ${e} \u5DF2\u5B58\u5728`);let n=[...o,e];t.mcpEndpoint=n,this.saveConfig(t)}removeMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig(),o=this.getMcpEndpoints();if(o.indexOf(e)===-1)throw new Error(`MCP \u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728`);if(o.length===1)throw new Error("\u4E0D\u80FD\u5220\u9664\u6700\u540E\u4E00\u4E2A MCP \u7AEF\u70B9");let s=o.filter(c=>c!==e);t.mcpEndpoint=s,this.saveConfig(t)}updateMcpServer(e,t){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let o=X(e,t);if(!o.valid)throw new Error(o.error||"\u670D\u52A1\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");let n=this.getMutableConfig();n.mcpServers[e]=t,this.saveConfig(n)}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 n={...t,mcpServers:o};this.saveConfig(n)}updateServerToolsConfig(e,t){let o=this.getMutableConfig();o.mcpServerConfig||(o.mcpServerConfig={}),Object.keys(t).length===0?delete o.mcpServerConfig[e]:o.mcpServerConfig[e]={tools:t},this.saveConfig(o)}removeServerToolsConfig(e){let o={...this.getConfig()};o.mcpServerConfig&&(delete o.mcpServerConfig[e],this.saveConfig(o))}setToolEnabled(e,t,o,n){let s=this.getMutableConfig();s.mcpServerConfig||(s.mcpServerConfig={}),s.mcpServerConfig[e]||(s.mcpServerConfig[e]={tools:{}}),s.mcpServerConfig[e].tools[t]={...s.mcpServerConfig[e].tools[t],enable:o,...n&&{description:n}},this.saveConfig(s)}saveConfig(e){try{this.validateConfig(e);let t;this.currentConfigPath?t=this.currentConfigPath:(t=this.getConfigFilePath(),this.currentConfigPath=t);let o=this.getConfigFileFormat(t),n;switch(o){case"json5":try{this.json5Writer?(this.json5Writer.write(e),n=this.json5Writer.toSource()):(console.warn("\u6CA1\u6709 json5Writer \u5B9E\u4F8B\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON5 \u683C\u5F0F"),n=Z.stringify(e,null,2))}catch(s){console.warn("\u4F7F\u7528 json5-writer \u4FDD\u5B58\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON5 \u683C\u5F0F:",s),n=Z.stringify(e,null,2)}break;case"jsonc":try{n=H.stringify(e,null,2)}catch(s){console.warn("\u4F7F\u7528 comment-json \u4FDD\u5B58\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON \u683C\u5F0F:",s),n=JSON.stringify(e,null,2)}break;default:n=JSON.stringify(e,null,2);break}ke(t,n,"utf8"),this.config=e,logger.info("saveConfig",this.config),this.notifyConfigUpdate(e)}catch(t){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}reloadConfig(){this.config=null,this.currentConfigPath=null,this.json5Writer=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let t=this.getConfig().connection||{};return{heartbeatInterval:t.heartbeatInterval??V.heartbeatInterval,heartbeatTimeout:t.heartbeatTimeout??V.heartbeatTimeout,reconnectInterval:t.reconnectInterval??V.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let t=this.getMutableConfig();t.connection||(t.connection={}),Object.assign(t.connection,e),this.saveConfig(t)}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.getMutableConfig();t.modelscope||(t.modelscope={}),Object.assign(t.modelscope,e),this.saveConfig(t)}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}notifyConfigUpdate(e){try{let t=global.__webServer;t&&typeof t.broadcastConfigUpdate=="function"&&(t.broadcastConfigUpdate(e),console.log("\u5DF2\u901A\u8FC7 WebSocket \u5E7F\u64AD\u914D\u7F6E\u66F4\u65B0"))}catch(t){console.warn("\u901A\u77E5 Web \u754C\u9762\u914D\u7F6E\u66F4\u65B0\u5931\u8D25:",t instanceof Error?t.message:String(t))}}updateWebUIConfig(e){let t=this.getMutableConfig();t.webUI||(t.webUI={}),Object.assign(t.webUI,e),this.saveConfig(t)}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})}},a=q.getInstance()});import L from"fs";import De from"path";import k from"chalk";import{createConsola as He}from"consola";function Le(r){let e=r.getFullYear(),t=String(r.getMonth()+1).padStart(2,"0"),o=String(r.getDate()).padStart(2,"0"),n=String(r.getHours()).padStart(2,"0"),s=String(r.getMinutes()).padStart(2,"0"),c=String(r.getSeconds()).padStart(2,"0");return`${e}-${t}-${o} ${n}:${s}:${c}`}var A,I,W=R(()=>{"use strict";p(Le,"formatDateTime");A=class{static{p(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=He({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:p(t=>{let o={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},n={info:k.blue,success:k.green,warn:k.yellow,error:k.red,debug:k.gray,log:p(y=>y,"log")},s=o[t.type]||t.type.toUpperCase(),c=n[t.type]||(y=>y),l=Le(new Date),u=c(`[${s}]`),h=`[${l}] ${u} ${t.args.join(" ")}`;if(!e)try{console.error(h)}catch(y){if(y instanceof Error&&y.message?.includes("EPIPE"))return;throw y}},"log")}])}initLogFile(e){this.logFilePath=De.join(e,"xiaozhi.log"),L.existsSync(this.logFilePath)||L.writeFileSync(this.logFilePath,""),this.writeStream=L.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(e,t,...o){if(this.writeStream){let s=`[${new Date().toISOString()}] [${e.toUpperCase()}] ${t}`,c=o.length>0?`${s} ${o.map(l=>typeof l=="object"?JSON.stringify(l):String(l)).join(" ")}`:s;this.writeStream.write(`${c}
2
+ `)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=L.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)}},I=new A});import{spawn as Ge}from"child_process";import x from"process";import _ from"ws";var he,d,G,ye=R(()=>{"use strict";M();W();he=p(()=>x.env.NODE_ENV==="test"||x.env.VITEST==="true","isTestEnvironment"),d=I.withTag("MULTI_MCP_PIPE");x.env.XIAOZHI_DAEMON==="true"&&x.env.XIAOZHI_CONFIG_DIR&&(I.initLogFile(x.env.XIAOZHI_CONFIG_DIR),I.enableFileLogging(!0));G=class{static{p(this,"MultiEndpointMCPPipe")}mcpScript;endpoints;shouldReconnect;shutdownResolve;connectionConfig;constructor(e,t){this.mcpScript=e,this.endpoints=new Map,this.shouldReconnect=!0,d.info(t.length===1?`\u521D\u59CB\u5316\u5355\u7AEF\u70B9\u8FDE\u63A5: ${t[0]}`:`\u521D\u59CB\u5316\u591A\u7AEF\u70B9\u8FDE\u63A5\uFF08${t.length} \u4E2A\u7AEF\u70B9\uFF09`);for(let o of t)this.endpoints.set(o,{url:o,websocket:null,isConnected:!1,reconnectAttempt:0,maxReconnectAttempts:5,process:null,stdoutBuffer:""});try{this.connectionConfig=a.getConnectionConfig(),d.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},d.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 await this.connectToAllEndpoints(),this.reportStatusToWebUI(),new Promise(e=>{this.shutdownResolve=e})}async connectToAllEndpoints(){let e=[];for(let[t,o]of this.endpoints)e.push(this.connectToEndpoint(t));await Promise.allSettled(e)}async connectToEndpoint(e){let t=this.endpoints.get(e);if(!t||t.isConnected)return;this.startMCPProcessForEndpoint(e),d.info(`\u6B63\u5728\u8FDE\u63A5\u5230 WebSocket \u670D\u52A1\u5668: ${e}`);let o=new _(e);t.websocket=o,o.on("open",()=>{d.info(`\u6210\u529F\u8FDE\u63A5\u5230 WebSocket \u670D\u52A1\u5668: ${e}`),t.isConnected=!0,t.reconnectAttempt=0,t.reconnectTimer&&(clearTimeout(t.reconnectTimer),t.reconnectTimer=void 0),this.reportStatusToWebUI(),this.startHeartbeat(e)}),o.on("message",n=>{let s=n.toString();d.info(`<< [${e}] WebSocket\u6536\u5230\u6D88\u606F: ${s}`);try{let c=JSON.parse(s);(c.method==="notifications/initialized"||c.method==="tools/list"&&c.id||c?.result?.tools)&&setTimeout(()=>{this.reportStatusToWebUI()},1e3)}catch{}t.process?.stdin&&!t.process.stdin.destroyed&&t.process.stdin.write(`${s}
3
+ `)}),o.on("close",(n,s)=>{d.error(`[${e}] WebSocket \u8FDE\u63A5\u5DF2\u5173\u95ED: ${n} ${s}`),t.isConnected=!1,t.websocket=null,this.stopHeartbeat(e),this.reportStatusToWebUI(),this.shouldReconnect&&(n===4004?t.reconnectAttempt<t.maxReconnectAttempts?(d.warn(`[${e}] \u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF(4004)\uFF0C\u5C06\u8FDB\u884C\u7B2C ${t.reconnectAttempt+1} \u6B21\u91CD\u8FDE\u5C1D\u8BD5\uFF08\u6700\u591A ${t.maxReconnectAttempts} \u6B21\uFF09`),this.scheduleReconnect(e)):d.error(`[${e}] \u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF(4004)\uFF0C\u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8FDE\u6B21\u6570(${t.maxReconnectAttempts})\uFF0C\u505C\u6B62\u91CD\u8FDE`):this.scheduleReconnect(e))}),o.on("error",n=>{d.error(`[${e}] WebSocket \u9519\u8BEF: ${n.message}`),t.isConnected=!1,this.stopHeartbeat(e)}),o.on("pong",()=>{t.heartbeatTimeoutTimer&&(clearTimeout(t.heartbeatTimeoutTimer),t.heartbeatTimeoutTimer=void 0)})}scheduleReconnect(e){let t=this.endpoints.get(e);if(!t||!this.shouldReconnect)return;t.reconnectTimer&&clearTimeout(t.reconnectTimer),t.reconnectAttempt++;let o=this.connectionConfig.reconnectInterval,s=Math.min(o*2**(t.reconnectAttempt-1),6e4);d.info(`[${e}] \u8BA1\u5212\u5728 ${(s/1e3).toFixed(2)} \u79D2\u540E\u8FDB\u884C\u7B2C ${t.reconnectAttempt} \u6B21\u91CD\u8FDE\u5C1D\u8BD5...`),t.reconnectTimer=setTimeout(async()=>{this.shouldReconnect&&(await this.cleanupEndpointResources(e),(!t.process||t.process.killed)&&d.info(`[${e}] MCP \u8FDB\u7A0B\u672A\u8FD0\u884C\uFF0C\u5C06\u5728\u91CD\u8FDE\u65F6\u542F\u52A8...`),this.connectToEndpoint(e))},s)}startMCPProcessForEndpoint(e){let t=this.endpoints.get(e);if(!t){d.error(`\u7AEF\u70B9\u4E0D\u5B58\u5728: ${e}`);return}if(t.process){d.info(`[${e}] MCP \u8FDB\u7A0B\u5DF2\u5728\u8FD0\u884C`);return}d.info(`[${e}] \u6B63\u5728\u542F\u52A8 MCP \u8FDB\u7A0B`),t.process=Ge("node",[this.mcpScript],{stdio:["pipe","pipe","pipe"]}),t.process.stdout?.on("data",o=>{t.stdoutBuffer+=o.toString();let n=t.stdoutBuffer.split(`
4
+ `);t.stdoutBuffer=n.pop()||"";for(let s of n)s.trim()&&this.handleMCPMessage(e,s)}),t.process.stderr?.on("data",o=>{if(x.env.XIAOZHI_DAEMON!=="true")try{x.stderr.write(o)}catch{}}),t.process.on("exit",(o,n)=>{d.warn(`[${e}] MCP \u8FDB\u7A0B\u5DF2\u9000\u51FA\uFF0C\u9000\u51FA\u7801: ${o}, \u4FE1\u53F7: ${n}`),t.process=null,this.shouldReconnect&&n!=="SIGTERM"&&n!=="SIGKILL"&&d.info(`[${e}] MCP \u8FDB\u7A0B\u610F\u5916\u9000\u51FA\uFF0C\u5C06\u5728\u4E0B\u6B21\u91CD\u8FDE\u65F6\u5C1D\u8BD5\u91CD\u542F`)}),t.process.on("error",o=>{d.error(`[${e}] \u8FDB\u7A0B\u9519\u8BEF: ${o.message}`),t.process=null,this.shouldReconnect&&d.info(`[${e}] MCP \u8FDB\u7A0B\u53D1\u751F\u9519\u8BEF\uFF0C\u5C06\u5728\u4E0B\u6B21\u91CD\u8FDE\u65F6\u5C1D\u8BD5\u91CD\u542F`)})}handleMCPMessage(e,t){d.info(`>> [${e}] mcpServerProxy\u53D1\u9001\u6D88\u606F\u957F\u5EA6: ${t.length} \u5B57\u8282`),d.info(`>> [${e}] mcpServerProxy\u53D1\u9001\u6D88\u606F: ${t.substring(0,500)}...`),this.sendToEndpoint(e,t)}sendToEndpoint(e,t){let o=this.endpoints.get(e);if(!o||!o.websocket||o.websocket.readyState!==_.OPEN){d.warn(`[${e}] \u7AEF\u70B9\u4E0D\u53EF\u7528\uFF0C\u6D88\u606F\u65E0\u6CD5\u53D1\u9001`);return}try{o.websocket.send(`${t}
5
+ `),d.info(`>> [${e}] \u6210\u529F\u53D1\u9001\u6D88\u606F\u5230 WebSocket`)}catch(n){d.error(`>> [${e}] \u53D1\u9001\u6D88\u606F\u5230 WebSocket \u5931\u8D25: ${n}`)}}startHeartbeat(e){let t=this.endpoints.get(e);t&&(this.stopHeartbeat(e),t.heartbeatTimer=setInterval(()=>{t.websocket&&t.websocket.readyState===_.OPEN&&(t.websocket.ping(),t.heartbeatTimeoutTimer=setTimeout(()=>{d.warn(`[${e}] \u5FC3\u8DF3\u8D85\u65F6\uFF0C\u65AD\u5F00\u8FDE\u63A5`),t.websocket?.close()},this.connectionConfig.heartbeatTimeout),this.reportStatusToWebUI())},this.connectionConfig.heartbeatInterval))}stopHeartbeat(e){let t=this.endpoints.get(e);t&&(t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=void 0),t.heartbeatTimeoutTimer&&(clearTimeout(t.heartbeatTimeoutTimer),t.heartbeatTimeoutTimer=void 0))}async cleanupEndpointResources(e){let t=this.endpoints.get(e);if(t){if(d.debug(`[${e}] \u6E05\u7406\u7AEF\u70B9\u8D44\u6E90...`),this.stopHeartbeat(e),t.reconnectTimer&&(clearTimeout(t.reconnectTimer),t.reconnectTimer=void 0),t.websocket){try{t.websocket.readyState===_.OPEN&&t.websocket.close()}catch(o){d.debug(`[${e}] \u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${o}`)}t.websocket=null}if(t.process&&!t.process.killed){try{d.debug(`[${e}] \u7EC8\u6B62 MCP \u8FDB\u7A0B...`),t.process.kill("SIGTERM"),await new Promise(o=>{let n=setTimeout(()=>{t.process&&!t.process.killed&&(d.warn(`[${e}] MCP \u8FDB\u7A0B\u672A\u80FD\u6B63\u5E38\u9000\u51FA\uFF0C\u5F3A\u5236\u7EC8\u6B62`),t.process.kill("SIGKILL")),o()},2e3);t.process?.on("exit",()=>{clearTimeout(n),o()})})}catch(o){d.warn(`[${e}] \u7EC8\u6B62 MCP \u8FDB\u7A0B\u65F6\u51FA\u9519: ${o}`)}t.process=null}t.stdoutBuffer="",t.isConnected=!1,d.debug(`[${e}] \u7AEF\u70B9\u8D44\u6E90\u6E05\u7406\u5B8C\u6210`)}}cleanup(){for(let e of this.endpoints.keys())this.stopHeartbeat(e);for(let[e,t]of this.endpoints){if(t.reconnectTimer&&(clearTimeout(t.reconnectTimer),t.reconnectTimer=void 0),t.stdoutBuffer="",t.process){d.info(`[${e}] \u6B63\u5728\u7EC8\u6B62 MCP \u8FDB\u7A0B`);try{t.process.kill("SIGTERM"),setTimeout(()=>{t.process&&!t.process.killed&&t.process.kill("SIGKILL")},5e3)}catch(o){d.error(`[${e}] \u7EC8\u6B62\u8FDB\u7A0B\u65F6\u51FA\u9519: ${o instanceof Error?o.message:String(o)}`)}t.process=null}if(t.websocket){try{t.websocket.close()}catch(o){d.warn(`[${e}] \u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${o}`)}t.websocket=null}}}shutdown(){d.info("\u6B63\u5728\u5173\u95ED Multi-Endpoint MCP Pipe..."),this.shouldReconnect=!1;for(let e of this.endpoints.values())e.isConnected=!1;this.reportStatusToWebUI(),this.cleanup(),this.shutdownResolve&&this.shutdownResolve(),he()||setTimeout(()=>{x.exit(0)},100)}async reportStatusToWebUI(){if(!he())try{let e=a.getWebUIPort(),t=new _(`ws://localhost:${e}`);t.on("open",()=>{let o=[];for(let[s,c]of this.endpoints)o.push({url:s,connected:c.isConnected});let n={type:"clientStatus",data:{status:this.hasAnyConnection()?"connected":"disconnected",mcpEndpoints:o,activeMCPServers:[],lastHeartbeat:Date.now()}};t.send(JSON.stringify(n)),d.debug("\u5DF2\u5411 Web UI \u62A5\u544A\u72B6\u6001"),setTimeout(()=>{t.close()},1e3)}),t.on("error",o=>{d.debug(`Web UI \u8FDE\u63A5\u5931\u8D25\uFF08\u53EF\u80FD\u672A\u8FD0\u884C\uFF09: ${o.message}`)})}catch(e){d.debug(`\u5411 Web UI \u62A5\u544A\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}hasAnyConnection(){for(let e of this.endpoints.values())if(e.isConnected)return!0;return!1}}});var Ce={};Te(Ce,{MCPServer:()=>Q});import{spawn as Je}from"child_process";import{randomUUID as Ue}from"crypto";import{EventEmitter as Xe}from"events";import J from"fs";import Be from"os";import w from"path";import{fileURLToPath as be}from"url";import Y from"express";var Ze,F,m,N,Ve,Q,Se=R(()=>{"use strict";M();W();ye();Ze=be(import.meta.url),F=w.dirname(Ze),m=I.withTag("mcp-server"),N="mcpServerProxy.js",Ve=5,Q=class extends Xe{static{p(this,"MCPServer")}app;server=null;clients=new Map;mcpProxy=null;mcpClient=null;mcpProxyPath=null;port;constructor(e=3e3){super(),this.port=e,this.app=Y(),this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){this.app.use(Y.json()),this.app.use(Y.urlencoded({extended:!0})),this.app.use((e,t,o)=>{t.header("Access-Control-Allow-Origin","*"),t.header("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.header("Access-Control-Allow-Headers","Content-Type, Accept"),t.header("Cache-Control","no-cache"),o()})}setupRoutes(){this.app.get("/sse",(e,t)=>{let o=Date.now().toString(),n=Ue();t.setHeader("Content-Type","text/event-stream"),t.setHeader("Cache-Control","no-cache, no-transform"),t.setHeader("Connection","keep-alive"),t.setHeader("X-Accel-Buffering","no"),this.clients.set(n,{id:o,sessionId:n,response:t}),m.info(`MCP\u5BA2\u6237\u7AEF\u5DF2\u8FDE\u63A5: ${o} (\u4F1A\u8BDD: ${n})`),t.write(`event: endpoint
6
6
  data: /messages?sessionId=${n}
7
7
 
8
- `),e.on("close",()=>{this.clients.delete(n),h.info(`MCP\u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00\u8FDE\u63A5: ${t} (\u4F1A\u8BDD: ${n})`)})}),this.app.post("/messages",async(e,o)=>{try{let t=e.query.sessionId,n=e.body;if(h.info(`\u901A\u8FC7SSE\u4F20\u8F93\u6536\u5230\u6D88\u606F (\u4F1A\u8BDD: ${t}):`,JSON.stringify(n)),!t||!this.clients.has(t)){o.status(400).json({jsonrpc:"2.0",error:{code:-32600,message:"\u65E0\u6548\u6216\u7F3A\u5C11sessionId"},id:n.id});return}if(!this.mcpProxy){o.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP\u4EE3\u7406\u672A\u8FD0\u884C"},id:n.id});return}if(n.id===void 0)h.info(`\u8F6C\u53D1\u901A\u77E5: ${n.method}`),this.mcpProxy.stdin.write(`${JSON.stringify(n)}
9
- `),o.status(202).send();else{let s=await this.forwardToProxy(n),c=this.clients.get(t);c&&this.sendToClient(c,s),o.status(202).send()}}catch(t){h.error("SSE\u6D88\u606F\u9519\u8BEF:",t),o.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:t instanceof Error?t.message:"\u5185\u90E8\u9519\u8BEF"},id:e.body.id})}}),this.app.post("/rpc",async(e,o)=>{try{let t=e.body;if(h.debug("\u6536\u5230RPC\u6D88\u606F:",t),!this.mcpProxy){o.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP\u4EE3\u7406\u672A\u8FD0\u884C"},id:t.id});return}let n=await this.forwardToProxy(t);o.json(n)}catch(t){h.error("RPC\u9519\u8BEF:",t),o.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:t instanceof Error?t.message:"\u5185\u90E8\u9519\u8BEF"},id:e.body.id})}}),this.app.get("/health",(e,o)=>{o.json({status:"ok",mode:"mcp-server",proxy:this.mcpProxy?"running":"stopped",clients:this.clients.size})})}responseBuffer="";pendingRequests=new Map;async forwardToProxy(e){return new Promise((o,t)=>{if(!this.mcpProxy||!this.mcpProxy.stdin||!this.mcpProxy.stdout){t(new Error("MCP\u4EE3\u7406\u4E0D\u53EF\u7528"));return}let n=setTimeout(()=>{this.pendingRequests.delete(e.id),h.warn(`\u6D88\u606F\u8D85\u65F6 id: ${e.id}, \u65B9\u6CD5: ${e.method} - \u5982\u679C\u54CD\u5E94\u5DF2\u901A\u8FC7SSE\u53D1\u9001\uFF0C\u8FD9\u662F\u6B63\u5E38\u7684`),o({jsonrpc:"2.0",id:e.id,result:{_timeout:!0,message:"\u54CD\u5E94\u53EF\u80FD\u5DF2\u901A\u8FC7SSE\u53D1\u9001"}})},3e4);this.pendingRequests.set(e.id,{resolve:o,reject:t,timeoutId:n}),h.info(`\u8F6C\u53D1\u6D88\u606F\u5230\u4EE3\u7406: ${JSON.stringify(e)}`),this.mcpProxy.stdin.write(`${JSON.stringify(e)}
10
- `)})}handleProxyResponse(e){try{this.responseBuffer+=e.toString();let o=this.responseBuffer.split(`
11
- `);this.responseBuffer=o.pop()||"";for(let t of o)if(t.trim())try{let n=JSON.parse(t);if(h.debug(`\u6536\u5230\u4EE3\u7406\u54CD\u5E94: ${t.substring(0,200)}...`),n.id!==void 0&&this.pendingRequests.has(n.id)){let s=this.pendingRequests.get(n.id);clearTimeout(s.timeoutId),this.pendingRequests.delete(n.id),s.resolve(n)}}catch{h.debug(`\u6765\u81EA\u4EE3\u7406\u7684\u975EJSON\u884C: ${t}`)}}catch(o){h.error("\u5904\u7406\u4EE3\u7406\u54CD\u5E94\u65F6\u51FA\u9519:",o)}}sendToClient(e,o){try{let t=`event: message
12
- data: ${JSON.stringify(o)}
8
+ `),e.on("close",()=>{this.clients.delete(n),m.info(`MCP\u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00\u8FDE\u63A5: ${o} (\u4F1A\u8BDD: ${n})`)})}),this.app.post("/messages",async(e,t)=>{try{let o=e.query.sessionId,n=e.body;if(m.info(`\u901A\u8FC7SSE\u4F20\u8F93\u6536\u5230\u6D88\u606F (\u4F1A\u8BDD: ${o}):`,JSON.stringify(n)),!o||!this.clients.has(o)){t.status(400).json({jsonrpc:"2.0",error:{code:-32600,message:"\u65E0\u6548\u6216\u7F3A\u5C11sessionId"},id:n.id});return}if(!this.mcpProxy){t.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP\u4EE3\u7406\u672A\u8FD0\u884C"},id:n.id});return}if(n.id===void 0)m.info(`\u8F6C\u53D1\u901A\u77E5: ${n.method}`),this.mcpProxy.stdin.write(`${JSON.stringify(n)}
9
+ `),t.status(202).send();else{let s=await this.forwardToProxy(n),c=this.clients.get(o);c&&this.sendToClient(c,s),t.status(202).send()}}catch(o){m.error("SSE\u6D88\u606F\u9519\u8BEF:",o),t.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:o instanceof Error?o.message:"\u5185\u90E8\u9519\u8BEF"},id:e.body.id})}}),this.app.post("/rpc",async(e,t)=>{try{let o=e.body;if(m.debug("\u6536\u5230RPC\u6D88\u606F:",o),!this.mcpProxy){t.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP\u4EE3\u7406\u672A\u8FD0\u884C"},id:o.id});return}let n=await this.forwardToProxy(o);t.json(n)}catch(o){m.error("RPC\u9519\u8BEF:",o),t.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:o instanceof Error?o.message:"\u5185\u90E8\u9519\u8BEF"},id:e.body.id})}}),this.app.get("/health",(e,t)=>{t.json({status:"ok",mode:"mcp-server",proxy:this.mcpProxy?"running":"stopped",clients:this.clients.size})})}responseBuffer="";pendingRequests=new Map;async forwardToProxy(e){return new Promise((t,o)=>{if(!this.mcpProxy||!this.mcpProxy.stdin||!this.mcpProxy.stdout){o(new Error("MCP\u4EE3\u7406\u4E0D\u53EF\u7528"));return}let n=setTimeout(()=>{this.pendingRequests.delete(e.id),m.warn(`\u6D88\u606F\u8D85\u65F6 id: ${e.id}, \u65B9\u6CD5: ${e.method} - \u5982\u679C\u54CD\u5E94\u5DF2\u901A\u8FC7SSE\u53D1\u9001\uFF0C\u8FD9\u662F\u6B63\u5E38\u7684`),t({jsonrpc:"2.0",id:e.id,result:{_timeout:!0,message:"\u54CD\u5E94\u53EF\u80FD\u5DF2\u901A\u8FC7SSE\u53D1\u9001"}})},3e4);this.pendingRequests.set(e.id,{resolve:t,reject:o,timeoutId:n}),m.info(`\u8F6C\u53D1\u6D88\u606F\u5230\u4EE3\u7406: ${JSON.stringify(e)}`),this.mcpProxy.stdin.write(`${JSON.stringify(e)}
10
+ `)})}handleProxyResponse(e){try{this.responseBuffer+=e.toString();let t=this.responseBuffer.split(`
11
+ `);this.responseBuffer=t.pop()||"";for(let o of t)if(o.trim())try{let n=JSON.parse(o);if(m.debug(`\u6536\u5230\u4EE3\u7406\u54CD\u5E94: ${o.substring(0,200)}...`),n.id!==void 0&&this.pendingRequests.has(n.id)){let s=this.pendingRequests.get(n.id);clearTimeout(s.timeoutId),this.pendingRequests.delete(n.id),s.resolve(n)}}catch{m.debug(`\u6765\u81EA\u4EE3\u7406\u7684\u975EJSON\u884C: ${o}`)}}catch(t){m.error("\u5904\u7406\u4EE3\u7406\u54CD\u5E94\u65F6\u51FA\u9519:",t)}}sendToClient(e,t){try{let o=`event: message
12
+ data: ${JSON.stringify(t)}
13
13
 
14
- `;e.response.write(t)}catch(t){h.error(`\u53D1\u9001\u5230\u5BA2\u6237\u7AEF ${e.id} \u5931\u8D25:`,t),this.clients.delete(e.sessionId)}}broadcastToClients(e){for(let o of this.clients.values())this.sendToClient(o,e)}async start(){try{let e=await Promise.allSettled([this.startMCPProxy(),new Promise(n=>{this.server=this.app.listen(this.port,()=>{h.info(`MCP\u670D\u52A1\u5668\u76D1\u542C\u7AEF\u53E3 ${this.port}`),h.info(`SSE\u7AEF\u70B9: http://localhost:${this.port}/sse`),h.info(`\u6D88\u606F\u7AEF\u70B9: http://localhost:${this.port}/messages`),h.info(`RPC\u7AEF\u70B9: http://localhost:${this.port}/rpc`),n()})})]),[o,t]=e;if(o.status==="rejected"&&h.error("MCP\u4EE3\u7406\u542F\u52A8\u5931\u8D25:",o.reason),t.status==="rejected")throw h.error("HTTP\u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25:",t.reason),t.reason;this.startMCPClient().catch(n=>{h.error("\u542F\u52A8\u8FDE\u63A5\u5230xiaozhi.me\u7684MCP\u5BA2\u6237\u7AEF\u5931\u8D25:",n)}),this.emit("started")}catch(e){throw h.error("\u542F\u52A8MCP\u670D\u52A1\u5668\u5931\u8D25:",e),e}}findMCPProxyPath(){if(this.mcpProxyPath)return this.mcpProxyPath;if(process.env.MCP_SERVER_PROXY_PATH){let n=w.normalize(process.env.MCP_SERVER_PROXY_PATH),s=w.resolve(n),c=[z,w.join(z,".."),w.join(z,"..",".."),w.join(z,"..","..","dist"),Le.tmpdir()];if(L.existsSync(s)&&w.basename(s)===_&&c.some(a=>s.startsWith(a)))return this.mcpProxyPath=s,this.mcpProxyPath;throw h.warn(`MCP_SERVER_PROXY_PATH \u8DEF\u5F84\u4E0D\u5B89\u5168: ${n}`),new Error(`\u6307\u5B9A\u7684 MCP \u4EE3\u7406\u8DEF\u5F84\u4E0D\u5B58\u5728\u6216\u4E0D\u5B89\u5168: ${process.env.MCP_SERVER_PROXY_PATH}`)}let e=me(import.meta.url),o=w.dirname(e),t=null;for(let n=0;n<5;n++){let s=w.join(o,_);if(L.existsSync(s)){t=s;break}let c=w.join(o,"dist",_);if(L.existsSync(c)){t=c;break}o=w.dirname(o)}if(!t){let n=w.resolve(z,"..",".."),s=w.join(n,"dist",_);L.existsSync(s)&&(t=s)}if(!t)throw new Error(`\u5728\u9879\u76EE\u7ED3\u6784\u4E2D\u627E\u4E0D\u5230 ${_}`);return this.mcpProxyPath=t,this.mcpProxyPath}async startMCPProxy(){let e=this.findMCPProxyPath();h.info(`\u6B63\u5728\u542F\u52A8MCP\u4EE3\u7406: ${e}`),this.mcpProxy=De("node",[e],{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",o=>{h.error("MCP\u4EE3\u7406\u9519\u8BEF:",o)}),this.mcpProxy.on("exit",(o,t)=>{h.warn(`MCP\u4EE3\u7406\u9000\u51FA\uFF0C\u4EE3\u7801 ${o}\uFF0C\u4FE1\u53F7 ${t}`),this.mcpProxy=null}),this.mcpProxy.stderr&&this.mcpProxy.stderr.on("data",o=>{let t=o.toString().trim();t.includes("[ERROR]")||t.includes("Error:")||t.includes("Failed")?h.error("MCP\u4EE3\u7406stderr:",t):h.info("MCP\u4EE3\u7406\u8F93\u51FA:",t)}),this.mcpProxy.stdout&&this.mcpProxy.stdout.on("data",o=>{this.handleProxyResponse(o)}),await new Promise((o,t)=>{let n=setTimeout(()=>{t(new Error("MCP\u4EE3\u7406\u542F\u52A8\u8D85\u65F6"))},1e4),s=g(c=>{let a=c.toString();(a.includes("MCP proxy ready")||a.includes("started"))&&(clearTimeout(n),this.mcpProxy?.stdout?.removeListener("data",s),o())},"dataHandler");this.mcpProxy?.stdout?.on("data",s)}),h.info("MCP\u4EE3\u7406\u542F\u52A8\u6210\u529F")}async startMCPClient(){let e=[];try{l.configExists()&&(e=l.getMcpEndpoints())}catch(o){h.warn("\u4ECE\u914D\u7F6E\u4E2D\u8BFB\u53D6MCP\u7AEF\u70B9\u5931\u8D25:",o)}if(e.length>0){let o=this.findMCPProxyPath();this.mcpClient=new G(o,e),await this.mcpClient.start(),h.info("MCP\u5BA2\u6237\u7AEF\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u8FDE\u63A5\u5230 xiaozhi.me")}else h.info("\u672A\u914D\u7F6EMCP\u7AEF\u70B9\uFF0C\u8DF3\u8FC7\u5BA2\u6237\u7AEF\u8FDE\u63A5")}async stop(){h.info("\u6B63\u5728\u505C\u6B62MCP\u670D\u52A1\u5668...");for(let e of this.clients.values())try{e.response.end()}catch{}this.clients.clear(),this.server&&(await new Promise(e=>{this.server.close(()=>e())}),this.server=null),this.mcpProxy&&(this.mcpProxy.kill("SIGTERM"),await new Promise(e=>{this.mcpProxy.on("exit",()=>e()),setTimeout(()=>{this.mcpProxy?.kill("SIGKILL"),e()},5e3)}),this.mcpProxy=null),this.mcpClient&&(this.mcpClient.shutdown(),this.mcpClient=null),this.mcpProxyPath=null,this.emit("stopped"),h.info("MCP\u670D\u52A1\u5668\u5DF2\u505C\u6B62")}}});import{spawn as Pe}from"child_process";import{existsSync as oe}from"fs";import{readFile as Ie}from"fs/promises";import{createServer as go}from"http";import{dirname as po,join as j}from"path";import{parse as fo}from"url";import{fileURLToPath as mo}from"url";import{WebSocketServer as ho}from"ws";import{spawn as Y}from"child_process";import C from"fs";import f from"path";import{fileURLToPath as $}from"url";import i from"chalk";import{Command as Ue}from"commander";import P from"ora";E();import ke from"omelette";function Ae(){try{if(!l.configExists())return[];let r=l.getMcpServers();return Object.keys(r)}catch{return[]}}g(Ae,"getMcpServerNames");function Ne(r){try{if(!l.configExists())return[];let e=l.getServerToolsConfig(r);return Object.keys(e)}catch{return[]}}g(Ne,"getServerToolNames");function re(){let r=ke("xiaozhi <command>");if(r.on("command",({reply:e})=>{e(["create","init","config","start","stop","status","attach","restart","mcp","completion"])}),r.on("complete",(e,{line:o,before:t,reply:n})=>{process.env.XIAOZHI_DEBUG_COMPLETION&&console.error(`Debug completion - line: "${o}", before: "${t}", fragment: "${e}"`);let s=o.trim().split(/\s+/),a=o!==o.trim()?s.length:s.length-1;if(s[1]==="mcp"){let m=s[2];if(a===2){let u=["list","server","tool"],y=s[2]||"",b=u.filter(S=>S.startsWith(y));n(b);return}if(a===3){switch(m){case"list":{let u=["--tools"],y=s[3]||"",b=u.filter(S=>S.startsWith(y));n(b);break}case"server":case"tool":{let u=Ae(),y=s[3]||"",b=u.filter(S=>S.startsWith(y));n(b);break}default:n([])}return}if(a===4&&m==="tool"){let u=s[3],y=Ne(u),b=s[4]||"",S=y.filter(R=>R.startsWith(b));n(S);return}if(a===5&&m==="tool"){let u=["enable","disable"],y=s[5]||"",b=u.filter(S=>S.startsWith(y));n(b);return}}if(a===2){switch(s[1]){case"create":n(["--template","-t"]);break;case"start":case"restart":n(["--daemon","-d"]);break;case"completion":n(["install","uninstall"]);break;default:n([])}return}n([])}),process.argv.includes("--completion")){try{console.log(r.setupShellInitFile())}catch(e){console.error("\u751F\u6210\u81EA\u52A8\u8865\u5168\u811A\u672C\u65F6\u51FA\u9519:",e)}process.exit(0)}process.argv.includes("--completion-fish")&&(console.log(r.setupShellInitFile("fish")),process.exit(0)),process.argv.includes("--compzsh")||process.argv.includes("--compbash"),r.init()}g(re,"setupAutoCompletion");function se(){console.log("\u{1F680} xiaozhi \u81EA\u52A8\u8865\u5168\u8BBE\u7F6E"),console.log(),console.log("\u8981\u542F\u7528\u81EA\u52A8\u8865\u5168\uFF0C\u8BF7\u6839\u636E\u4F60\u7684shell\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\uFF1A"),console.log(),console.log("\u{1F4DD} Zsh (\u63A8\u8350):"),console.log(" xiaozhi --completion >> ~/.xiaozhi-completion.zsh"),console.log(" echo 'source ~/.xiaozhi-completion.zsh' >> ~/.zshrc"),console.log(" source ~/.zshrc"),console.log(),console.log("\u{1F4DD} Bash:"),console.log(" xiaozhi --completion >> ~/.xiaozhi-completion.bash"),console.log(" echo 'source ~/.xiaozhi-completion.bash' >> ~/.bash_profile"),console.log(" source ~/.bash_profile"),console.log(),console.log("\u{1F4DD} Fish:"),console.log(" xiaozhi --completion-fish >> ~/.config/fish/completions/xiaozhi.fish"),console.log(),console.log("\u2728 \u8BBE\u7F6E\u5B8C\u6210\u540E\uFF0C\u4F60\u5C31\u53EF\u4EE5\u4F7F\u7528 Tab \u952E\u8FDB\u884C\u81EA\u52A8\u8865\u5168\u4E86\uFF01"),console.log(),console.log("\u{1F4A1} \u793A\u4F8B:"),console.log(" xiaozhi m<Tab> # \u2192 mcp"),console.log(" xiaozhi mcp l<Tab> # \u2192 list"),console.log(" xiaozhi mcp tool <Tab> # \u2192 \u663E\u793A\u6240\u6709\u670D\u52A1\u5668\u540D\u79F0")}g(se,"showCompletionHelp");E();A();E();import p from"chalk";import ie from"cli-table3";import Z from"ora";function ce(r){let e=0;for(let o of r)/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(o)?e+=2:e+=1;return e}g(ce,"getDisplayWidth");function ae(r,e){if(ce(r)<=e)return r;if(e<=3)return"";let o="",t=0,n=!1;for(let s of r){let c=/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(s)?2:1;if(t+c>e-3){if(!n)return"";o+="...";break}o+=s,t+=c,n=!0}return o}g(ae,"truncateToWidth");async function le(r={}){let e=Z("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868...").start();try{let o=l.getMcpServers(),t=Object.keys(o);if(t.length===0){e.warn("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1"),console.log(p.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi config' \u547D\u4EE4\u914D\u7F6E MCP \u670D\u52A1"));return}if(e.succeed(`\u627E\u5230 ${t.length} \u4E2A MCP \u670D\u52A1`),r.tools){console.log(),console.log(p.bold("MCP \u670D\u52A1\u5DE5\u5177\u5217\u8868:")),console.log();let n=8,s=[];for(let a of t){let m=l.getServerToolsConfig(a),u=Object.keys(m);s.push(...u)}for(let a of s){let m=ce(a);m>n&&(n=m)}n=Math.max(10,Math.min(n+2,30));let c=new ie({head:[p.bold("MCP"),p.bold("\u5DE5\u5177\u540D\u79F0"),p.bold("\u72B6\u6001"),p.bold("\u63CF\u8FF0")],colWidths:[15,n,8,40],wordWrap:!0,style:{head:[],border:[]}});for(let a of t){let m=l.getServerToolsConfig(a),u=Object.keys(m);if(u.length===0)c.push([p.gray(a),p.gray("-"),p.gray("-"),p.gray("\u6682\u672A\u8BC6\u522B\u5230\u76F8\u5173\u5DE5\u5177")]);else{c.length>0&&c.push([{colSpan:4,content:""}]);for(let y of u){let b=m[y],S=b.enable?p.green("\u542F\u7528"):p.red("\u7981\u7528"),R=ae(b.description||"",32);c.push([a,y,S,R])}}}console.log(c.toString())}else{console.log(),console.log(p.bold("MCP \u670D\u52A1\u5217\u8868:")),console.log();for(let n of t){let s=o[n],c=l.getServerToolsConfig(n),a=Object.keys(c).length,m=Object.values(c).filter(u=>u.enable!==!1).length;console.log(`${p.cyan("\u2022")} ${p.bold(n)}`),"url"in s?("type"in s&&s.type==="sse"?console.log(` \u7C7B\u578B: ${p.gray("SSE")}`):console.log(` \u7C7B\u578B: ${p.gray("Streamable HTTP")}`),console.log(` URL: ${p.gray(s.url)}`)):console.log(` \u547D\u4EE4: ${p.gray(s.command)} ${p.gray(s.args.join(" "))}`),a>0?console.log(` \u5DE5\u5177: ${p.green(m)} \u542F\u7528 / ${p.yellow(a)} \u603B\u8BA1`):console.log(` \u5DE5\u5177: ${p.gray("\u672A\u626B\u63CF (\u8BF7\u5148\u542F\u52A8\u670D\u52A1)")}`),console.log()}}console.log(p.gray("\u{1F4A1} \u63D0\u793A:")),console.log(p.gray(" - \u4F7F\u7528 'xiaozhi mcp list --tools' \u67E5\u770B\u6240\u6709\u5DE5\u5177")),console.log(p.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> list' \u67E5\u770B\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177")),console.log(p.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> <\u5DE5\u5177\u540D> enable/disable' \u542F\u7528/\u7981\u7528\u5DE5\u5177"))}catch(o){e.fail("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868\u5931\u8D25"),console.error(p.red(`\u9519\u8BEF: ${o instanceof Error?o.message:String(o)}`)),process.exit(1)}}g(le,"listMcpServers");async function ge(r){let e=Z(`\u83B7\u53D6 ${r} \u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868...`).start();try{if(!l.getMcpServers()[r]){e.fail(`\u670D\u52A1 '${r}' \u4E0D\u5B58\u5728`),console.log(p.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let t=l.getServerToolsConfig(r),n=Object.keys(t);if(n.length===0){e.warn(`\u670D\u52A1 '${r}' \u6682\u65E0\u5DE5\u5177\u4FE1\u606F`),console.log(p.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u542F\u52A8\u670D\u52A1\u4EE5\u626B\u63CF\u5DE5\u5177\u5217\u8868"));return}e.succeed(`\u670D\u52A1 '${r}' \u5171\u6709 ${n.length} \u4E2A\u5DE5\u5177`),console.log(),console.log(p.bold(`${r} \u670D\u52A1\u5DE5\u5177\u5217\u8868:`)),console.log();let s=new ie({head:[p.bold("\u5DE5\u5177\u540D\u79F0"),p.bold("\u72B6\u6001"),p.bold("\u63CF\u8FF0")],colWidths:[30,8,50],wordWrap:!0,style:{head:[],border:[]}});for(let c of n){let a=t[c],m=a.enable?p.green("\u542F\u7528"):p.red("\u7981\u7528"),u=ae(a.description||"",40);s.push([c,m,u])}console.log(s.toString()),console.log(),console.log(p.gray("\u{1F4A1} \u63D0\u793A:")),console.log(p.gray(` - \u4F7F\u7528 'xiaozhi mcp ${r} <\u5DE5\u5177\u540D> enable' \u542F\u7528\u5DE5\u5177`)),console.log(p.gray(` - \u4F7F\u7528 'xiaozhi mcp ${r} <\u5DE5\u5177\u540D> disable' \u7981\u7528\u5DE5\u5177`))}catch(o){e.fail("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25"),console.error(p.red(`\u9519\u8BEF: ${o instanceof Error?o.message:String(o)}`)),process.exit(1)}}g(ge,"listServerTools");async function pe(r,e,o){let t=o?"\u542F\u7528":"\u7981\u7528",n=Z(`${t}\u5DE5\u5177 ${r}/${e}...`).start();try{if(!l.getMcpServers()[r]){n.fail(`\u670D\u52A1 '${r}' \u4E0D\u5B58\u5728`),console.log(p.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let c=l.getServerToolsConfig(r);if(!c[e]){n.fail(`\u5DE5\u5177 '${e}' \u5728\u670D\u52A1 '${r}' \u4E2D\u4E0D\u5B58\u5728`),console.log(p.yellow(`\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp ${r} list' \u67E5\u770B\u8BE5\u670D\u52A1\u7684\u6240\u6709\u5DE5\u5177`));return}l.setToolEnabled(r,e,o,c[e].description),n.succeed(`\u6210\u529F${t}\u5DE5\u5177 ${p.cyan(r)}/${p.cyan(e)}`),console.log(),console.log(p.gray("\u{1F4A1} \u63D0\u793A: \u5DE5\u5177\u72B6\u6001\u66F4\u6539\u5C06\u5728\u4E0B\u6B21\u542F\u52A8\u670D\u52A1\u65F6\u751F\u6548"))}catch(s){n.fail(`${t}\u5DE5\u5177\u5931\u8D25`),console.error(p.red(`\u9519\u8BEF: ${s instanceof Error?s.message:String(s)}`)),process.exit(1)}}g(pe,"setToolEnabled");var v=new Ue,Xe="xiaozhi-mcp-service";function be(){try{let r=$(import.meta.url),e=f.dirname(r),o=[f.join(e,"..","package.json"),f.join(e,"..","package.json"),f.join(e,"..","..","package.json"),f.join(e,"package.json")];for(let t of o)if(C.existsSync(t)){let n=JSON.parse(C.readFileSync(t,"utf8"));if(n.version)return n.version}return"unknown"}catch(r){return console.warn("\u65E0\u6CD5\u4ECE package.json \u8BFB\u53D6\u7248\u672C\u4FE1\u606F:",r),"unknown"}}g(be,"getVersion");var Q=g(()=>{let r=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return f.join(r,`.${Xe}.pid`)},"getPidFile");function M(){try{let r=Q();if(!C.existsSync(r))return{running:!1};let e=C.readFileSync(r,"utf8").trim(),[o,t,n]=e.split("|"),s=Number.parseInt(o);if(Number.isNaN(s))return C.unlinkSync(r),{running:!1};try{process.kill(s,0);let c=Number.parseInt(t),a=Be(Date.now()-c);return{running:!0,pid:s,uptime:a,mode:n||"foreground"}}catch{return C.unlinkSync(r),{running:!1}}}catch{return{running:!1}}}g(M,"getServiceStatus");function Be(r){let e=Math.floor(r/1e3),o=Math.floor(e/60),t=Math.floor(o/60),n=Math.floor(t/24);return n>0?`${n}\u5929 ${t%24}\u5C0F\u65F6 ${o%60}\u5206\u949F`:t>0?`${t}\u5C0F\u65F6 ${o%60}\u5206\u949F`:o>0?`${o}\u5206\u949F ${e%60}\u79D2`:`${e}\u79D2`}g(Be,"formatUptime");function q(r,e){let o=`${r}|${Date.now()}|${e}`;C.writeFileSync(Q(),o)}g(q,"savePidInfo");function H(){try{let r=Q();C.existsSync(r)&&C.unlinkSync(r)}catch{}}g(H,"cleanupPidFile");function Ze(){if(!l.configExists())return console.error(i.red("\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728")),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E')),!1;try{let r=l.getMcpEndpoint();return!r||r.includes("<\u8BF7\u586B\u5199")?(console.error(i.red("\u274C \u9519\u8BEF: MCP \u7AEF\u70B9\u672A\u914D\u7F6E")),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9')),!1):!0}catch(r){return console.error(i.red(`\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u65E0\u6548 - ${r instanceof Error?r.message:String(r)}`)),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u91CD\u65B0\u521D\u59CB\u5316\u914D\u7F6E')),!1}}g(Ze,"checkEnvironment");function Ve(){let r=f.dirname($(import.meta.url)),e;return r.includes("js-demo/dist")?e=r:e=[f.join(r,"..","js-demo","dist"),f.join(r,"..","..","js-demo","dist"),f.join(r,"..","..","..","js-demo","dist"),f.join(process.cwd(),"js-demo","dist"),f.join(process.cwd(),"dist")].find(t=>C.existsSync(f.join(t,"adaptiveMCPPipe.js"))&&C.existsSync(f.join(t,"mcpServerProxy.js")))||r,{command:"node",args:["adaptiveMCPPipe.js","mcpServerProxy.js"],cwd:e}}g(Ve,"getServiceCommand");async function ye(){try{if(!l.configExists()){console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7 Web UI \u542F\u52A8"));return}let r=new F;await r.start();let e=l.getWebUIPort();console.log(i.green(`\u2705 Web UI \u5DF2\u542F\u52A8: http://localhost:${e}`));let{spawn:o}=await import("child_process"),t=`http://localhost:${e}`;try{process.platform==="darwin"?o("open",[t],{detached:!0,stdio:"ignore"}).unref():process.platform==="win32"?o("cmd",["/c","start",t],{detached:!0,stdio:"ignore"}).unref():o("xdg-open",[t],{detached:!0,stdio:"ignore"}).unref()}catch{}global.__webServer=r}catch(r){console.log(i.yellow(`\u26A0\uFE0F Web UI \u542F\u52A8\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`))}}g(ye,"startWebUIInBackground");async function Se(r=!1,e=!1){let o=P("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let t=M();if(t.running){o.fail(`\u670D\u52A1\u5DF2\u7ECF\u5728\u8FD0\u884C (PID: ${t.pid})`);return}if(o.text="\u68C0\u67E5\u73AF\u5883\u914D\u7F6E...",!Ze()){o.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}let{command:n,args:s,cwd:c}=Ve();if(o.text=`\u542F\u52A8\u670D\u52A1 (${r?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,r){let a=Y(n,s,{cwd:c,detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true"}});q(a.pid,"daemon");let m=process.cwd();I.initLogFile(m),I.enableFileLogging(!0);let u=f.join(m,"xiaozhi.log"),y=C.createWriteStream(u,{flags:"a"});a.stdout?.pipe(y),a.stderr?.pipe(y),a.on("exit",(b,S)=>{b!==0&&b!==null&&I.error(`\u540E\u53F0\u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${b}, \u4FE1\u53F7: ${S})`),H()}),a.on("error",b=>{I.error(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u9519\u8BEF: ${b.message}`),H(),o.fail(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u5931\u8D25: ${b.message}`)}),a.unref(),o.succeed(`\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${a.pid})`),console.log(i.gray(`\u65E5\u5FD7\u6587\u4EF6: ${u}`)),console.log(i.gray("\u4F7F\u7528 'xiaozhi attach' \u53EF\u4EE5\u67E5\u770B\u5B9E\u65F6\u65E5\u5FD7")),e&&await ye()}else{o.succeed("\u670D\u52A1\u542F\u52A8\u4E2D...");let a=Y(n,s,{cwd:c,stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});q(a.pid,"foreground"),a.on("exit",(m,u)=>{H(),console.log(m!==0?i.red(`
15
- \u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${m}, \u4FE1\u53F7: ${u})`):i.green(`
16
- \u670D\u52A1\u5DF2\u505C\u6B62`))}),e&&setTimeout(()=>{ye()},1e3),process.on("SIGINT",async()=>{if(console.log(i.yellow(`
17
- \u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),a.kill("SIGTERM"),global.__webServer)try{await global.__webServer.stop(),console.log(i.green("Web UI \u5DF2\u505C\u6B62"))}catch{}}),process.on("SIGTERM",async()=>{if(a.kill("SIGTERM"),global.__webServer)try{await global.__webServer.stop()}catch{}})}}catch(t){o.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(Se,"startService");async function ve(){let r=P("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=M();if(!e.running){r.warn("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}r.text=`\u505C\u6B62\u670D\u52A1 (PID: ${e.pid})...`;try{process.kill(e.pid,"SIGTERM");let o=0,t=30;for(;o<t;){await new Promise(n=>setTimeout(n,100));try{process.kill(e.pid,0),o++}catch{break}}try{process.kill(e.pid,0),r.text="\u5F3A\u5236\u505C\u6B62\u670D\u52A1...",process.kill(e.pid,"SIGKILL"),await new Promise(n=>setTimeout(n,500))}catch{}H(),r.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(o){H(),r.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}catch(e){r.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}g(ve,"stopService");async function Ke(){let r=P("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=M();if(e.running){if(r.succeed("\u670D\u52A1\u72B6\u6001"),console.log(i.green("\u2705 \u670D\u52A1\u6B63\u5728\u8FD0\u884C")),console.log(i.gray(` PID: ${e.pid}`)),console.log(i.gray(` \u8FD0\u884C\u65F6\u95F4: ${e.uptime}`)),console.log(i.gray(` \u8FD0\u884C\u6A21\u5F0F: ${e.mode==="daemon"?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"}`)),e.mode==="daemon"){let o=f.join(process.cwd(),"xiaozhi.log");console.log(i.gray(` \u65E5\u5FD7\u6587\u4EF6: ${o}`))}}else r.succeed("\u670D\u52A1\u72B6\u6001"),console.log(i.red("\u274C \u670D\u52A1\u672A\u8FD0\u884C"))}catch(e){r.fail(`\u68C0\u67E5\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}g(Ke,"checkStatus");async function Ye(){let r=P("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=M();if(!e.running){r.fail("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}if(e.mode!=="daemon"){r.fail("\u670D\u52A1\u4E0D\u662F\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C");return}r.succeed("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1..."),console.log(i.green(`\u5DF2\u8FDE\u63A5\u5230\u670D\u52A1 (PID: ${e.pid})`)),console.log(i.gray("\u6309 Ctrl+C \u53EF\u4EE5\u65AD\u5F00\u8FDE\u63A5\uFF08\u4E0D\u4F1A\u505C\u6B62\u670D\u52A1\uFF09")),console.log(i.gray("=".repeat(50)));let o=f.join(process.cwd(),"xiaozhi.log");if(C.existsSync(o))if(process.platform==="win32"){let{spawn:t}=await import("child_process"),n=t("powershell",["-Command",`Get-Content -Path "${o}" -Wait`],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(i.yellow(`
18
- \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),n.kill(),process.exit(0)}),n.on("exit",()=>{process.exit(0)})}else{let{spawn:t}=await import("child_process"),n=t("tail",["-f",o],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(i.yellow(`
19
- \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),n.kill(),process.exit(0)}),n.on("exit",()=>{process.exit(0)})}else console.log(i.yellow("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728"))}catch(e){r.fail(`\u8FDE\u63A5\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}g(Ye,"attachService");async function qe(r=!1,e=!1){console.log(i.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await ve(),await new Promise(o=>setTimeout(o,1e3)),await Se(r,e)}g(qe,"restartService");async function Qe(r,e=!1){let o=P("\u542F\u52A8 MCP Server \u6A21\u5F0F...").start();try{if(!l.configExists()){o.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}let{MCPServer:t}=await Promise.resolve().then(()=>(ue(),he));if(e){let n=$(import.meta.url),s=f.dirname(n),c=Y("node",[f.join(s,"cli.js"),"start","--server",r.toString()],{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true",MCP_SERVER_MODE:"true"}});q(c.pid,"daemon");let a=f.join(process.cwd(),"xiaozhi-mcp-server.log"),m=C.createWriteStream(a,{flags:"a"});c.stdout?.pipe(m),c.stderr?.pipe(m),c.unref(),o.succeed(`MCP Server \u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${c.pid}, Port: ${r})`),console.log(i.gray(`\u65E5\u5FD7\u6587\u4EF6: ${a}`))}else{let n=new t(r),s=g(async()=>{console.log(i.yellow(`
20
- \u6B63\u5728\u505C\u6B62 MCP Server...`)),await n.stop(),process.exit(0)},"cleanup");process.on("SIGINT",s),process.on("SIGTERM",s),await n.start(),o.succeed("MCP Server \u5DF2\u542F\u52A8"),console.log(i.green(`\u2705 SSE endpoint: http://localhost:${r}/sse`)),console.log(i.green(`\u2705 Messages endpoint: http://localhost:${r}/messages`)),console.log(i.green(`\u2705 RPC endpoint: http://localhost:${r}/rpc`)),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1"))}}catch(t){o.fail(`\u542F\u52A8 MCP Server \u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(Qe,"startMCPServerMode");function eo(){let r=be();console.log(i.blue(`xiaozhi v${r}`)),console.log(i.gray("MCP Calculator Service CLI Tool")),console.log(i.gray("Built with Node.js and TypeScript")),console.log(i.gray(`Node.js: ${process.version}`)),console.log(i.gray(`Platform: ${process.platform} ${process.arch}`))}g(eo,"showDetailedInfo");async function oo(r="json"){let e=P("\u521D\u59CB\u5316\u914D\u7F6E...").start();try{if(l.configExists()){e.warn("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728"),console.log(i.yellow("\u5982\u9700\u91CD\u65B0\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u5220\u9664\u73B0\u6709\u7684\u914D\u7F6E\u6587\u4EF6"));return}l.initConfig(r),e.succeed("\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u6210\u529F");let o=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=`xiaozhi.config.${r}`,n=f.join(o,t);console.log(i.green(`\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u521B\u5EFA: ${t}`)),console.log(i.yellow("\u{1F4DD} \u8BF7\u7F16\u8F91\u914D\u7F6E\u6587\u4EF6\u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9:")),console.log(i.gray(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${n}`)),console.log(i.yellow("\u{1F4A1} \u6216\u8005\u4F7F\u7528\u547D\u4EE4\u8BBE\u7F6E:")),console.log(i.gray(" xiaozhi config mcpEndpoint <your-endpoint-url>"))}catch(o){e.fail(`\u521D\u59CB\u5316\u914D\u7F6E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(oo,"initConfig");function to(){let r=f.dirname($(import.meta.url)),o=[f.join(r,"..","templates"),f.join(r,"templates"),f.join(r,"..","..","templates")].find(t=>C.existsSync(t));return o?C.readdirSync(o).filter(t=>{let n=f.join(o,t);return C.statSync(n).isDirectory()}):[]}g(to,"getAvailableTemplates");function Ce(r,e){let o=r.length,t=e.length,n=Array(o+1).fill(null).map(()=>Array(t+1).fill(0));for(let c=0;c<=o;c++)n[c][0]=c;for(let c=0;c<=t;c++)n[0][c]=c;for(let c=1;c<=o;c++)for(let a=1;a<=t;a++)r[c-1]===e[a-1]?n[c][a]=n[c-1][a-1]:n[c][a]=Math.min(n[c-1][a]+1,n[c][a-1]+1,n[c-1][a-1]+1);let s=Math.max(o,t);return s===0?1:(s-n[o][t])/s}g(Ce,"calculateSimilarity");function no(r,e){if(e.length===0)return null;let o=e[0],t=Ce(r.toLowerCase(),o.toLowerCase());for(let n of e.slice(1)){let s=Ce(r.toLowerCase(),n.toLowerCase());s>t&&(t=s,o=n)}return t>.5?o:null}g(no,"findSimilarTemplate");async function ro(r){if(!process.stdin.isTTY)return console.log("n (\u975E\u4EA4\u4E92\u5F0F\u73AF\u5883)"),!1;let e=await import("readline");return new Promise(o=>{process.stdout.write(r);let t=e.createInterface({input:process.stdin,output:process.stdout}),n=g(s=>{let c=s.trim().toLowerCase();c==="y"||c==="yes"?(t.close(),o(!0)):c==="n"||c==="no"||c===""?(t.close(),o(!1)):process.stdout.write("\u8BF7\u8F93\u5165 y \u6216 n: ")},"handleInput");t.on("line",n),t.on("SIGINT",()=>{t.close(),o(!1)})})}g(ro,"askUserConfirmation");function so(r){let e={mcpEndpoint:"<\u8BF7\u586B\u5199\u4F60\u7684\u63A5\u5165\u70B9\u5730\u5740\uFF08\u83B7\u53D6\u5730\u5740\u5728 xiaozhi.me\uFF09>",mcpServers:{}},o=f.join(r,"xiaozhi.config.json");C.writeFileSync(o,JSON.stringify(e,null,2),"utf8")}g(so,"createBasicConfig");async function io(r,e){let o=P("\u521D\u59CB\u5316\u9879\u76EE...").start();try{let t=f.join(process.cwd(),r);if(C.existsSync(t)){o.fail(`\u76EE\u5F55 "${r}" \u5DF2\u5B58\u5728`),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u9009\u62E9\u4E0D\u540C\u7684\u9879\u76EE\u540D\u79F0\u6216\u5220\u9664\u73B0\u6709\u76EE\u5F55"));return}if(e.template){o.text="\u68C0\u67E5\u6A21\u677F...";let n=to();if(n.length===0){o.fail("\u627E\u4E0D\u5230 templates \u76EE\u5F55"),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u786E\u4FDD xiaozhi-client \u6B63\u786E\u5B89\u88C5"));return}if(!n.includes(e.template)){o.fail(`\u6A21\u677F "${e.template}" \u4E0D\u5B58\u5728`);let y=no(e.template,n);if(y)if(console.log(i.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${y}" \u5417\uFF1F`)),await ro(i.cyan("\u786E\u8BA4\u4F7F\u7528\u6B64\u6A21\u677F\uFF1F(y/n): ")))e.template=y;else{console.log(i.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let S of n)console.log(i.gray(` - ${S}`));return}else{console.log(i.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let b of n)console.log(i.gray(` - ${b}`));return}}let s=f.dirname($(import.meta.url)),a=[f.join(s,"..","templates"),f.join(s,"templates"),f.join(s,"..","..","templates")].find(y=>C.existsSync(y)),m=f.join(a,e.template);o.text=`\u4ECE\u6A21\u677F "${e.template}" \u521B\u5EFA\u9879\u76EE "${r}"...`,we(m,t,["node_modules",".pnpm-debug.log","pnpm-lock.yaml"]);let u=f.join(t,"xiaozhi.log");C.existsSync(u)||C.writeFileSync(u,"","utf8"),o.succeed(`\u9879\u76EE "${r}" \u521B\u5EFA\u6210\u529F`),console.log(i.green("\u2705 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(i.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(i.gray(` cd ${r}`)),console.log(i.gray(" pnpm install # \u5B89\u88C5\u4F9D\u8D56")),console.log(i.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9")),console.log(i.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1"))}else{o.text=`\u521B\u5EFA\u57FA\u672C\u9879\u76EE "${r}"...`,C.mkdirSync(t,{recursive:!0}),so(t);let n=f.join(t,"xiaozhi.log");C.writeFileSync(n,"","utf8"),o.succeed(`\u9879\u76EE "${r}" \u521B\u5EFA\u6210\u529F`),console.log(i.green("\u2705 \u57FA\u672C\u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(i.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(i.gray(` cd ${r}`)),console.log(i.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9\u548C\u670D\u52A1")),console.log(i.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1")),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 --template \u9009\u9879\u53EF\u4EE5\u4ECE\u6A21\u677F\u521B\u5EFA\u9879\u76EE"))}}catch(t){o.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(io,"createProject");function we(r,e,o=[]){C.existsSync(e)||C.mkdirSync(e,{recursive:!0});let t=C.readdirSync(r);for(let n of t){if(o.some(m=>n.includes(m)))continue;let s=f.join(r,n),c=f.join(e,n);C.statSync(s).isDirectory()?we(s,c,o):C.copyFileSync(s,c)}}g(we,"copyDirectory");async function co(){let r=P("\u542F\u52A8 UI \u670D\u52A1...").start();try{if(!l.configExists()){r.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}let e=new F;await e.start(),r.succeed("UI \u670D\u52A1\u5DF2\u542F\u52A8");let o=l.getWebUIPort();console.log(i.green(`\u2705 \u914D\u7F6E\u7BA1\u7406\u7F51\u9875\u5DF2\u542F\u52A8: http://localhost:${o}`)),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1"));let{spawn:t}=await import("child_process"),n=`http://localhost:${o}`;try{process.platform==="darwin"?t("open",[n],{detached:!0,stdio:"ignore"}).unref():process.platform==="win32"?t("cmd",["/c","start",n],{detached:!0,stdio:"ignore"}).unref():t("xdg-open",[n],{detached:!0,stdio:"ignore"}).unref()}catch{}let s=!1;process.on("SIGINT",async()=>{s&&(console.log(i.red(`
14
+ `;e.response.write(o)}catch(o){m.error(`\u53D1\u9001\u5230\u5BA2\u6237\u7AEF ${e.id} \u5931\u8D25:`,o),this.clients.delete(e.sessionId)}}broadcastToClients(e){for(let t of this.clients.values())this.sendToClient(t,e)}async start(){try{let e=await Promise.allSettled([this.startMCPProxy(),new Promise(n=>{this.server=this.app.listen(this.port,"0.0.0.0",()=>{m.info(`MCP\u670D\u52A1\u5668\u76D1\u542C\u7AEF\u53E3 ${this.port} (\u6240\u6709\u7F51\u7EDC\u63A5\u53E3)`),m.info(`SSE\u7AEF\u70B9: http://0.0.0.0:${this.port}/sse`),m.info(`\u6D88\u606F\u7AEF\u70B9: http://0.0.0.0:${this.port}/messages`),m.info(`RPC\u7AEF\u70B9: http://0.0.0.0:${this.port}/rpc`),m.info(`\u672C\u5730\u8BBF\u95EE: http://localhost:${this.port}`),n()})})]),[t,o]=e;if(t.status==="rejected"&&m.error("MCP\u4EE3\u7406\u542F\u52A8\u5931\u8D25:",t.reason),o.status==="rejected")throw m.error("HTTP\u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25:",o.reason),o.reason;this.startMCPClient().catch(n=>{m.error("\u542F\u52A8\u8FDE\u63A5\u5230xiaozhi.me\u7684MCP\u5BA2\u6237\u7AEF\u5931\u8D25:",n)}),this.emit("started")}catch(e){throw m.error("\u542F\u52A8MCP\u670D\u52A1\u5668\u5931\u8D25:",e),e}}findMCPProxyPath(){if(this.mcpProxyPath)return this.mcpProxyPath;if(process.env.MCP_SERVER_PROXY_PATH){let n=w.normalize(process.env.MCP_SERVER_PROXY_PATH),s=w.resolve(n),c=[F,w.join(F,".."),w.join(F,"..",".."),w.join(F,"..","..","dist"),Be.tmpdir()];if(J.existsSync(s)&&w.basename(s)===N&&c.some(l=>s.startsWith(l)))return this.mcpProxyPath=s,this.mcpProxyPath;throw m.warn(`MCP_SERVER_PROXY_PATH \u8DEF\u5F84\u4E0D\u5B89\u5168: ${n}`),new Error(`\u6307\u5B9A\u7684 MCP \u4EE3\u7406\u8DEF\u5F84\u4E0D\u5B58\u5728\u6216\u4E0D\u5B89\u5168: ${process.env.MCP_SERVER_PROXY_PATH}`)}let e=be(import.meta.url),t=w.dirname(e),o=null;for(let n=0;n<Ve;n++){let s=w.join(t,N);if(J.existsSync(s)){o=s;break}let c=w.join(t,"dist",N);if(J.existsSync(c)){o=c;break}t=w.dirname(t)}if(!o){let n=w.resolve(F,"..",".."),s=w.join(n,"dist",N);J.existsSync(s)&&(o=s)}if(!o)throw new Error(`\u5728\u9879\u76EE\u7ED3\u6784\u4E2D\u627E\u4E0D\u5230 ${N}`);return this.mcpProxyPath=o,this.mcpProxyPath}async startMCPProxy(){let e=this.findMCPProxyPath();m.info(`\u6B63\u5728\u542F\u52A8MCP\u4EE3\u7406: ${e}`),this.mcpProxy=Je("node",[e],{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",t=>{m.error("MCP\u4EE3\u7406\u9519\u8BEF:",t)}),this.mcpProxy.on("exit",(t,o)=>{m.warn(`MCP\u4EE3\u7406\u9000\u51FA\uFF0C\u4EE3\u7801 ${t}\uFF0C\u4FE1\u53F7 ${o}`),this.mcpProxy=null}),this.mcpProxy.stderr&&this.mcpProxy.stderr.on("data",t=>{let o=t.toString().trim();o.includes("[ERROR]")||o.includes("Error:")||o.includes("Failed")?m.error("MCP\u4EE3\u7406stderr:",o):m.info("MCP\u4EE3\u7406\u8F93\u51FA:",o)}),this.mcpProxy.stdout&&this.mcpProxy.stdout.on("data",t=>{this.handleProxyResponse(t)}),await new Promise((t,o)=>{let n=setTimeout(()=>{o(new Error("MCP\u4EE3\u7406\u542F\u52A8\u8D85\u65F6"))},1e4),s=p(c=>{let l=c.toString();(l.includes("MCP proxy ready")||l.includes("started"))&&(clearTimeout(n),this.mcpProxy?.stdout?.removeListener("data",s),t())},"dataHandler");this.mcpProxy?.stdout?.on("data",s)}),m.info("MCP\u4EE3\u7406\u542F\u52A8\u6210\u529F")}async startMCPClient(){let e=[];try{a.configExists()&&(e=a.getMcpEndpoints())}catch(t){m.warn("\u4ECE\u914D\u7F6E\u4E2D\u8BFB\u53D6MCP\u7AEF\u70B9\u5931\u8D25:",t)}if(e.length>0){let t=this.findMCPProxyPath();this.mcpClient=new G(t,e),await this.mcpClient.start(),m.info("MCP\u5BA2\u6237\u7AEF\u5DF2\u542F\u52A8\uFF0C\u6B63\u5728\u8FDE\u63A5\u5230 xiaozhi.me")}else m.info("\u672A\u914D\u7F6EMCP\u7AEF\u70B9\uFF0C\u8DF3\u8FC7\u5BA2\u6237\u7AEF\u8FDE\u63A5")}async stop(){m.info("\u6B63\u5728\u505C\u6B62MCP\u670D\u52A1\u5668...");for(let e of this.clients.values())try{e.response.end()}catch{}this.clients.clear(),this.server&&(await new Promise(e=>{this.server.close(()=>e())}),this.server=null),this.mcpProxy&&(this.mcpProxy.kill("SIGTERM"),await new Promise(e=>{this.mcpProxy.on("exit",()=>e()),setTimeout(()=>{this.mcpProxy?.kill("SIGKILL"),e()},5e3)}),this.mcpProxy=null),this.mcpClient&&(this.mcpClient.shutdown(),this.mcpClient=null),this.mcpProxyPath=null,this.emit("stopped"),m.info("MCP\u670D\u52A1\u5668\u5DF2\u505C\u6B62")}}});import{spawn as $e}from"child_process";import{existsSync as re}from"fs";import{readFile as Ee}from"fs/promises";import{createServer as mt}from"http";import{dirname as ht,join as T}from"path";import{fileURLToPath as yt}from"url";import{serve as bt}from"@hono/node-server";import{Hono as Ct}from"hono";import{cors as St}from"hono/cors";import{WebSocketServer as vt}from"ws";import{spawn as ee}from"child_process";import b from"fs";import f from"path";import{fileURLToPath as $}from"url";import i from"chalk";import{Command as qe}from"commander";import P from"ora";M();import Fe from"omelette";function Ne(){try{if(!a.configExists())return[];let r=a.getMcpServers();return Object.keys(r)}catch{return[]}}p(Ne,"getMcpServerNames");function ze(r){try{if(!a.configExists())return[];let e=a.getServerToolsConfig(r);return Object.keys(e)}catch{return[]}}p(ze,"getServerToolNames");function ae(){let r=Fe("xiaozhi <command>");if(r.on("command",({reply:e})=>{e(["create","init","config","start","stop","status","attach","restart","mcp","completion"])}),r.on("complete",(e,{line:t,before:o,reply:n})=>{process.env.XIAOZHI_DEBUG_COMPLETION&&console.error(`Debug completion - line: "${t}", before: "${o}", fragment: "${e}"`);let s=t.trim().split(/\s+/),l=t!==t.trim()?s.length:s.length-1;if(s[1]==="mcp"){let u=s[2];if(l===2){let h=["list","server","tool"],y=s[2]||"",C=h.filter(S=>S.startsWith(y));n(C);return}if(l===3){switch(u){case"list":{let h=["--tools"],y=s[3]||"",C=h.filter(S=>S.startsWith(y));n(C);break}case"server":case"tool":{let h=Ne(),y=s[3]||"",C=h.filter(S=>S.startsWith(y));n(C);break}default:n([])}return}if(l===4&&u==="tool"){let h=s[3],y=ze(h),C=s[4]||"",S=y.filter(j=>j.startsWith(C));n(S);return}if(l===5&&u==="tool"){let h=["enable","disable"],y=s[5]||"",C=h.filter(S=>S.startsWith(y));n(C);return}}if(l===2){switch(s[1]){case"create":n(["--template","-t"]);break;case"start":case"restart":n(["--daemon","-d"]);break;case"completion":n(["install","uninstall"]);break;default:n([])}return}n([])}),process.argv.includes("--completion")){try{console.log(r.setupShellInitFile())}catch(e){console.error("\u751F\u6210\u81EA\u52A8\u8865\u5168\u811A\u672C\u65F6\u51FA\u9519:",e)}process.exit(0)}process.argv.includes("--completion-fish")&&(console.log(r.setupShellInitFile("fish")),process.exit(0)),process.argv.includes("--compzsh")||process.argv.includes("--compbash"),r.init()}p(ae,"setupAutoCompletion");function le(){console.log("\u{1F680} xiaozhi \u81EA\u52A8\u8865\u5168\u8BBE\u7F6E"),console.log(),console.log("\u8981\u542F\u7528\u81EA\u52A8\u8865\u5168\uFF0C\u8BF7\u6839\u636E\u4F60\u7684shell\u6267\u884C\u4EE5\u4E0B\u547D\u4EE4\uFF1A"),console.log(),console.log("\u{1F4DD} Zsh (\u63A8\u8350):"),console.log(" xiaozhi --completion >> ~/.xiaozhi-completion.zsh"),console.log(" echo 'source ~/.xiaozhi-completion.zsh' >> ~/.zshrc"),console.log(" source ~/.zshrc"),console.log(),console.log("\u{1F4DD} Bash:"),console.log(" xiaozhi --completion >> ~/.xiaozhi-completion.bash"),console.log(" echo 'source ~/.xiaozhi-completion.bash' >> ~/.bash_profile"),console.log(" source ~/.bash_profile"),console.log(),console.log("\u{1F4DD} Fish:"),console.log(" xiaozhi --completion-fish >> ~/.config/fish/completions/xiaozhi.fish"),console.log(),console.log("\u2728 \u8BBE\u7F6E\u5B8C\u6210\u540E\uFF0C\u4F60\u5C31\u53EF\u4EE5\u4F7F\u7528 Tab \u952E\u8FDB\u884C\u81EA\u52A8\u8865\u5168\u4E86\uFF01"),console.log(),console.log("\u{1F4A1} \u793A\u4F8B:"),console.log(" xiaozhi m<Tab> # \u2192 mcp"),console.log(" xiaozhi mcp l<Tab> # \u2192 list"),console.log(" xiaozhi mcp tool <Tab> # \u2192 \u663E\u793A\u6240\u6709\u670D\u52A1\u5668\u540D\u79F0")}p(le,"showCompletionHelp");M();W();M();import g from"chalk";import pe from"cli-table3";import K from"ora";function ge(r){let e=0;for(let t of r)/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(t)?e+=2:e+=1;return e}p(ge,"getDisplayWidth");function fe(r,e){if(ge(r)<=e)return r;if(e<=3)return"";let t="",o=0,n=!1;for(let s of r){let c=/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(s)?2:1;if(o+c>e-3){if(!n)return"";t+="...";break}t+=s,o+=c,n=!0}return t}p(fe,"truncateToWidth");async function de(r={}){let e=K("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868...").start();try{let t=a.getMcpServers(),o=Object.keys(t);if(o.length===0){e.warn("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1"),console.log(g.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi config' \u547D\u4EE4\u914D\u7F6E MCP \u670D\u52A1"));return}if(e.succeed(`\u627E\u5230 ${o.length} \u4E2A MCP \u670D\u52A1`),r.tools){console.log(),console.log(g.bold("MCP \u670D\u52A1\u5DE5\u5177\u5217\u8868:")),console.log();let n=8,s=[];for(let l of o){let u=a.getServerToolsConfig(l),h=Object.keys(u);s.push(...h)}for(let l of s){let u=ge(l);u>n&&(n=u)}n=Math.max(10,Math.min(n+2,30));let c=new pe({head:[g.bold("MCP"),g.bold("\u5DE5\u5177\u540D\u79F0"),g.bold("\u72B6\u6001"),g.bold("\u63CF\u8FF0")],colWidths:[15,n,8,40],wordWrap:!0,style:{head:[],border:[]}});for(let l of o){let u=a.getServerToolsConfig(l),h=Object.keys(u);if(h.length===0)c.push([g.gray(l),g.gray("-"),g.gray("-"),g.gray("\u6682\u672A\u8BC6\u522B\u5230\u76F8\u5173\u5DE5\u5177")]);else{c.length>0&&c.push([{colSpan:4,content:""}]);for(let y of h){let C=u[y],S=C.enable?g.green("\u542F\u7528"):g.red("\u7981\u7528"),j=fe(C.description||"",32);c.push([l,y,S,j])}}}console.log(c.toString())}else{console.log(),console.log(g.bold("MCP \u670D\u52A1\u5217\u8868:")),console.log();for(let n of o){let s=t[n],c=a.getServerToolsConfig(n),l=Object.keys(c).length,u=Object.values(c).filter(h=>h.enable!==!1).length;console.log(`${g.cyan("\u2022")} ${g.bold(n)}`),"url"in s?("type"in s&&s.type==="sse"?console.log(` \u7C7B\u578B: ${g.gray("SSE")}`):console.log(` \u7C7B\u578B: ${g.gray("Streamable HTTP")}`),console.log(` URL: ${g.gray(s.url)}`)):console.log(` \u547D\u4EE4: ${g.gray(s.command)} ${g.gray(s.args.join(" "))}`),l>0?console.log(` \u5DE5\u5177: ${g.green(u)} \u542F\u7528 / ${g.yellow(l)} \u603B\u8BA1`):console.log(` \u5DE5\u5177: ${g.gray("\u672A\u626B\u63CF (\u8BF7\u5148\u542F\u52A8\u670D\u52A1)")}`),console.log()}}console.log(g.gray("\u{1F4A1} \u63D0\u793A:")),console.log(g.gray(" - \u4F7F\u7528 'xiaozhi mcp list --tools' \u67E5\u770B\u6240\u6709\u5DE5\u5177")),console.log(g.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> list' \u67E5\u770B\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177")),console.log(g.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> <\u5DE5\u5177\u540D> enable/disable' \u542F\u7528/\u7981\u7528\u5DE5\u5177"))}catch(t){e.fail("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868\u5931\u8D25"),console.error(g.red(`\u9519\u8BEF: ${t instanceof Error?t.message:String(t)}`)),process.exit(1)}}p(de,"listMcpServers");async function ue(r){let e=K(`\u83B7\u53D6 ${r} \u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868...`).start();try{if(!a.getMcpServers()[r]){e.fail(`\u670D\u52A1 '${r}' \u4E0D\u5B58\u5728`),console.log(g.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let o=a.getServerToolsConfig(r),n=Object.keys(o);if(n.length===0){e.warn(`\u670D\u52A1 '${r}' \u6682\u65E0\u5DE5\u5177\u4FE1\u606F`),console.log(g.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u542F\u52A8\u670D\u52A1\u4EE5\u626B\u63CF\u5DE5\u5177\u5217\u8868"));return}e.succeed(`\u670D\u52A1 '${r}' \u5171\u6709 ${n.length} \u4E2A\u5DE5\u5177`),console.log(),console.log(g.bold(`${r} \u670D\u52A1\u5DE5\u5177\u5217\u8868:`)),console.log();let s=new pe({head:[g.bold("\u5DE5\u5177\u540D\u79F0"),g.bold("\u72B6\u6001"),g.bold("\u63CF\u8FF0")],colWidths:[30,8,50],wordWrap:!0,style:{head:[],border:[]}});for(let c of n){let l=o[c],u=l.enable?g.green("\u542F\u7528"):g.red("\u7981\u7528"),h=fe(l.description||"",40);s.push([c,u,h])}console.log(s.toString()),console.log(),console.log(g.gray("\u{1F4A1} \u63D0\u793A:")),console.log(g.gray(` - \u4F7F\u7528 'xiaozhi mcp ${r} <\u5DE5\u5177\u540D> enable' \u542F\u7528\u5DE5\u5177`)),console.log(g.gray(` - \u4F7F\u7528 'xiaozhi mcp ${r} <\u5DE5\u5177\u540D> disable' \u7981\u7528\u5DE5\u5177`))}catch(t){e.fail("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25"),console.error(g.red(`\u9519\u8BEF: ${t instanceof Error?t.message:String(t)}`)),process.exit(1)}}p(ue,"listServerTools");async function me(r,e,t){let o=t?"\u542F\u7528":"\u7981\u7528",n=K(`${o}\u5DE5\u5177 ${r}/${e}...`).start();try{if(!a.getMcpServers()[r]){n.fail(`\u670D\u52A1 '${r}' \u4E0D\u5B58\u5728`),console.log(g.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let c=a.getServerToolsConfig(r);if(!c[e]){n.fail(`\u5DE5\u5177 '${e}' \u5728\u670D\u52A1 '${r}' \u4E2D\u4E0D\u5B58\u5728`),console.log(g.yellow(`\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp ${r} list' \u67E5\u770B\u8BE5\u670D\u52A1\u7684\u6240\u6709\u5DE5\u5177`));return}a.setToolEnabled(r,e,t,c[e].description),n.succeed(`\u6210\u529F${o}\u5DE5\u5177 ${g.cyan(r)}/${g.cyan(e)}`),console.log(),console.log(g.gray("\u{1F4A1} \u63D0\u793A: \u5DE5\u5177\u72B6\u6001\u66F4\u6539\u5C06\u5728\u4E0B\u6B21\u542F\u52A8\u670D\u52A1\u65F6\u751F\u6548"))}catch(s){n.fail(`${o}\u5DE5\u5177\u5931\u8D25`),console.error(g.red(`\u9519\u8BEF: ${s instanceof Error?s.message:String(s)}`)),process.exit(1)}}p(me,"setToolEnabled");var v=new qe,Ke="xiaozhi-mcp-service";function Pe(){try{let r=$(import.meta.url),e=f.dirname(r),t=[f.join(e,"..","package.json"),f.join(e,"..","package.json"),f.join(e,"..","..","package.json"),f.join(e,"package.json")];for(let o of t)if(b.existsSync(o)){let n=JSON.parse(b.readFileSync(o,"utf8"));if(n.version)return n.version}return"unknown"}catch(r){return console.warn("\u65E0\u6CD5\u4ECE package.json \u8BFB\u53D6\u7248\u672C\u4FE1\u606F:",r),"unknown"}}p(Pe,"getVersion");var oe=p(()=>{let r=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return f.join(r,`.${Ke}.pid`)},"getPidFile");function E(){try{let r=oe();if(!b.existsSync(r))return{running:!1};let e=b.readFileSync(r,"utf8").trim(),[t,o,n]=e.split("|"),s=Number.parseInt(t);if(Number.isNaN(s))return b.unlinkSync(r),{running:!1};try{process.kill(s,0);let c=Number.parseInt(o),l=Ye(Date.now()-c);return{running:!0,pid:s,uptime:l,mode:n||"foreground"}}catch{return b.unlinkSync(r),{running:!1}}}catch{return{running:!1}}}p(E,"getServiceStatus");function Ye(r){let e=Math.floor(r/1e3),t=Math.floor(e/60),o=Math.floor(t/60),n=Math.floor(o/24);return n>0?`${n}\u5929 ${o%24}\u5C0F\u65F6 ${t%60}\u5206\u949F`:o>0?`${o}\u5C0F\u65F6 ${t%60}\u5206\u949F`:t>0?`${t}\u5206\u949F ${e%60}\u79D2`:`${e}\u79D2`}p(Ye,"formatUptime");function te(r,e){let t=`${r}|${Date.now()}|${e}`;b.writeFileSync(oe(),t)}p(te,"savePidInfo");function z(){try{let r=oe();b.existsSync(r)&&b.unlinkSync(r)}catch{}}p(z,"cleanupPidFile");function Qe(){if(!a.configExists())return console.error(i.red("\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728")),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E')),!1;try{let e=a.getMcpEndpoints().filter(t=>t&&!t.includes("<\u8BF7\u586B\u5199"));return e.length===0?(console.log(i.yellow("\u26A0\uFE0F \u8B66\u544A: MCP \u7AEF\u70B9\u672A\u914D\u7F6E")),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u670D\u52A1\u5C06\u542F\u52A8\u4F46\u65E0\u6CD5\u8FDE\u63A5\u5C0F\u667A\u670D\u52A1\u7AEF\uFF0C\u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9')),console.log(i.gray(" MCP \u670D\u52A1\u5668\u529F\u80FD\u4ECD\u7136\u53EF\u7528\uFF0C\u53EF\u901A\u8FC7 Web \u754C\u9762\u914D\u7F6E\u7AEF\u70B9\u540E\u91CD\u542F\u670D\u52A1"))):console.log(i.green(`\u2705 \u5DF2\u914D\u7F6E ${e.length} \u4E2A\u6709\u6548\u7684 MCP \u7AEF\u70B9`)),!0}catch(r){return console.error(i.red(`\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u65E0\u6548 - ${r instanceof Error?r.message:String(r)}`)),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u91CD\u65B0\u521D\u59CB\u5316\u914D\u7F6E')),!1}}p(Qe,"checkEnvironment");function et(){let r=f.dirname($(import.meta.url)),e;return r.includes("js-demo/dist")?e=r:e=[f.join(r,"..","js-demo","dist"),f.join(r,"..","..","js-demo","dist"),f.join(r,"..","..","..","js-demo","dist"),f.join(process.cwd(),"js-demo","dist"),f.join(process.cwd(),"dist")].find(o=>b.existsSync(f.join(o,"adaptiveMCPPipe.js"))&&b.existsSync(f.join(o,"mcpServerProxy.js")))||r,{command:"node",args:["adaptiveMCPPipe.js","mcpServerProxy.js"],cwd:e}}p(et,"getServiceCommand");async function ve(){try{if(!a.configExists()){console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7 Web UI \u542F\u52A8"));return}let r=new D;await r.start();let e=a.getWebUIPort();console.log(i.green("\u2705 Web UI \u5DF2\u542F\u52A8\uFF0C\u53EF\u901A\u8FC7\u4EE5\u4E0B\u5730\u5740\u8BBF\u95EE:")),console.log(i.green(` \u672C\u5730\u8BBF\u95EE: http://localhost:${e}`)),console.log(i.green(` \u7F51\u7EDC\u8BBF\u95EE: http://<\u4F60\u7684IP\u5730\u5740>:${e}`));let{spawn:t}=await import("child_process"),o=`http://localhost:${e}`;try{let n;process.platform==="darwin"?n=t("open",[o],{detached:!0,stdio:"ignore"}):process.platform==="win32"?n=t("cmd",["/c","start",o],{detached:!0,stdio:"ignore"}):n=t("xdg-open",[o],{detached:!0,stdio:"ignore"}),n.on("error",()=>{console.log(i.gray(`\u{1F4A1} \u63D0\u793A: \u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE: ${o}`))}),n.unref()}catch{console.log(i.gray(`\u{1F4A1} \u63D0\u793A: \u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE: ${o}`))}global.__webServer=r}catch(r){console.log(i.yellow(`\u26A0\uFE0F Web UI \u542F\u52A8\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`))}}p(ve,"startWebUIInBackground");async function Ie(r=!1,e=!1){let t=P("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let o=E();if(o.running){t.fail(`\u670D\u52A1\u5DF2\u7ECF\u5728\u8FD0\u884C (PID: ${o.pid})`);return}if(t.text="\u68C0\u67E5\u73AF\u5883\u914D\u7F6E...",!Qe()){t.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}let{command:n,args:s,cwd:c}=et();if(t.text=`\u542F\u52A8\u670D\u52A1 (${r?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,r){let l=ee(n,s,{cwd:c,detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true"}});te(l.pid,"daemon");let u=process.cwd();I.initLogFile(u),I.enableFileLogging(!0);let h=f.join(u,"xiaozhi.log"),y=b.createWriteStream(h,{flags:"a"});l.stdout?.pipe(y),l.stderr?.pipe(y),l.on("exit",(C,S)=>{C!==0&&C!==null&&I.error(`\u540E\u53F0\u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${C}, \u4FE1\u53F7: ${S})`),z()}),l.on("error",C=>{I.error(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u9519\u8BEF: ${C.message}`),z(),t.fail(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u5931\u8D25: ${C.message}`)}),l.unref(),t.succeed(`\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${l.pid})`),console.log(i.gray(`\u65E5\u5FD7\u6587\u4EF6: ${h}`)),console.log(i.gray("\u4F7F\u7528 'xiaozhi attach' \u53EF\u4EE5\u67E5\u770B\u5B9E\u65F6\u65E5\u5FD7")),e&&await ve()}else{t.succeed("\u670D\u52A1\u542F\u52A8\u4E2D...");let l=ee(n,s,{cwd:c,stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.FORCE_CONFIG_DIR||process.cwd()}});te(l.pid,"foreground"),l.on("exit",(u,h)=>{z(),console.log(u!==0?i.red(`
15
+ \u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${u}, \u4FE1\u53F7: ${h})`):i.green(`
16
+ \u670D\u52A1\u5DF2\u505C\u6B62`))}),e&&setTimeout(()=>{ve()},1e3),process.on("SIGINT",async()=>{if(console.log(i.yellow(`
17
+ \u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),l.kill("SIGTERM"),global.__webServer)try{await global.__webServer.stop(),console.log(i.green("Web UI \u5DF2\u505C\u6B62"))}catch{}}),process.on("SIGTERM",async()=>{if(l.kill("SIGTERM"),global.__webServer)try{await global.__webServer.stop()}catch{}})}}catch(o){t.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}p(Ie,"startService");async function xe(){let r=P("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=E();if(!e.running){r.warn("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}r.text=`\u505C\u6B62\u670D\u52A1 (PID: ${e.pid})...`;try{process.kill(e.pid,"SIGTERM");let t=0,o=30;for(;t<o;){await new Promise(n=>setTimeout(n,100));try{process.kill(e.pid,0),t++}catch{break}}try{process.kill(e.pid,0),r.text="\u5F3A\u5236\u505C\u6B62\u670D\u52A1...",process.kill(e.pid,"SIGKILL"),await new Promise(n=>setTimeout(n,500))}catch{}z(),r.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(t){z(),r.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}catch(e){r.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}p(xe,"stopService");async function tt(){let r=P("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=E();if(e.running){if(r.succeed("\u670D\u52A1\u72B6\u6001"),console.log(i.green("\u2705 \u670D\u52A1\u6B63\u5728\u8FD0\u884C")),console.log(i.gray(` PID: ${e.pid}`)),console.log(i.gray(` \u8FD0\u884C\u65F6\u95F4: ${e.uptime}`)),console.log(i.gray(` \u8FD0\u884C\u6A21\u5F0F: ${e.mode==="daemon"?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"}`)),e.mode==="daemon"){let t=f.join(process.cwd(),"xiaozhi.log");console.log(i.gray(` \u65E5\u5FD7\u6587\u4EF6: ${t}`))}}else r.succeed("\u670D\u52A1\u72B6\u6001"),console.log(i.red("\u274C \u670D\u52A1\u672A\u8FD0\u884C"))}catch(e){r.fail(`\u68C0\u67E5\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}p(tt,"checkStatus");async function ot(){let r=P("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=E();if(!e.running){r.fail("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}if(e.mode!=="daemon"){r.fail("\u670D\u52A1\u4E0D\u662F\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C");return}r.succeed("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1..."),console.log(i.green(`\u5DF2\u8FDE\u63A5\u5230\u670D\u52A1 (PID: ${e.pid})`)),console.log(i.gray("\u6309 Ctrl+C \u53EF\u4EE5\u65AD\u5F00\u8FDE\u63A5\uFF08\u4E0D\u4F1A\u505C\u6B62\u670D\u52A1\uFF09")),console.log(i.gray("=".repeat(50)));let t=f.join(process.cwd(),"xiaozhi.log");if(b.existsSync(t))if(process.platform==="win32"){let{spawn:o}=await import("child_process"),n=o("powershell",["-Command",`Get-Content -Path "${t}" -Wait`],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(i.yellow(`
18
+ \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),n.kill(),process.exit(0)}),n.on("exit",()=>{process.exit(0)})}else{let{spawn:o}=await import("child_process"),n=o("tail",["-f",t],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(i.yellow(`
19
+ \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),n.kill(),process.exit(0)}),n.on("exit",()=>{process.exit(0)})}else console.log(i.yellow("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728"))}catch(e){r.fail(`\u8FDE\u63A5\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}p(ot,"attachService");async function nt(r=!1,e=!1){console.log(i.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await xe(),await new Promise(t=>setTimeout(t,1e3)),await Ie(r,e)}p(nt,"restartService");async function rt(r,e=!1){let t=P("\u542F\u52A8 MCP Server \u6A21\u5F0F...").start();try{if(!a.configExists()){t.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}let{MCPServer:o}=await Promise.resolve().then(()=>(Se(),Ce));if(e){let n=$(import.meta.url),s=f.dirname(n),c=ee("node",[f.join(s,"cli.js"),"start","--server",r.toString()],{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true",MCP_SERVER_MODE:"true"}});te(c.pid,"daemon");let l=f.join(process.cwd(),"xiaozhi-mcp-server.log"),u=b.createWriteStream(l,{flags:"a"});c.stdout?.pipe(u),c.stderr?.pipe(u),c.unref(),t.succeed(`MCP Server \u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${c.pid}, Port: ${r})`),console.log(i.gray(`\u65E5\u5FD7\u6587\u4EF6: ${l}`))}else{let n=new o(r),s=p(async()=>{console.log(i.yellow(`
20
+ \u6B63\u5728\u505C\u6B62 MCP Server...`)),await n.stop(),process.exit(0)},"cleanup");process.on("SIGINT",s),process.on("SIGTERM",s),await n.start(),t.succeed("MCP Server \u5DF2\u542F\u52A8"),console.log(i.green("\u2705 MCP Server \u7AEF\u70B9\u5DF2\u542F\u52A8\uFF0C\u53EF\u901A\u8FC7\u4EE5\u4E0B\u5730\u5740\u8BBF\u95EE:")),console.log(i.green(` SSE endpoint: http://localhost:${r}/sse`)),console.log(i.green(` Messages endpoint: http://localhost:${r}/messages`)),console.log(i.green(` RPC endpoint: http://localhost:${r}/rpc`)),console.log(i.green(" \u7F51\u7EDC\u8BBF\u95EE: \u5C06 localhost \u66FF\u6362\u4E3A\u4F60\u7684IP\u5730\u5740")),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1"))}}catch(o){t.fail(`\u542F\u52A8 MCP Server \u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}p(rt,"startMCPServerMode");function st(){let r=Pe();console.log(i.blue(`xiaozhi v${r}`)),console.log(i.gray("MCP Calculator Service CLI Tool")),console.log(i.gray("Built with Node.js and TypeScript")),console.log(i.gray(`Node.js: ${process.version}`)),console.log(i.gray(`Platform: ${process.platform} ${process.arch}`))}p(st,"showDetailedInfo");async function it(r="json"){let e=P("\u521D\u59CB\u5316\u914D\u7F6E...").start();try{if(a.configExists()){e.warn("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728"),console.log(i.yellow("\u5982\u9700\u91CD\u65B0\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u5220\u9664\u73B0\u6709\u7684\u914D\u7F6E\u6587\u4EF6"));return}a.initConfig(r),e.succeed("\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u6210\u529F");let t=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),o=`xiaozhi.config.${r}`,n=f.join(t,o);console.log(i.green(`\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u521B\u5EFA: ${o}`)),console.log(i.yellow("\u{1F4DD} \u8BF7\u7F16\u8F91\u914D\u7F6E\u6587\u4EF6\u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9:")),console.log(i.gray(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${n}`)),console.log(i.yellow("\u{1F4A1} \u6216\u8005\u4F7F\u7528\u547D\u4EE4\u8BBE\u7F6E:")),console.log(i.gray(" xiaozhi config mcpEndpoint <your-endpoint-url>"))}catch(t){e.fail(`\u521D\u59CB\u5316\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}p(it,"initConfig");function ct(){let r=f.dirname($(import.meta.url)),t=[f.join(r,"..","templates"),f.join(r,"templates"),f.join(r,"..","..","templates")].find(o=>b.existsSync(o));return t?b.readdirSync(t).filter(o=>{let n=f.join(t,o);return b.statSync(n).isDirectory()}):[]}p(ct,"getAvailableTemplates");function we(r,e){let t=r.length,o=e.length,n=Array(t+1).fill(null).map(()=>Array(o+1).fill(0));for(let c=0;c<=t;c++)n[c][0]=c;for(let c=0;c<=o;c++)n[0][c]=c;for(let c=1;c<=t;c++)for(let l=1;l<=o;l++)r[c-1]===e[l-1]?n[c][l]=n[c-1][l-1]:n[c][l]=Math.min(n[c-1][l]+1,n[c][l-1]+1,n[c-1][l-1]+1);let s=Math.max(t,o);return s===0?1:(s-n[t][o])/s}p(we,"calculateSimilarity");function at(r,e){if(e.length===0)return null;let t=e[0],o=we(r.toLowerCase(),t.toLowerCase());for(let n of e.slice(1)){let s=we(r.toLowerCase(),n.toLowerCase());s>o&&(o=s,t=n)}return o>.5?t:null}p(at,"findSimilarTemplate");async function lt(r){if(!process.stdin.isTTY)return console.log("n (\u975E\u4EA4\u4E92\u5F0F\u73AF\u5883)"),!1;let e=await import("readline");return new Promise(t=>{process.stdout.write(r);let o=e.createInterface({input:process.stdin,output:process.stdout}),n=p(s=>{let c=s.trim().toLowerCase();c==="y"||c==="yes"?(o.close(),t(!0)):c==="n"||c==="no"||c===""?(o.close(),t(!1)):process.stdout.write("\u8BF7\u8F93\u5165 y \u6216 n: ")},"handleInput");o.on("line",n),o.on("SIGINT",()=>{o.close(),t(!1)})})}p(lt,"askUserConfirmation");function pt(r){let e={mcpEndpoint:"<\u8BF7\u586B\u5199\u4F60\u7684\u63A5\u5165\u70B9\u5730\u5740\uFF08\u83B7\u53D6\u5730\u5740\u5728 xiaozhi.me\uFF09>",mcpServers:{}},t=f.join(r,"xiaozhi.config.json");b.writeFileSync(t,JSON.stringify(e,null,2),"utf8")}p(pt,"createBasicConfig");async function gt(r,e){let t=P("\u521D\u59CB\u5316\u9879\u76EE...").start();try{let o=f.join(process.cwd(),r);if(b.existsSync(o)){t.fail(`\u76EE\u5F55 "${r}" \u5DF2\u5B58\u5728`),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u9009\u62E9\u4E0D\u540C\u7684\u9879\u76EE\u540D\u79F0\u6216\u5220\u9664\u73B0\u6709\u76EE\u5F55"));return}if(e.template){t.text="\u68C0\u67E5\u6A21\u677F...";let n=ct();if(n.length===0){t.fail("\u627E\u4E0D\u5230 templates \u76EE\u5F55"),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u786E\u4FDD xiaozhi-client \u6B63\u786E\u5B89\u88C5"));return}if(!n.includes(e.template)){t.fail(`\u6A21\u677F "${e.template}" \u4E0D\u5B58\u5728`);let y=at(e.template,n);if(y)if(console.log(i.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${y}" \u5417\uFF1F`)),await lt(i.cyan("\u786E\u8BA4\u4F7F\u7528\u6B64\u6A21\u677F\uFF1F(y/n): ")))e.template=y;else{console.log(i.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let S of n)console.log(i.gray(` - ${S}`));return}else{console.log(i.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let C of n)console.log(i.gray(` - ${C}`));return}}let s=f.dirname($(import.meta.url)),l=[f.join(s,"..","templates"),f.join(s,"templates"),f.join(s,"..","..","templates")].find(y=>b.existsSync(y)),u=f.join(l,e.template);t.text=`\u4ECE\u6A21\u677F "${e.template}" \u521B\u5EFA\u9879\u76EE "${r}"...`,Me(u,o,["node_modules",".pnpm-debug.log","pnpm-lock.yaml"]);let h=f.join(o,"xiaozhi.log");b.existsSync(h)||b.writeFileSync(h,"","utf8"),t.succeed(`\u9879\u76EE "${r}" \u521B\u5EFA\u6210\u529F`),console.log(i.green("\u2705 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(i.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(i.gray(` cd ${r}`)),console.log(i.gray(" pnpm install # \u5B89\u88C5\u4F9D\u8D56")),console.log(i.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9")),console.log(i.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1"))}else{t.text=`\u521B\u5EFA\u57FA\u672C\u9879\u76EE "${r}"...`,b.mkdirSync(o,{recursive:!0}),pt(o);let n=f.join(o,"xiaozhi.log");b.writeFileSync(n,"","utf8"),t.succeed(`\u9879\u76EE "${r}" \u521B\u5EFA\u6210\u529F`),console.log(i.green("\u2705 \u57FA\u672C\u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(i.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(i.gray(` cd ${r}`)),console.log(i.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9\u548C\u670D\u52A1")),console.log(i.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1")),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 --template \u9009\u9879\u53EF\u4EE5\u4ECE\u6A21\u677F\u521B\u5EFA\u9879\u76EE"))}}catch(o){t.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}p(gt,"createProject");function Me(r,e,t=[]){b.existsSync(e)||b.mkdirSync(e,{recursive:!0});let o=b.readdirSync(r);for(let n of o){if(t.some(u=>n.includes(u)))continue;let s=f.join(r,n),c=f.join(e,n);b.statSync(s).isDirectory()?Me(s,c,t):b.copyFileSync(s,c)}}p(Me,"copyDirectory");async function ft(){let r=P("\u542F\u52A8 UI \u670D\u52A1...").start();try{if(!a.configExists()){r.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}let e=new D;await e.start(),r.succeed("UI \u670D\u52A1\u5DF2\u542F\u52A8");let t=a.getWebUIPort();console.log(i.green("\u2705 \u914D\u7F6E\u7BA1\u7406\u7F51\u9875\u5DF2\u542F\u52A8\uFF0C\u53EF\u901A\u8FC7\u4EE5\u4E0B\u5730\u5740\u8BBF\u95EE:")),console.log(i.green(` \u672C\u5730\u8BBF\u95EE: http://localhost:${t}`)),console.log(i.green(` \u7F51\u7EDC\u8BBF\u95EE: http://<\u4F60\u7684IP\u5730\u5740>:${t}`)),console.log(i.yellow("\u{1F4A1} \u63D0\u793A: \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1"));let{spawn:o}=await import("child_process"),n=`http://localhost:${t}`;try{let c;process.platform==="darwin"?c=o("open",[n],{detached:!0,stdio:"ignore"}):process.platform==="win32"?c=o("cmd",["/c","start",n],{detached:!0,stdio:"ignore"}):c=o("xdg-open",[n],{detached:!0,stdio:"ignore"}),c.on("error",()=>{console.log(i.gray(`\u{1F4A1} \u63D0\u793A: \u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE: ${n}`))}),c.unref()}catch{console.log(i.gray(`\u{1F4A1} \u63D0\u793A: \u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE: ${n}`))}let s=!1;process.on("SIGINT",async()=>{s&&(console.log(i.red(`
21
21
  \u5F3A\u5236\u9000\u51FA...`)),process.exit(1)),s=!0,console.log(i.yellow(`
22
- \u6B63\u5728\u505C\u6B62 UI \u670D\u52A1...`));try{await e.stop(),console.log(i.green("UI \u670D\u52A1\u5DF2\u505C\u6B62"))}catch{console.log(i.red("\u505C\u6B62\u670D\u52A1\u65F6\u51FA\u9519\uFF0C\u5F3A\u5236\u9000\u51FA"))}process.exit(0)}),process.on("SIGTERM",async()=>{s=!0,await e.stop(),process.exit(0)})}catch(e){r.fail(`\u542F\u52A8 UI \u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}g(co,"startUIService");async function ao(r,e){let o=P("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!l.configExists()){o.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}if(e)switch(r){case"mcpEndpoint":l.updateMcpEndpoint(e),o.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${e}`);break;case"heartbeatInterval":{let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0){o.fail("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}l.setHeartbeatInterval(t),o.succeed(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}case"heartbeatTimeout":{let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0){o.fail("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}l.setHeartbeatTimeout(t),o.succeed(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}case"reconnectInterval":{let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0){o.fail("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}l.setReconnectInterval(t),o.succeed(`\u91CD\u8FDE\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}default:o.fail(`\u914D\u7F6E\u9879 ${r} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(i.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}else{o.text="\u8BFB\u53D6\u914D\u7F6E...";let t=l.getConfig();switch(r){case"mcpEndpoint":{o.succeed("\u914D\u7F6E\u4FE1\u606F");let n=l.getMcpEndpoints();n.length===0?console.log(i.yellow("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9")):n.length===1?console.log(i.green(`MCP \u7AEF\u70B9: ${n[0]}`)):(console.log(i.green(`MCP \u7AEF\u70B9 (${n.length} \u4E2A):`)),n.forEach((s,c)=>{console.log(i.gray(` ${c+1}. ${s}`))}));break}case"mcpServers":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green("MCP \u670D\u52A1:"));for(let[n,s]of Object.entries(t.mcpServers))"type"in s&&s.type==="sse"?console.log(i.gray(` ${n}: [SSE] ${s.url}`)):console.log(i.gray(` ${n}: ${s.command} ${s.args.join(" ")}`));break;case"connection":{o.succeed("\u914D\u7F6E\u4FE1\u606F");let n=l.getConnectionConfig();console.log(i.green("\u8FDE\u63A5\u914D\u7F6E:")),console.log(i.gray(` \u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${n.heartbeatInterval}ms`)),console.log(i.gray(` \u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${n.heartbeatTimeout}ms`)),console.log(i.gray(` \u91CD\u8FDE\u95F4\u9694: ${n.reconnectInterval}ms`));break}case"heartbeatInterval":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${l.getHeartbeatInterval()}ms`));break;case"heartbeatTimeout":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${l.getHeartbeatTimeout()}ms`));break;case"reconnectInterval":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u91CD\u8FDE\u95F4\u9694: ${l.getReconnectInterval()}ms`));break;default:o.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${r}`),console.log(i.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers, connection, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}}}catch(t){o.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(ao,"configCommand");function lo(){console.log(i.blue.bold("xiaozhi - MCP Calculator Service CLI")),console.log(),console.log(i.yellow("\u4F7F\u7528\u65B9\u6CD5:")),console.log(" xiaozhi <command> [options]"),console.log(),console.log(i.yellow("\u547D\u4EE4:")),console.log(" create <projectName> \u521B\u5EFA\u9879\u76EE"),console.log(" init \u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6"),console.log(" config <key> [value] \u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E"),console.log(" start [--daemon] [--ui] [--server] \u542F\u52A8\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C, --ui \u540C\u65F6\u542F\u52A8 Web UI, --server MCP Server \u6A21\u5F0F)"),console.log(" stop \u505C\u6B62\u670D\u52A1"),console.log(" status \u68C0\u67E5\u670D\u52A1\u72B6\u6001"),console.log(" attach \u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7"),console.log(" restart [--daemon] [--ui] \u91CD\u542F\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C, --ui \u540C\u65F6\u542F\u52A8 Web UI)"),console.log(" ui \u542F\u52A8\u914D\u7F6E\u7BA1\u7406\u7F51\u9875"),console.log(" completion \u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E"),console.log(),console.log(i.yellow("\u9009\u9879:")),console.log(" -v, --version \u663E\u793A\u7248\u672C\u4FE1\u606F"),console.log(" -V \u663E\u793A\u8BE6\u7EC6\u4FE1\u606F"),console.log(" -h, --help \u663E\u793A\u5E2E\u52A9\u4FE1\u606F"),console.log(" -t, --template <name> \u6307\u5B9A\u6A21\u677F\u540D\u79F0\uFF08\u7528\u4E8E create \u547D\u4EE4\uFF09"),console.log(),console.log(i.yellow("\u9879\u76EE\u793A\u4F8B:")),console.log(" xiaozhi create my-app # \u521B\u5EFA\u57FA\u672C\u9879\u76EE"),console.log(" xiaozhi create my-app -t hello-world # \u4F7F\u7528 hello-world \u6A21\u677F"),console.log(" xiaozhi create my-app --template hello-world # \u540C\u4E0A\uFF0C\u5B8C\u6574\u9009\u9879\u540D"),console.log(),console.log(i.yellow("\u914D\u7F6E\u793A\u4F8B:")),console.log(" xiaozhi init # \u521D\u59CB\u5316\u914D\u7F6E"),console.log(" xiaozhi config mcpEndpoint # \u67E5\u770B MCP \u7AEF\u70B9"),console.log(" xiaozhi config mcpEndpoint wss://... # \u8BBE\u7F6E MCP \u7AEF\u70B9"),console.log(),console.log(i.yellow("\u670D\u52A1\u793A\u4F8B:")),console.log(" xiaozhi start # \u524D\u53F0\u542F\u52A8\u670D\u52A1"),console.log(" xiaozhi start --daemon # \u540E\u53F0\u542F\u52A8\u670D\u52A1"),console.log(" xiaozhi start --ui # \u542F\u52A8\u670D\u52A1\u5E76\u540C\u65F6\u542F\u52A8 Web UI"),console.log(" xiaozhi start -d -u # \u540E\u53F0\u542F\u52A8\u670D\u52A1\u5E76\u540C\u65F6\u542F\u52A8 Web UI"),console.log(" xiaozhi start --server # \u4EE5 MCP Server \u6A21\u5F0F\u542F\u52A8 (\u7AEF\u53E3 3000)"),console.log(" xiaozhi start -s 8080 # \u4EE5 MCP Server \u6A21\u5F0F\u542F\u52A8 (\u7AEF\u53E3 8080)"),console.log(" xiaozhi start -s -d # \u540E\u53F0\u8FD0\u884C MCP Server"),console.log(" xiaozhi status # \u68C0\u67E5\u670D\u52A1\u72B6\u6001"),console.log(" xiaozhi attach # \u67E5\u770B\u540E\u53F0\u670D\u52A1\u65E5\u5FD7"),console.log(" xiaozhi stop # \u505C\u6B62\u670D\u52A1"),console.log(),console.log(i.yellow("MCP \u7BA1\u7406\u793A\u4F8B:")),console.log(" xiaozhi mcp list # \u5217\u51FA\u6240\u6709 MCP \u670D\u52A1"),console.log(" xiaozhi mcp list --tools # \u5217\u51FA\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177"),console.log(" xiaozhi mcp server <name> # \u5217\u51FA\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177"),console.log(" xiaozhi mcp tool <server> <tool> enable # \u542F\u7528\u5DE5\u5177"),console.log(" xiaozhi mcp tool <server> <tool> disable # \u7981\u7528\u5DE5\u5177"),console.log(),console.log(i.yellow("\u81EA\u52A8\u8865\u5168:")),console.log(" xiaozhi completion # \u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E"),console.log(" # \u8BBE\u7F6E\u540E\u53EF\u4F7F\u7528 Tab \u952E\u8FDB\u884C\u547D\u4EE4\u3001\u53C2\u6570\u81EA\u52A8\u8865\u5168")}g(lo,"showHelp");v.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(be(),"-v, --version","\u663E\u793A\u7248\u672C\u4FE1\u606F").helpOption("-h, --help","\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");v.command("create <projectName>").description("\u521B\u5EFA\u9879\u76EE").option("-t, --template <templateName>","\u4F7F\u7528\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u9879\u76EE").action(async(r,e)=>{await io(r,e)});v.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").option("-f, --format <format>","\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F (json, json5, jsonc)","json").action(async r=>{let e=r.format;e!=="json"&&e!=="json5"&&e!=="jsonc"&&(console.error(i.red("\u9519\u8BEF: \u683C\u5F0F\u5FC5\u987B\u662F json, json5 \u6216 jsonc")),process.exit(1)),await oo(e)});v.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(r,e)=>{await ao(r,e)});v.command("start").description("\u542F\u52A8\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").option("-u, --ui","\u540C\u65F6\u542F\u52A8 Web UI \u670D\u52A1").option("-s, --server [port]","\u4EE5 MCP Server \u6A21\u5F0F\u542F\u52A8 (\u53EF\u9009\u6307\u5B9A\u7AEF\u53E3\uFF0C\u9ED8\u8BA4 3000)").option("--stdio","\u4EE5 stdio \u6A21\u5F0F\u8FD0\u884C MCP Server (\u7528\u4E8E Cursor \u7B49\u5BA2\u6237\u7AEF)").action(async r=>{if(r.stdio){let{spawn:e}=await import("child_process"),o=$(import.meta.url),t=f.dirname(o),n=f.join(t,"mcpServerProxy.js");e("node",[n],{stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}})}else if(r.server){let e=typeof r.server=="string"?Number.parseInt(r.server):3e3;await Qe(e,r.daemon)}else await Se(r.daemon,r.ui)});v.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await ve()});v.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await Ke()});v.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await Ye()});v.command("restart").description("\u91CD\u542F\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").option("-u, --ui","\u540C\u65F6\u542F\u52A8 Web UI \u670D\u52A1").action(async r=>{await qe(r.daemon,r.ui)});var ee=v.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");ee.command("list").description("\u5217\u51FA MCP \u670D\u52A1").option("--tools","\u663E\u793A\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868").action(async r=>{await le(r)});ee.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async r=>{await ge(r)});ee.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(r,e,o)=>{o!=="enable"&&o!=="disable"&&(console.error(i.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await pe(r,e,o==="enable")});var J=v.command("endpoint").description("\u7BA1\u7406 MCP \u7AEF\u70B9");J.command("list").description("\u5217\u51FA\u6240\u6709 MCP \u7AEF\u70B9").action(async()=>{let r=P("\u8BFB\u53D6\u7AEF\u70B9\u914D\u7F6E...").start();try{let e=l.getMcpEndpoints();r.succeed("\u7AEF\u70B9\u5217\u8868"),e.length===0?console.log(i.yellow("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9")):(console.log(i.green(`\u5171 ${e.length} \u4E2A\u7AEF\u70B9:`)),e.forEach((o,t)=>{console.log(i.gray(` ${t+1}. ${o}`))}))}catch(e){r.fail(`\u8BFB\u53D6\u7AEF\u70B9\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}});J.command("add <url>").description("\u6DFB\u52A0\u65B0\u7684 MCP \u7AEF\u70B9").action(async r=>{let e=P("\u6DFB\u52A0\u7AEF\u70B9...").start();try{l.addMcpEndpoint(r),e.succeed(`\u6210\u529F\u6DFB\u52A0\u7AEF\u70B9: ${r}`);let o=l.getMcpEndpoints();console.log(i.gray(`\u5F53\u524D\u5171 ${o.length} \u4E2A\u7AEF\u70B9`))}catch(o){e.fail(`\u6DFB\u52A0\u7AEF\u70B9\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}});J.command("remove <url>").description("\u79FB\u9664\u6307\u5B9A\u7684 MCP \u7AEF\u70B9").action(async r=>{let e=P("\u79FB\u9664\u7AEF\u70B9...").start();try{l.removeMcpEndpoint(r),e.succeed(`\u6210\u529F\u79FB\u9664\u7AEF\u70B9: ${r}`);let o=l.getMcpEndpoints();console.log(i.gray(`\u5F53\u524D\u5269\u4F59 ${o.length} \u4E2A\u7AEF\u70B9`))}catch(o){e.fail(`\u79FB\u9664\u7AEF\u70B9\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}});J.command("set <urls...>").description("\u8BBE\u7F6E MCP \u7AEF\u70B9\uFF08\u53EF\u4EE5\u662F\u5355\u4E2A\u6216\u591A\u4E2A\uFF09").action(async r=>{let e=P("\u8BBE\u7F6E\u7AEF\u70B9...").start();try{if(r.length===1)l.updateMcpEndpoint(r[0]),e.succeed(`\u6210\u529F\u8BBE\u7F6E\u7AEF\u70B9: ${r[0]}`);else{l.updateMcpEndpoint(r),e.succeed(`\u6210\u529F\u8BBE\u7F6E ${r.length} \u4E2A\u7AEF\u70B9`);for(let[o,t]of r.entries())console.log(i.gray(` ${o+1}. ${t}`))}}catch(o){e.fail(`\u8BBE\u7F6E\u7AEF\u70B9\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}});v.command("ui").description("\u542F\u52A8\u914D\u7F6E\u7BA1\u7406\u7F51\u9875").action(async()=>{await co()});v.command("completion").description("\u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E").action(async()=>{se()});v.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(r=>{r.V&&(eo(),process.exit(0))});re();process.argv.length<=2&&(lo(),process.exit(0));v.parse(process.argv);E();A();var F=class{static{g(this,"WebServer")}httpServer;wss;logger;port;clientInfo={status:"disconnected",mcpEndpoint:"",activeMCPServers:[]};heartbeatTimeout;HEARTBEAT_TIMEOUT=35e3;constructor(e){if(e===void 0)try{this.port=l.getWebUIPort()}catch{this.port=9999}else this.port=e;this.logger=new k,this.httpServer=go((o,t)=>{this.handleHttpRequest(o,t)}),this.wss=new ho({server:this.httpServer}),this.setupWebSocket()}async handleHttpRequest(e,o){let{pathname:t}=fo(e.url||"",!0);if(o.setHeader("Access-Control-Allow-Origin","*"),o.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, OPTIONS"),o.setHeader("Access-Control-Allow-Headers","Content-Type"),e.method==="OPTIONS"){o.writeHead(200),o.end();return}try{if(e.method==="GET"&&!t?.startsWith("/api/")){await this.serveStaticFile(t||"/",o);return}if(t==="/api/config"&&e.method==="GET"){let n=l.getConfig();o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify(n))}else if(t==="/api/config"&&e.method==="PUT"){let n="";e.on("data",s=>{n+=s.toString()}),e.on("end",async()=>{try{let s=JSON.parse(n);this.updateConfig(s),this.broadcastConfigUpdate(s),o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify({success:!0})),this.logger.info("\u914D\u7F6E\u5DF2\u66F4\u65B0")}catch(s){o.writeHead(400,{"Content-Type":"application/json"}),o.end(JSON.stringify({error:s instanceof Error?s.message:String(s)}))}})}else t==="/api/status"&&e.method==="GET"?(o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify(this.clientInfo))):(o.writeHead(404),o.end("Not Found"))}catch(n){this.logger.error("HTTP request error:",n),o.writeHead(500,{"Content-Type":"application/json"}),o.end(JSON.stringify({error:"Internal Server Error"}))}}async serveStaticFile(e,o){try{let t=po(mo(import.meta.url)),s=[j(t,"..","web","dist"),j(t,"..","web"),j(process.cwd(),"web","dist"),j(process.cwd(),"web")].find(S=>oe(S));if(!s){o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(`
22
+ \u6B63\u5728\u505C\u6B62 UI \u670D\u52A1...`));try{await e.stop(),console.log(i.green("UI \u670D\u52A1\u5DF2\u505C\u6B62"))}catch{console.log(i.red("\u505C\u6B62\u670D\u52A1\u65F6\u51FA\u9519\uFF0C\u5F3A\u5236\u9000\u51FA"))}process.exit(0)}),process.on("SIGTERM",async()=>{s=!0,await e.stop(),process.exit(0)})}catch(e){r.fail(`\u542F\u52A8 UI \u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}p(ft,"startUIService");async function dt(r,e){let t=P("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!a.configExists()){t.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(i.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}if(e)switch(r){case"mcpEndpoint":a.updateMcpEndpoint(e),t.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${e}`);break;case"heartbeatInterval":{let o=Number.parseInt(e,10);if(Number.isNaN(o)||o<=0){t.fail("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}a.setHeartbeatInterval(o),t.succeed(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${o}ms`);break}case"heartbeatTimeout":{let o=Number.parseInt(e,10);if(Number.isNaN(o)||o<=0){t.fail("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}a.setHeartbeatTimeout(o),t.succeed(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5DF2\u66F4\u65B0\u4E3A: ${o}ms`);break}case"reconnectInterval":{let o=Number.parseInt(e,10);if(Number.isNaN(o)||o<=0){t.fail("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}a.setReconnectInterval(o),t.succeed(`\u91CD\u8FDE\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${o}ms`);break}default:t.fail(`\u914D\u7F6E\u9879 ${r} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(i.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}else{t.text="\u8BFB\u53D6\u914D\u7F6E...";let o=a.getConfig();switch(r){case"mcpEndpoint":{t.succeed("\u914D\u7F6E\u4FE1\u606F");let n=a.getMcpEndpoints();n.length===0?console.log(i.yellow("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9")):n.length===1?console.log(i.green(`MCP \u7AEF\u70B9: ${n[0]}`)):(console.log(i.green(`MCP \u7AEF\u70B9 (${n.length} \u4E2A):`)),n.forEach((s,c)=>{console.log(i.gray(` ${c+1}. ${s}`))}));break}case"mcpServers":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green("MCP \u670D\u52A1:"));for(let[n,s]of Object.entries(o.mcpServers))"type"in s&&s.type==="sse"?console.log(i.gray(` ${n}: [SSE] ${s.url}`)):console.log(i.gray(` ${n}: ${s.command} ${s.args.join(" ")}`));break;case"connection":{t.succeed("\u914D\u7F6E\u4FE1\u606F");let n=a.getConnectionConfig();console.log(i.green("\u8FDE\u63A5\u914D\u7F6E:")),console.log(i.gray(` \u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${n.heartbeatInterval}ms`)),console.log(i.gray(` \u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${n.heartbeatTimeout}ms`)),console.log(i.gray(` \u91CD\u8FDE\u95F4\u9694: ${n.reconnectInterval}ms`));break}case"heartbeatInterval":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${a.getHeartbeatInterval()}ms`));break;case"heartbeatTimeout":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${a.getHeartbeatTimeout()}ms`));break;case"reconnectInterval":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u91CD\u8FDE\u95F4\u9694: ${a.getReconnectInterval()}ms`));break;default:t.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${r}`),console.log(i.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers, connection, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}}}catch(o){t.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}p(dt,"configCommand");function ut(){console.log(i.blue.bold("xiaozhi - MCP Calculator Service CLI")),console.log(),console.log(i.yellow("\u4F7F\u7528\u65B9\u6CD5:")),console.log(" xiaozhi <command> [options]"),console.log(),console.log(i.yellow("\u547D\u4EE4:")),console.log(" create <projectName> \u521B\u5EFA\u9879\u76EE"),console.log(" init \u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6"),console.log(" config <key> [value] \u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E"),console.log(" start [--daemon] [--ui] [--server] \u542F\u52A8\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C, --ui \u540C\u65F6\u542F\u52A8 Web UI, --server MCP Server \u6A21\u5F0F)"),console.log(" stop \u505C\u6B62\u670D\u52A1"),console.log(" status \u68C0\u67E5\u670D\u52A1\u72B6\u6001"),console.log(" attach \u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7"),console.log(" restart [--daemon] [--ui] \u91CD\u542F\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C, --ui \u540C\u65F6\u542F\u52A8 Web UI)"),console.log(" ui \u542F\u52A8\u914D\u7F6E\u7BA1\u7406\u7F51\u9875"),console.log(" completion \u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E"),console.log(),console.log(i.yellow("\u9009\u9879:")),console.log(" -v, --version \u663E\u793A\u7248\u672C\u4FE1\u606F"),console.log(" -V \u663E\u793A\u8BE6\u7EC6\u4FE1\u606F"),console.log(" -h, --help \u663E\u793A\u5E2E\u52A9\u4FE1\u606F"),console.log(" -t, --template <name> \u6307\u5B9A\u6A21\u677F\u540D\u79F0\uFF08\u7528\u4E8E create \u547D\u4EE4\uFF09"),console.log(),console.log(i.yellow("\u9879\u76EE\u793A\u4F8B:")),console.log(" xiaozhi create my-app # \u521B\u5EFA\u57FA\u672C\u9879\u76EE"),console.log(" xiaozhi create my-app -t hello-world # \u4F7F\u7528 hello-world \u6A21\u677F"),console.log(" xiaozhi create my-app --template hello-world # \u540C\u4E0A\uFF0C\u5B8C\u6574\u9009\u9879\u540D"),console.log(),console.log(i.yellow("\u914D\u7F6E\u793A\u4F8B:")),console.log(" xiaozhi init # \u521D\u59CB\u5316\u914D\u7F6E"),console.log(" xiaozhi config mcpEndpoint # \u67E5\u770B MCP \u7AEF\u70B9"),console.log(" xiaozhi config mcpEndpoint wss://... # \u8BBE\u7F6E MCP \u7AEF\u70B9"),console.log(),console.log(i.yellow("\u670D\u52A1\u793A\u4F8B:")),console.log(" xiaozhi start # \u524D\u53F0\u542F\u52A8\u670D\u52A1"),console.log(" xiaozhi start --daemon # \u540E\u53F0\u542F\u52A8\u670D\u52A1"),console.log(" xiaozhi start --ui # \u542F\u52A8\u670D\u52A1\u5E76\u540C\u65F6\u542F\u52A8 Web UI"),console.log(" xiaozhi start -d -u # \u540E\u53F0\u542F\u52A8\u670D\u52A1\u5E76\u540C\u65F6\u542F\u52A8 Web UI"),console.log(" xiaozhi start --server # \u4EE5 MCP Server \u6A21\u5F0F\u542F\u52A8 (\u7AEF\u53E3 3000)"),console.log(" xiaozhi start -s 8080 # \u4EE5 MCP Server \u6A21\u5F0F\u542F\u52A8 (\u7AEF\u53E3 8080)"),console.log(" xiaozhi start -s -d # \u540E\u53F0\u8FD0\u884C MCP Server"),console.log(" xiaozhi status # \u68C0\u67E5\u670D\u52A1\u72B6\u6001"),console.log(" xiaozhi attach # \u67E5\u770B\u540E\u53F0\u670D\u52A1\u65E5\u5FD7"),console.log(" xiaozhi stop # \u505C\u6B62\u670D\u52A1"),console.log(),console.log(i.yellow("MCP \u7BA1\u7406\u793A\u4F8B:")),console.log(" xiaozhi mcp list # \u5217\u51FA\u6240\u6709 MCP \u670D\u52A1"),console.log(" xiaozhi mcp list --tools # \u5217\u51FA\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177"),console.log(" xiaozhi mcp server <name> # \u5217\u51FA\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177"),console.log(" xiaozhi mcp tool <server> <tool> enable # \u542F\u7528\u5DE5\u5177"),console.log(" xiaozhi mcp tool <server> <tool> disable # \u7981\u7528\u5DE5\u5177"),console.log(),console.log(i.yellow("\u81EA\u52A8\u8865\u5168:")),console.log(" xiaozhi completion # \u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E"),console.log(" # \u8BBE\u7F6E\u540E\u53EF\u4F7F\u7528 Tab \u952E\u8FDB\u884C\u547D\u4EE4\u3001\u53C2\u6570\u81EA\u52A8\u8865\u5168")}p(ut,"showHelp");v.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(Pe(),"-v, --version","\u663E\u793A\u7248\u672C\u4FE1\u606F").helpOption("-h, --help","\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");v.command("create <projectName>").description("\u521B\u5EFA\u9879\u76EE").option("-t, --template <templateName>","\u4F7F\u7528\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u9879\u76EE").action(async(r,e)=>{await gt(r,e)});v.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").option("-f, --format <format>","\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F (json, json5, jsonc)","json").action(async r=>{let e=r.format;e!=="json"&&e!=="json5"&&e!=="jsonc"&&(console.error(i.red("\u9519\u8BEF: \u683C\u5F0F\u5FC5\u987B\u662F json, json5 \u6216 jsonc")),process.exit(1)),await it(e)});v.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(r,e)=>{await dt(r,e)});v.command("start").description("\u542F\u52A8\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").option("-u, --ui","\u540C\u65F6\u542F\u52A8 Web UI \u670D\u52A1").option("-s, --server [port]","\u4EE5 MCP Server \u6A21\u5F0F\u542F\u52A8 (\u53EF\u9009\u6307\u5B9A\u7AEF\u53E3\uFF0C\u9ED8\u8BA4 3000)").option("--stdio","\u4EE5 stdio \u6A21\u5F0F\u8FD0\u884C MCP Server (\u7528\u4E8E Cursor \u7B49\u5BA2\u6237\u7AEF)").action(async r=>{if(r.stdio){let{spawn:e}=await import("child_process"),t=$(import.meta.url),o=f.dirname(t),n=f.join(o,"mcpServerProxy.js");e("node",[n],{stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}})}else if(r.server){let e=typeof r.server=="string"?Number.parseInt(r.server):3e3;await rt(e,r.daemon)}else await Ie(r.daemon,r.ui)});v.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await xe()});v.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await tt()});v.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await ot()});v.command("restart").description("\u91CD\u542F\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").option("-u, --ui","\u540C\u65F6\u542F\u52A8 Web UI \u670D\u52A1").action(async r=>{await nt(r.daemon,r.ui)});var ne=v.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");ne.command("list").description("\u5217\u51FA MCP \u670D\u52A1").option("--tools","\u663E\u793A\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868").action(async r=>{await de(r)});ne.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async r=>{await ue(r)});ne.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(r,e,t)=>{t!=="enable"&&t!=="disable"&&(console.error(i.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await me(r,e,t==="enable")});var U=v.command("endpoint").description("\u7BA1\u7406 MCP \u7AEF\u70B9");U.command("list").description("\u5217\u51FA\u6240\u6709 MCP \u7AEF\u70B9").action(async()=>{let r=P("\u8BFB\u53D6\u7AEF\u70B9\u914D\u7F6E...").start();try{let e=a.getMcpEndpoints();r.succeed("\u7AEF\u70B9\u5217\u8868"),e.length===0?console.log(i.yellow("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9")):(console.log(i.green(`\u5171 ${e.length} \u4E2A\u7AEF\u70B9:`)),e.forEach((t,o)=>{console.log(i.gray(` ${o+1}. ${t}`))}))}catch(e){r.fail(`\u8BFB\u53D6\u7AEF\u70B9\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}});U.command("add <url>").description("\u6DFB\u52A0\u65B0\u7684 MCP \u7AEF\u70B9").action(async r=>{let e=P("\u6DFB\u52A0\u7AEF\u70B9...").start();try{a.addMcpEndpoint(r),e.succeed(`\u6210\u529F\u6DFB\u52A0\u7AEF\u70B9: ${r}`);let t=a.getMcpEndpoints();console.log(i.gray(`\u5F53\u524D\u5171 ${t.length} \u4E2A\u7AEF\u70B9`))}catch(t){e.fail(`\u6DFB\u52A0\u7AEF\u70B9\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}});U.command("remove <url>").description("\u79FB\u9664\u6307\u5B9A\u7684 MCP \u7AEF\u70B9").action(async r=>{let e=P("\u79FB\u9664\u7AEF\u70B9...").start();try{a.removeMcpEndpoint(r),e.succeed(`\u6210\u529F\u79FB\u9664\u7AEF\u70B9: ${r}`);let t=a.getMcpEndpoints();console.log(i.gray(`\u5F53\u524D\u5269\u4F59 ${t.length} \u4E2A\u7AEF\u70B9`))}catch(t){e.fail(`\u79FB\u9664\u7AEF\u70B9\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}});U.command("set <urls...>").description("\u8BBE\u7F6E MCP \u7AEF\u70B9\uFF08\u53EF\u4EE5\u662F\u5355\u4E2A\u6216\u591A\u4E2A\uFF09").action(async r=>{let e=P("\u8BBE\u7F6E\u7AEF\u70B9...").start();try{if(r.length===1)a.updateMcpEndpoint(r[0]),e.succeed(`\u6210\u529F\u8BBE\u7F6E\u7AEF\u70B9: ${r[0]}`);else{a.updateMcpEndpoint(r),e.succeed(`\u6210\u529F\u8BBE\u7F6E ${r.length} \u4E2A\u7AEF\u70B9`);for(let[t,o]of r.entries())console.log(i.gray(` ${t+1}. ${o}`))}}catch(t){e.fail(`\u8BBE\u7F6E\u7AEF\u70B9\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}});v.command("ui").description("\u542F\u52A8\u914D\u7F6E\u7BA1\u7406\u7F51\u9875").action(async()=>{await ft()});v.command("completion").description("\u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E").action(async()=>{le()});v.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(r=>{r.V&&(st(),process.exit(0))});ae();process.argv.length<=2&&(ut(),process.exit(0));v.parse(process.argv);M();W();var D=class{static{p(this,"WebServer")}app;httpServer=null;wss=null;logger;port;clientInfo={status:"disconnected",mcpEndpoint:"",activeMCPServers:[]};heartbeatTimeout;HEARTBEAT_TIMEOUT=35e3;constructor(e){if(e===void 0)try{this.port=a.getWebUIPort()}catch{this.port=9999}else this.port=e;this.logger=new A,this.app=new Ct,this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){this.app.use("*",St({origin:"*",allowMethods:["GET","POST","PUT","OPTIONS"],allowHeaders:["Content-Type"]})),this.app.onError((e,t)=>(this.logger.error("HTTP request error:",e),t.json({error:"Internal Server Error"},500)))}setupRoutes(){this.app.get("/api/config",async e=>{let t=a.getConfig();return e.json(t)}),this.app.put("/api/config",async e=>{try{let t=await e.req.json();return this.updateConfig(t),this.broadcastConfigUpdate(t),this.logger.info("\u914D\u7F6E\u5DF2\u66F4\u65B0"),e.json({success:!0})}catch(t){return e.json({error:t instanceof Error?t.message:String(t)},400)}}),this.app.get("/api/status",async e=>e.json(this.clientInfo)),this.app.all("/api/*",async e=>e.text("Not Found",404)),this.app.get("*",async e=>this.serveStaticFile(e))}async serveStaticFile(e){let t=new URL(e.req.url).pathname;try{let o=ht(yt(import.meta.url)),s=[T(o,"..","web","dist"),T(o,"..","web"),T(process.cwd(),"web","dist"),T(process.cwd(),"web")].find(S=>re(S));if(!s)return e.html(`
23
23
  <!DOCTYPE html>
24
24
  <html>
25
25
  <head>
@@ -39,5 +39,5 @@ data: ${JSON.stringify(o)}
39
39
  </div>
40
40
  </body>
41
41
  </html>
42
- `);return}let c=e;if(c==="/"&&(c="/index.html"),c.includes("..")){o.writeHead(403),o.end("Forbidden");return}let a=j(s,c);if(!oe(a)){let S=j(s,"index.html");if(oe(S)){let R=await Ie(S);o.writeHead(200,{"Content-Type":"text/html"}),o.end(R)}else o.writeHead(404),o.end("Not Found");return}let m=await Ie(a),u=a.split(".").pop()?.toLowerCase(),b={html:"text/html",js:"application/javascript",css:"text/css",json:"application/json",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",svg:"image/svg+xml",ico:"image/x-icon"}[u||""]||"application/octet-stream";o.writeHead(200,{"Content-Type":b}),o.end(m)}catch(t){this.logger.error("Serve static file error:",t),o.writeHead(500),o.end("Internal Server Error")}}setupWebSocket(){this.wss.on("connection",e=>{this.logger.debug("WebSocket client connected"),e.on("message",async o=>{try{let t=JSON.parse(o.toString());await this.handleWebSocketMessage(e,t)}catch(t){this.logger.error("WebSocket message error:",t),e.send(JSON.stringify({type:"error",error:t instanceof Error?t.message:String(t)}))}}),e.on("close",()=>{this.logger.debug("WebSocket client disconnected")}),this.sendInitialData(e)})}async handleWebSocketMessage(e,o){switch(o.type){case"getConfig":{let t=l.getConfig();e.send(JSON.stringify({type:"config",data:t}));break}case"updateConfig":this.updateConfig(o.config),this.broadcastConfigUpdate(o.config);break;case"getStatus":e.send(JSON.stringify({type:"status",data:this.clientInfo}));break;case"clientStatus":this.updateClientInfo(o.data),this.broadcastStatusUpdate();break;case"restartService":this.logger.info("\u6536\u5230\u624B\u52A8\u91CD\u542F\u670D\u52A1\u8BF7\u6C42"),this.broadcastRestartStatus("restarting"),setTimeout(async()=>{try{await this.restartService(),setTimeout(()=>{this.broadcastRestartStatus("completed")},5e3)}catch(t){this.logger.error(`\u624B\u52A8\u91CD\u542F\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`),this.broadcastRestartStatus("failed",t instanceof Error?t.message:"\u672A\u77E5\u9519\u8BEF")}},500);break}}async sendInitialData(e){let o=l.getConfig();e.send(JSON.stringify({type:"config",data:o})),e.send(JSON.stringify({type:"status",data:this.clientInfo}))}broadcastConfigUpdate(e){let o=JSON.stringify({type:"configUpdate",data:e});for(let t of this.wss.clients)t.readyState===1&&t.send(o)}broadcastRestartStatus(e,o){let t=JSON.stringify({type:"restartStatus",data:{status:e,error:o,timestamp:Date.now()}});for(let n of this.wss.clients)n.readyState===1&&n.send(t)}broadcastStatusUpdate(){let e=JSON.stringify({type:"statusUpdate",data:this.clientInfo});for(let o of this.wss.clients)o.readyState===1&&o.send(e)}updateClientInfo(e){this.clientInfo={...this.clientInfo,...e},e.lastHeartbeat&&(this.clientInfo.lastHeartbeat=Date.now()),e.status==="connected"&&this.resetHeartbeatTimeout()}resetHeartbeatTimeout(){this.heartbeatTimeout&&clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=setTimeout(()=>{this.logger.warn("\u5BA2\u6237\u7AEF\u5FC3\u8DF3\u8D85\u65F6\uFF0C\u6807\u8BB0\u4E3A\u65AD\u5F00\u8FDE\u63A5"),this.updateClientInfo({status:"disconnected"}),this.broadcastStatusUpdate()},this.HEARTBEAT_TIMEOUT)}updateConfig(e){e.mcpEndpoint!==l.getMcpEndpoint()&&l.updateMcpEndpoint(e.mcpEndpoint);let o=l.getMcpServers();for(let[t,n]of Object.entries(e.mcpServers))JSON.stringify(o[t])!==JSON.stringify(n)&&l.updateMcpServer(t,n);for(let t of Object.keys(o))t in e.mcpServers||(l.removeMcpServer(t),l.removeServerToolsConfig(t));if(e.connection&&l.updateConnectionConfig(e.connection),e.modelscope&&l.updateModelScopeConfig(e.modelscope),e.webUI&&l.updateWebUIConfig(e.webUI),e.mcpServerConfig)for(let[t,n]of Object.entries(e.mcpServerConfig))for(let[s,c]of Object.entries(n.tools))l.setToolEnabled(t,s,c.enable)}async restartService(){this.logger.info("\u6B63\u5728\u91CD\u542F MCP \u670D\u52A1..."),this.heartbeatTimeout&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=void 0);try{let e=M();if(!e.running){this.logger.warn("MCP \u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u5C1D\u8BD5\u542F\u52A8\u670D\u52A1"),Pe("xiaozhi",["start","--daemon"],{detached:!0,stdio:"ignore",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}}).unref(),this.logger.info("MCP \u670D\u52A1\u542F\u52A8\u547D\u4EE4\u5DF2\u53D1\u9001");return}let o=e.mode==="daemon",t=["restart"];o&&t.push("--daemon"),Pe("xiaozhi",t,{detached:!0,stdio:"ignore",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}}).unref(),this.logger.info("MCP \u670D\u52A1\u91CD\u542F\u547D\u4EE4\u5DF2\u53D1\u9001"),this.resetHeartbeatTimeout()}catch(e){throw this.logger.error(`\u91CD\u542F\u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),this.resetHeartbeatTimeout(),e}}updateStatus(e){this.updateClientInfo(e),this.broadcastStatusUpdate()}start(){return new Promise((e,o)=>{this.httpServer.listen(this.port,()=>{this.logger.info(`Web server listening on http://localhost:${this.port}`),e()}).on("error",o)})}stop(){return new Promise(e=>{this.heartbeatTimeout&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=void 0);for(let o of this.wss.clients)o.terminate();this.wss.close(()=>{this.httpServer.close(()=>{this.logger.info("Web server stopped"),e()}),setTimeout(()=>{this.logger.info("Web server force stopped"),e()},2e3)})})}};export{F as WebServer};
42
+ `);let c=t;if(c==="/"&&(c="/index.html"),c.includes(".."))return e.text("Forbidden",403);let l=T(s,c);if(!re(l)){let S=T(s,"index.html");if(re(S)){let j=await Ee(S);return e.html(j.toString())}return e.text("Not Found",404)}let u=await Ee(l),h=l.split(".").pop()?.toLowerCase(),C={html:"text/html",js:"application/javascript",css:"text/css",json:"application/json",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",svg:"image/svg+xml",ico:"image/x-icon"}[h||""]||"application/octet-stream";return C.startsWith("text/")||C.includes("javascript")||C.includes("json")?e.text(u.toString(),200,{"Content-Type":C}):e.body(u,200,{"Content-Type":C})}catch(o){return this.logger.error("Serve static file error:",o),e.text("Internal Server Error",500)}}setupWebSocket(){this.wss&&this.wss.on("connection",e=>{this.logger.debug("WebSocket client connected"),e.on("message",async t=>{try{let o=JSON.parse(t.toString());await this.handleWebSocketMessage(e,o)}catch(o){this.logger.error("WebSocket message error:",o),e.send(JSON.stringify({type:"error",error:o instanceof Error?o.message:String(o)}))}}),e.on("close",()=>{this.logger.debug("WebSocket client disconnected")}),this.sendInitialData(e)})}async handleWebSocketMessage(e,t){switch(t.type){case"getConfig":{let o=a.getConfig();this.logger.debug("getConfig ws getConfig",o),e.send(JSON.stringify({type:"config",data:o}));break}case"updateConfig":this.updateConfig(t.config),this.broadcastConfigUpdate(t.config);break;case"getStatus":e.send(JSON.stringify({type:"status",data:this.clientInfo}));break;case"clientStatus":{this.updateClientInfo(t.data),this.broadcastStatusUpdate();let o=a.getConfig();e.send(JSON.stringify({type:"configUpdate",data:o}));break}case"restartService":this.logger.info("\u6536\u5230\u624B\u52A8\u91CD\u542F\u670D\u52A1\u8BF7\u6C42"),this.broadcastRestartStatus("restarting"),setTimeout(async()=>{try{await this.restartService(),setTimeout(()=>{this.broadcastRestartStatus("completed")},5e3)}catch(o){this.logger.error(`\u624B\u52A8\u91CD\u542F\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`),this.broadcastRestartStatus("failed",o instanceof Error?o.message:"\u672A\u77E5\u9519\u8BEF")}},500);break}}async sendInitialData(e){let t=a.getConfig();e.send(JSON.stringify({type:"config",data:t})),e.send(JSON.stringify({type:"status",data:this.clientInfo})),setTimeout(()=>{let o=a.getConfig();e.send(JSON.stringify({type:"configUpdate",data:o}))},2e3)}broadcastConfigUpdate(e){if(!this.wss)return;let t=JSON.stringify({type:"configUpdate",data:e});for(let o of this.wss.clients)o.readyState===1&&o.send(t)}broadcastRestartStatus(e,t){if(!this.wss)return;let o=JSON.stringify({type:"restartStatus",data:{status:e,error:t,timestamp:Date.now()}});for(let n of this.wss.clients)n.readyState===1&&n.send(o)}broadcastStatusUpdate(){if(!this.wss)return;let e=JSON.stringify({type:"statusUpdate",data:this.clientInfo});for(let t of this.wss.clients)t.readyState===1&&t.send(e)}updateClientInfo(e){this.clientInfo={...this.clientInfo,...e},e.lastHeartbeat&&(this.clientInfo.lastHeartbeat=Date.now()),e.status==="connected"&&this.resetHeartbeatTimeout()}resetHeartbeatTimeout(){this.heartbeatTimeout&&clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=setTimeout(()=>{this.logger.warn("\u5BA2\u6237\u7AEF\u5FC3\u8DF3\u8D85\u65F6\uFF0C\u6807\u8BB0\u4E3A\u65AD\u5F00\u8FDE\u63A5"),this.updateClientInfo({status:"disconnected"}),this.broadcastStatusUpdate()},this.HEARTBEAT_TIMEOUT)}updateConfig(e){e.mcpEndpoint!==a.getMcpEndpoint()&&a.updateMcpEndpoint(e.mcpEndpoint);let t=a.getMcpServers();for(let[o,n]of Object.entries(e.mcpServers))JSON.stringify(t[o])!==JSON.stringify(n)&&a.updateMcpServer(o,n);for(let o of Object.keys(t))o in e.mcpServers||(a.removeMcpServer(o),a.removeServerToolsConfig(o));if(e.connection&&a.updateConnectionConfig(e.connection),e.modelscope&&a.updateModelScopeConfig(e.modelscope),e.webUI&&a.updateWebUIConfig(e.webUI),e.mcpServerConfig)for(let[o,n]of Object.entries(e.mcpServerConfig))for(let[s,c]of Object.entries(n.tools))a.setToolEnabled(o,s,c.enable)}async restartService(){this.logger.info("\u6B63\u5728\u91CD\u542F MCP \u670D\u52A1..."),this.heartbeatTimeout&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=void 0);try{let e=E();if(!e.running){this.logger.warn("MCP \u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u5C1D\u8BD5\u542F\u52A8\u670D\u52A1"),$e("xiaozhi",["start","--daemon"],{detached:!0,stdio:"ignore",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}}).unref(),this.logger.info("MCP \u670D\u52A1\u542F\u52A8\u547D\u4EE4\u5DF2\u53D1\u9001");return}let t=e.mode==="daemon",o=["restart"];t&&o.push("--daemon"),$e("xiaozhi",o,{detached:!0,stdio:"ignore",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}}).unref(),this.logger.info("MCP \u670D\u52A1\u91CD\u542F\u547D\u4EE4\u5DF2\u53D1\u9001"),this.resetHeartbeatTimeout()}catch(e){throw this.logger.error(`\u91CD\u542F\u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`),this.resetHeartbeatTimeout(),e}}updateStatus(e){this.updateClientInfo(e),this.broadcastStatusUpdate()}start(){return new Promise((e,t)=>{try{let o=bt({fetch:this.app.fetch,port:this.port,hostname:"0.0.0.0",createServer:mt});this.httpServer=o,this.wss=new vt({server:this.httpServer}),this.setupWebSocket(),this.logger.info(`Web server listening on http://0.0.0.0:${this.port}`),this.logger.info(`Local access: http://localhost:${this.port}`),e(),this.httpServer.on("error",t)}catch(o){t(o)}})}stop(){return new Promise(e=>{let t=!1,o=p(()=>{t||(t=!0,e())},"doResolve");if(this.heartbeatTimeout&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=void 0),this.wss){for(let n of this.wss.clients)n.terminate();this.wss.close(()=>{this.httpServer?this.httpServer.close(()=>{this.logger.info("Web server stopped"),o()}):(this.logger.info("Web server stopped"),o()),setTimeout(()=>{this.logger.info("Web server force stopped"),o()},2e3)})}else this.logger.info("Web server stopped"),o()})}};export{D as WebServer};
43
43
  //# sourceMappingURL=webServer.js.map