xiaozhi-client 1.6.0 → 1.6.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,18 +1,15 @@
1
1
  #!/usr/bin/env node
2
- var se=Object.defineProperty;var g=(r,e)=>se(r,"name",{value:e,configurable:!0});var O=(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})};import H from"fs";import je from"path";import k from"chalk";import{createConsola as Re}from"consola";function Oe(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,w,$=O(()=>{"use strict";g(Oe,"formatDateTime");A=class{static{g(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=Re({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:g(t=>{let o={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},n={info:k.blue,success:k.green,warn:k.yellow,error:k.red,debug:k.gray,log:g(y=>y,"log")},s=o[t.type]||t.type.toUpperCase(),c=n[t.type]||(y=>y),a=Oe(new Date),u=c(`[${s}]`),h=`[${a}] ${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=je.join(e,"xiaozhi.log"),H.existsSync(this.logFilePath)||H.writeFileSync(this.logFilePath,""),this.writeStream=H.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(a=>typeof a=="object"?JSON.stringify(a):String(a)).join(" ")}`:s;this.writeStream.write(`${c}
3
- `)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=H.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)}},w=new A});function ke(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(ke(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=O(()=>{"use strict";g(ke,"getMcpServerCommunicationType");g(X,"validateMcpServerConfig")});import{copyFileSync as Ae,existsSync as B,readFileSync as We,writeFileSync as Fe}from"fs";import{dirname as _e,resolve as W}from"path";import{fileURLToPath as De}from"url";import*as L from"comment-json";import ze from"dayjs";import Z from"json5";import*as ce from"json5-writer";var Ne,V,q,l,x=O(()=>{"use strict";$();ie();Ne=_e(De(import.meta.url)),V={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},q=class r{static{g(this,"ConfigManager")}static instance;defaultConfigPath;config=null;currentConfigPath=null;json5Writer=null;constructor(){this.defaultConfigPath=W(Ne,"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=W(e,o);if(B(n))return n}return W(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=W(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=W(t,o);Ae(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),n=We(e,"utf8").replace(/^\uFEFF/,""),s;switch(t){case"json5":s=Z.parse(n),this.json5Writer=ce.load(n);break;case"jsonc":s=L.parse(n);break;default:s=JSON.parse(n);break}return this.validateConfig(s),s}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.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=L.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}Fe(t,n,"utf8"),this.config=e,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)}async updateToolUsageStats(e,t,o){try{let n=this.getMutableConfig();n.mcpServerConfig||(n.mcpServerConfig={}),n.mcpServerConfig[e]||(n.mcpServerConfig[e]={tools:{}}),n.mcpServerConfig[e].tools[t]||(n.mcpServerConfig[e].tools[t]={enable:!0});let s=n.mcpServerConfig[e].tools[t],c=s.usageCount||0,a=s.lastUsedTime;s.usageCount=c+1,(!a||new Date(o)>new Date(a))&&(s.lastUsedTime=ze(o).format("YYYY-MM-DD HH:mm:ss")),this.saveConfig(n),w.debug(`\u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5DF2\u66F4\u65B0: ${e}/${t}, \u4F7F\u7528\u6B21\u6570: ${s.usageCount}`)}catch(n){w.error(`\u66F4\u65B0\u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5931\u8D25 (${e}/${t}): ${n instanceof Error?n.message:String(n)}`)}}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})}},l=q.getInstance()});import{spawn as Ye}from"child_process";import M from"process";import _ from"ws";var be,d,G,Ce=O(()=>{"use strict";x();$();be=g(()=>M.env.NODE_ENV==="test"||M.env.VITEST==="true","isTestEnvironment"),d=w.withTag("MULTI_MCP_PIPE");M.env.XIAOZHI_DAEMON==="true"&&M.env.XIAOZHI_CONFIG_DIR&&(w.initLogFile(M.env.XIAOZHI_CONFIG_DIR),w.enableFileLogging(!0));G=class{static{g(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=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(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}
4
- `)}),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=Ye("node",[this.mcpScript],{stdio:["pipe","pipe","pipe"]}),t.process.stdout?.on("data",o=>{t.stdoutBuffer+=o.toString();let n=t.stdoutBuffer.split(`
5
- `);t.stdoutBuffer=n.pop()||"";for(let s of n)s.trim()&&this.handleMCPMessage(e,s)}),t.process.stderr?.on("data",o=>{if(M.env.XIAOZHI_DAEMON!=="true")try{M.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}
6
- `),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(),be()||setTimeout(()=>{M.exit(0)},100)}async reportStatusToWebUI(){if(!be())try{let e=l.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 ve={};Te(ve,{MCPServer:()=>ee});import{spawn as Ke}from"child_process";import{randomUUID as Qe}from"crypto";import{EventEmitter as et}from"events";import U from"fs";import tt from"os";import P from"path";import{fileURLToPath as Se}from"url";import Q from"express";var ot,D,m,z,nt,ee,we=O(()=>{"use strict";x();$();Ce();ot=Se(import.meta.url),D=P.dirname(ot),m=w.withTag("mcp-server"),z="mcpServerProxy.js",nt=5,ee=class extends et{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=Q(),this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){this.app.use(Q.json()),this.app.use(Q.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=Qe();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
7
- data: /messages?sessionId=${n}
2
+ var Te=Object.defineProperty;var c=(o,e)=>Te(o,"name",{value:e,configurable:!0});var N=(o,e)=>()=>(o&&(e=o(o=0)),e);var et=(o,e)=>{for(var t in e)Te(o,t,{get:e[t],enumerable:!0})};import Q from"fs";import tt from"path";import W from"chalk";import{createConsola as nt}from"consola";function ot(o){let e=o.getFullYear(),t=String(o.getMonth()+1).padStart(2,"0"),n=String(o.getDate()).padStart(2,"0"),r=String(o.getHours()).padStart(2,"0"),i=String(o.getMinutes()).padStart(2,"0"),s=String(o.getSeconds()).padStart(2,"0");return`${e}-${t}-${n} ${r}:${i}:${s}`}var C,E,x=N(()=>{"use strict";c(ot,"formatDateTime");C=class{static{c(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=nt({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:c(t=>{let n={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},r={info:W.blue,success:W.green,warn:W.yellow,error:W.red,debug:W.gray,log:c(S=>S,"log")},i=n[t.type]||t.type.toUpperCase(),s=r[t.type]||(S=>S),l=ot(new Date),p=s(`[${i}]`),f=`[${l}] ${p} ${t.args.join(" ")}`;if(!e)try{console.error(f)}catch(S){if(S instanceof Error&&S.message?.includes("EPIPE"))return;throw S}},"log")}])}initLogFile(e){this.logFilePath=tt.join(e,"xiaozhi.log"),Q.existsSync(this.logFilePath)||Q.writeFileSync(this.logFilePath,""),this.writeStream=Q.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(e,t,...n){if(this.writeStream){let i=`[${new Date().toISOString()}] [${e.toUpperCase()}] ${t}`,s=n.length>0?`${i} ${n.map(l=>typeof l=="object"?JSON.stringify(l):String(l)).join(" ")}`:i;this.writeStream.write(`${s}
3
+ `)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=Q.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)}},E=new C});import ee from"ws";var D,te=N(()=>{"use strict";x();D=class{static{c(this,"ProxyMCPServer")}endpointUrl;ws=null;logger;isConnected=!1;serverInitialized=!1;tools=new Map;connectionState="disconnected";reconnectOptions;reconnectState={attempts:0,nextInterval:0,timer:null,lastError:null,isManualDisconnect:!1};connectionTimeout=null;constructor(e,t){this.endpointUrl=e,this.logger=new C,this.reconnectOptions={enabled:!0,maxAttempts:10,initialInterval:3e3,maxInterval:3e4,backoffStrategy:"exponential",backoffMultiplier:1.5,timeout:1e4,jitter:!0,...t?.reconnect},this.reconnectState.nextInterval=this.reconnectOptions.initialInterval}setServiceManager(e){this.serviceManager=e,this.logger.info("\u5DF2\u8BBE\u7F6E MCPServiceManager"),this.syncToolsFromServiceManager()}syncToolsFromServiceManager(){let e=this.serviceManager;if(!e){this.logger.debug("MCPServiceManager \u672A\u8BBE\u7F6E\uFF0C\u8DF3\u8FC7\u5DE5\u5177\u540C\u6B65");return}try{let t=e.getAllTools(),n=new Map;for(let r of t)n.set(r.name,{name:r.name,description:r.description,inputSchema:r.inputSchema});this.tools=n,this.logger.info(`\u5DF2\u4ECE MCPServiceManager \u540C\u6B65 ${this.tools.size} \u4E2A\u5DE5\u5177`)}catch(t){this.logger.error(`\u540C\u6B65\u5DE5\u5177\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}addTool(e,t){return this.validateTool(e,t),this.tools.set(e,t),this.logger.debug(`\u5DE5\u5177 '${e}' \u5DF2\u6DFB\u52A0`),this}addTools(e){for(let[t,n]of Object.entries(e))this.addTool(t,n);return this}removeTool(e){return this.tools.delete(e)?this.logger.debug(`\u5DE5\u5177 '${e}' \u5DF2\u79FB\u9664`):this.logger.warn(`\u5C1D\u8BD5\u79FB\u9664\u4E0D\u5B58\u5728\u7684\u5DE5\u5177: '${e}'`),this}getTools(){try{this.syncToolsFromServiceManager()}catch{}return Array.from(this.tools.values())}hasTool(e){return this.tools.has(e)}validateTool(e,t){if(!e||typeof e!="string"||e.trim()==="")throw new Error("\u5DE5\u5177\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(this.tools.has(e))throw new Error(`\u5DE5\u5177 '${e}' \u5DF2\u5B58\u5728`);if(!t||typeof t!="object")throw new Error("\u5DE5\u5177\u5FC5\u987B\u662F\u6709\u6548\u7684\u5BF9\u8C61");if(!t.name||typeof t.name!="string")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'name' \u5B57\u6BB5");if(!t.description||typeof t.description!="string")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'description' \u5B57\u6BB5");if(!t.inputSchema||typeof t.inputSchema!="object")throw new Error("\u5DE5\u5177\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 'inputSchema' \u5B57\u6BB5");if(!t.inputSchema.type||!t.inputSchema.properties)throw new Error("\u5DE5\u5177\u7684 inputSchema \u5FC5\u987B\u5305\u542B 'type' \u548C 'properties' \u5B57\u6BB5")}async connect(){if(this.tools.size===0)throw new Error("\u672A\u914D\u7F6E\u4EFB\u4F55\u5DE5\u5177\u3002\u8BF7\u5728\u8FDE\u63A5\u524D\u81F3\u5C11\u6DFB\u52A0\u4E00\u4E2A\u5DE5\u5177\u3002");if(this.connectionState==="connecting")throw new Error("\u8FDE\u63A5\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u8FDE\u63A5\u5B8C\u6210");return this.cleanupConnection(),this.reconnectState.isManualDisconnect=!1,this.attemptConnection()}async attemptConnection(){return this.connectionState="connecting",this.logger.info(`\u6B63\u5728\u8FDE\u63A5 MCP \u63A5\u5165\u70B9: ${this.endpointUrl} (\u5C1D\u8BD5 ${this.reconnectState.attempts+1}/${this.reconnectOptions.maxAttempts})`),new Promise((e,t)=>{this.connectionTimeout=setTimeout(()=>{let n=new Error(`\u8FDE\u63A5\u8D85\u65F6 (${this.reconnectOptions.timeout}ms)`);this.handleConnectionError(n),t(n)},this.reconnectOptions.timeout),this.ws=new ee(this.endpointUrl),this.ws.on("open",()=>{this.handleConnectionSuccess(),e()}),this.ws.on("message",n=>{try{let r=JSON.parse(n.toString());this.handleMessage(r)}catch(r){this.logger.error("MCP \u6D88\u606F\u89E3\u6790\u9519\u8BEF:",r)}}),this.ws.on("close",(n,r)=>{this.handleConnectionClose(n,r.toString())}),this.ws.on("error",n=>{this.handleConnectionError(n),t(n)})})}handleConnectionSuccess(){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.isConnected=!0,this.connectionState="connected",this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.lastError=null,this.logger.info("MCP WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB")}handleConnectionError(e){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.reconnectState.lastError=e,this.logger.error("MCP WebSocket \u9519\u8BEF:",e.message),this.cleanupConnection()}handleConnectionClose(e,t){if(this.isConnected=!1,this.serverInitialized=!1,this.logger.info(`MCP \u8FDE\u63A5\u5DF2\u5173\u95ED (\u4EE3\u7801: ${e}, \u539F\u56E0: ${t})`),this.reconnectState.isManualDisconnect){this.connectionState="disconnected";return}this.shouldReconnect()?this.scheduleReconnect():(this.connectionState="failed",this.logger.warn(`\u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8FDE\u6B21\u6570 (${this.reconnectOptions.maxAttempts})\uFF0C\u505C\u6B62\u91CD\u8FDE`))}shouldReconnect(){return this.reconnectOptions.enabled&&this.reconnectState.attempts<this.reconnectOptions.maxAttempts&&!this.reconnectState.isManualDisconnect}scheduleReconnect(){this.connectionState="reconnecting",this.reconnectState.attempts++,this.calculateNextInterval(),this.logger.info(`\u5C06\u5728 ${this.reconnectState.nextInterval}ms \u540E\u8FDB\u884C\u7B2C ${this.reconnectState.attempts} \u6B21\u91CD\u8FDE`),this.reconnectState.timer&&clearTimeout(this.reconnectState.timer),this.reconnectState.timer=setTimeout(async()=>{try{await this.attemptConnection()}catch{}},this.reconnectState.nextInterval)}calculateNextInterval(){let e;switch(this.reconnectOptions.backoffStrategy){case"fixed":e=this.reconnectOptions.initialInterval;break;case"linear":e=this.reconnectOptions.initialInterval+this.reconnectState.attempts*this.reconnectOptions.backoffMultiplier*1e3;break;case"exponential":e=this.reconnectOptions.initialInterval*this.reconnectOptions.backoffMultiplier**(this.reconnectState.attempts-1);break;default:e=this.reconnectOptions.initialInterval}if(e=Math.min(e,this.reconnectOptions.maxInterval),this.reconnectOptions.jitter){let t=e*.1,n=(Math.random()-.5)*2*t;e+=n}this.reconnectState.nextInterval=Math.max(e,1e3)}cleanupConnection(){if(this.ws){this.ws.removeAllListeners();try{this.ws.readyState===ee.OPEN?this.ws.close(1e3,"Cleaning up connection"):this.ws.readyState===ee.CONNECTING&&this.ws.terminate()}catch(e){this.logger.debug("WebSocket \u5173\u95ED\u65F6\u51FA\u73B0\u9519\u8BEF\uFF08\u5DF2\u5FFD\u7565\uFF09:",e)}this.ws=null}this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.isConnected=!1,this.serverInitialized=!1}stopReconnect(){this.reconnectState.timer&&(clearTimeout(this.reconnectState.timer),this.reconnectState.timer=null)}handleMessage(e){this.logger.debug("\u6536\u5230 MCP \u6D88\u606F:",JSON.stringify(e,null,2)),e.method&&this.handleServerRequest(e)}handleServerRequest(e){switch(e.method){case"initialize":this.sendResponse(e.id,{protocolVersion:"2024-11-05",capabilities:{tools:{listChanged:!0},logging:{}},serverInfo:{name:"xiaozhi-mcp-server",version:"1.0.0"}}),this.serverInitialized=!0,this.logger.info("MCP \u670D\u52A1\u5668\u521D\u59CB\u5316\u5B8C\u6210");break;case"tools/list":{let t=this.getTools();this.sendResponse(e.id,{tools:t}),this.logger.info(`MCP \u5DE5\u5177\u5217\u8868\u5DF2\u53D1\u9001 (${t.length}\u4E2A\u5DE5\u5177)`);break}case"ping":this.sendResponse(e.id,{}),this.logger.debug("\u56DE\u5E94 MCP ping \u6D88\u606F");break;default:this.logger.warn(`\u672A\u77E5\u7684 MCP \u8BF7\u6C42: ${e.method}`)}}sendResponse(e,t){if(this.isConnected&&this.ws?.readyState===ee.OPEN){let n={jsonrpc:"2.0",id:e,result:t};this.ws.send(JSON.stringify(n))}}getStatus(){return{connected:this.isConnected,initialized:this.serverInitialized,url:this.endpointUrl,availableTools:this.tools.size,connectionState:this.connectionState,reconnectAttempts:this.reconnectState.attempts,lastError:this.reconnectState.lastError?.message||null}}disconnect(){this.logger.info("\u4E3B\u52A8\u65AD\u5F00 MCP \u8FDE\u63A5"),this.reconnectState.isManualDisconnect=!0,this.stopReconnect(),this.cleanupConnection(),this.connectionState="disconnected"}async reconnect(){this.logger.info("\u624B\u52A8\u91CD\u8FDE MCP \u63A5\u5165\u70B9"),this.stopReconnect(),this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.isManualDisconnect=!1,this.cleanupConnection(),await this.connect()}enableReconnect(){this.reconnectOptions.enabled=!0,this.logger.info("\u81EA\u52A8\u91CD\u8FDE\u5DF2\u542F\u7528")}disableReconnect(){this.reconnectOptions.enabled=!1,this.stopReconnect(),this.logger.info("\u81EA\u52A8\u91CD\u8FDE\u5DF2\u7981\u7528")}updateReconnectOptions(e){this.reconnectOptions={...this.reconnectOptions,...e},this.logger.info("\u91CD\u8FDE\u914D\u7F6E\u5DF2\u66F4\u65B0",e)}getReconnectOptions(){return{...this.reconnectOptions}}resetReconnectState(){this.stopReconnect(),this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.lastError=null,this.logger.info("\u91CD\u8FDE\u72B6\u6001\u5DF2\u91CD\u7F6E")}}});import{SSEClientTransport as Ie}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as rt}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as it}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{EventSource as st}from"eventsource";function at(){return new C().withTag("TransportFactory")}function ct(o){switch(at().info(`\u521B\u5EFA ${o.type} transport for ${o.name}`),o.type){case"stdio":return lt(o);case"sse":return gt(o);case"modelscope-sse":return ht(o);case"streamable-http":return pt(o);default:throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${o.type}`)}}function lt(o){if(!o.command)throw new Error("stdio transport \u9700\u8981 command \u914D\u7F6E");return new rt({command:o.command,args:o.args||[]})}function gt(o){if(!o.url)throw new Error("SSE transport \u9700\u8981 URL \u914D\u7F6E");let e=new URL(o.url),t=ft(o);return new Ie(e,t)}function ht(o){if(!o.url)throw new Error("ModelScope SSE transport \u9700\u8981 URL \u914D\u7F6E");if(!o.apiKey)throw new Error("ModelScope SSE transport \u9700\u8981 apiKey \u914D\u7F6E");let e=new URL(o.url),t=ut(o);return new Ie(e,t)}function pt(o){if(!o.url)throw new Error("StreamableHTTP transport \u9700\u8981 URL \u914D\u7F6E");let e=new URL(o.url),t=mt(o);return new it(e,t)}function ft(o){let e={};return o.apiKey?e.headers={Authorization:`Bearer ${o.apiKey}`,...o.headers}:o.headers&&(e.headers=o.headers),e}function ut(o){let e=o.apiKey;return o.customSSEOptions?o.customSSEOptions:{eventSourceInit:{fetch:c(async(t,n)=>{let r={...n?.headers,Authorization:`Bearer ${e}`};return fetch(t,{...n,headers:r})},"fetch")},requestInit:{headers:{Authorization:`Bearer ${e}`,...o.headers}}}}function mt(o){let e={};return o.apiKey?e.headers={Authorization:`Bearer ${o.apiKey}`,...o.headers}:o.headers&&(e.headers=o.headers),e}function dt(o){if(!o.name||typeof o.name!="string")throw new Error("\u914D\u7F6E\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 name \u5B57\u6BB5");if(!o.type)throw new Error("\u914D\u7F6E\u5FC5\u987B\u5305\u542B type \u5B57\u6BB5");switch(o.type){case"stdio":if(!o.command)throw new Error("stdio \u7C7B\u578B\u9700\u8981 command \u5B57\u6BB5");break;case"sse":case"streamable-http":if(!o.url)throw new Error(`${o.type} \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5`);break;case"modelscope-sse":if(!o.url)throw new Error("modelscope-sse \u7C7B\u578B\u9700\u8981 url \u5B57\u6BB5");if(!o.apiKey)throw new Error("modelscope-sse \u7C7B\u578B\u9700\u8981 apiKey \u5B57\u6BB5\u3002\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E modelscope.apiKey \u6216\u786E\u4FDD\u670D\u52A1\u914D\u7F6E\u5305\u542B apiKey");break;default:throw new Error(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${o.type}`)}}function St(){return["stdio","sse","modelscope-sse","streamable-http"]}var le,xe=N(()=>{"use strict";x();ne();typeof global<"u"&&!global.EventSource&&(global.EventSource=st);c(at,"getLogger");c(ct,"createTransport");c(lt,"createStdioTransport");c(gt,"createSSETransport");c(ht,"createModelScopeSSETransport");c(pt,"createStreamableHTTPTransport");c(ft,"createSSEOptions");c(ut,"createModelScopeSSEOptions");c(mt,"createStreamableHTTPOptions");c(dt,"validateConfig");c(St,"getSupportedTypes");le={create:ct,validateConfig:dt,getSupportedTypes:St}});import{Client as Ct}from"@modelcontextprotocol/sdk/client/index.js";var X,oe,ne=N(()=>{"use strict";x();xe();X=(r=>(r.STDIO="stdio",r.SSE="sse",r.STREAMABLE_HTTP="streamable-http",r.MODELSCOPE_SSE="modelscope-sse",r))(X||{}),oe=class{static{c(this,"MCPService")}config;client=null;transport=null;tools=new Map;connectionState="disconnected";reconnectOptions;reconnectState;logger;connectionTimeout=null;initialized=!1;pingOptions;pingTimer=null;pingFailureCount=0;lastPingTime=null;isPinging=!1;constructor(e,t){this.config=e,this.logger=new C().withTag(`MCP-${e.name}`),this.validateConfig(),this.reconnectOptions={enabled:!0,maxAttempts:10,initialInterval:3e3,maxInterval:3e4,backoffStrategy:"exponential",backoffMultiplier:1.5,timeout:1e4,jitter:!0,...t?.reconnect,...e.reconnect},this.pingOptions={enabled:!0,interval:3e4,timeout:5e3,maxFailures:3,startDelay:5e3,...e.ping},this.reconnectState={attempts:0,nextInterval:this.reconnectOptions.initialInterval,timer:null,lastError:null,isManualDisconnect:!1}}validateConfig(){le.validateConfig(this.config)}async connect(){if(this.connectionState==="connecting")throw new Error("\u8FDE\u63A5\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u8FDE\u63A5\u5B8C\u6210");return this.cleanupConnection(),this.reconnectState.isManualDisconnect=!1,this.attemptConnection()}async attemptConnection(){return this.connectionState="connecting",this.logger.info(`\u6B63\u5728\u8FDE\u63A5 MCP \u670D\u52A1: ${this.config.name} (\u5C1D\u8BD5 ${this.reconnectState.attempts+1}/${this.reconnectOptions.maxAttempts})`),new Promise((e,t)=>{this.connectionTimeout=setTimeout(()=>{let n=new Error(`\u8FDE\u63A5\u8D85\u65F6 (${this.reconnectOptions.timeout}ms)`);this.handleConnectionError(n),t(n)},this.reconnectOptions.timeout);try{this.client=new Ct({name:`xiaozhi-${this.config.name}-client`,version:"1.0.0"},{capabilities:{tools:{}}}),this.transport=le.create(this.config),this.client.connect(this.transport).then(async()=>{this.handleConnectionSuccess(),await this.refreshTools(),e()}).catch(n=>{this.handleConnectionError(n),t(n)})}catch(n){this.handleConnectionError(n),t(n)}})}handleConnectionSuccess(){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.connectionState="connected",this.initialized=!0,this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.lastError=null,this.resetPingState(),this.logger.info(`MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5\u5DF2\u5EFA\u7ACB`),this.startPingMonitoring()}handleConnectionError(e){this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.reconnectState.lastError=e,this.logger.error(`MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5\u9519\u8BEF:`,e.message),this.cleanupConnection(),this.shouldReconnect()?this.scheduleReconnect():(this.connectionState="failed",this.logger.warn(`${this.config.name} \u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8FDE\u6B21\u6570 (${this.reconnectOptions.maxAttempts})\uFF0C\u505C\u6B62\u91CD\u8FDE`))}shouldReconnect(){return this.reconnectOptions.enabled&&this.reconnectState.attempts<this.reconnectOptions.maxAttempts&&!this.reconnectState.isManualDisconnect}scheduleReconnect(){this.connectionState="reconnecting",this.reconnectState.attempts++,this.calculateNextInterval(),this.logger.info(`${this.config.name} \u5C06\u5728 ${this.reconnectState.nextInterval}ms \u540E\u8FDB\u884C\u7B2C ${this.reconnectState.attempts} \u6B21\u91CD\u8FDE`),this.reconnectState.timer&&clearTimeout(this.reconnectState.timer),this.reconnectState.timer=setTimeout(async()=>{try{await this.attemptConnection()}catch{}},this.reconnectState.nextInterval)}calculateNextInterval(){let e;switch(this.reconnectOptions.backoffStrategy){case"fixed":e=this.reconnectOptions.initialInterval;break;case"linear":e=this.reconnectOptions.initialInterval+this.reconnectState.attempts*this.reconnectOptions.backoffMultiplier*1e3;break;case"exponential":e=this.reconnectOptions.initialInterval*this.reconnectOptions.backoffMultiplier**(this.reconnectState.attempts-1);break;default:e=this.reconnectOptions.initialInterval}if(e=Math.min(e,this.reconnectOptions.maxInterval),this.reconnectOptions.jitter){let t=e*.1,n=(Math.random()-.5)*2*t;e+=n}this.reconnectState.nextInterval=Math.max(e,1e3)}cleanupConnection(){if(this.stopPingMonitoring(),this.client){try{this.client.close().catch(()=>{})}catch{}this.client=null}this.transport=null,this.connectionTimeout&&(clearTimeout(this.connectionTimeout),this.connectionTimeout=null),this.initialized=!1}stopReconnect(){this.reconnectState.timer&&(clearTimeout(this.reconnectState.timer),this.reconnectState.timer=null)}async refreshTools(){if(!this.client)throw new Error("\u5BA2\u6237\u7AEF\u672A\u521D\u59CB\u5316");try{let t=(await this.client.listTools()).tools||[];this.tools.clear();for(let n of t)this.tools.set(n.name,n);this.logger.info(`${this.config.name} \u670D\u52A1\u52A0\u8F7D\u4E86 ${t.length} \u4E2A\u5DE5\u5177: ${t.map(n=>n.name).join(", ")}`)}catch(e){throw this.logger.error(`${this.config.name} \u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25:`,e instanceof Error?e.message:String(e)),e}}async disconnect(){this.logger.info(`\u4E3B\u52A8\u65AD\u5F00 MCP \u670D\u52A1 ${this.config.name} \u8FDE\u63A5`),this.reconnectState.isManualDisconnect=!0,this.stopPingMonitoring(),this.stopReconnect(),this.cleanupConnection(),this.connectionState="disconnected"}async reconnect(){this.logger.info(`\u624B\u52A8\u91CD\u8FDE MCP \u670D\u52A1 ${this.config.name}`),this.stopReconnect(),this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.isManualDisconnect=!1,this.cleanupConnection(),await this.connect()}getTools(){return Array.from(this.tools.values())}async callTool(e,t){if(!this.client)throw new Error(`\u670D\u52A1 ${this.config.name} \u672A\u8FDE\u63A5`);if(!this.tools.has(e))throw new Error(`\u5DE5\u5177 ${e} \u5728\u670D\u52A1 ${this.config.name} \u4E2D\u4E0D\u5B58\u5728`);this.logger.info(`\u8C03\u7528 ${this.config.name} \u670D\u52A1\u7684\u5DE5\u5177 ${e}\uFF0C\u53C2\u6570:`,JSON.stringify(t));try{let n=await this.client.callTool({name:e,arguments:t||{}});return this.logger.info(`\u5DE5\u5177 ${e} \u8C03\u7528\u6210\u529F\uFF0C\u7ED3\u679C:`,`${JSON.stringify(n).substring(0,500)}...`),n}catch(n){throw this.logger.error(`\u5DE5\u5177 ${e} \u8C03\u7528\u5931\u8D25:`,n instanceof Error?n.message:String(n)),n}}getConfig(){return this.config}getStatus(){return{name:this.config.name,connected:this.connectionState==="connected",initialized:this.initialized,transportType:this.config.type,toolCount:this.tools.size,lastError:this.reconnectState.lastError?.message,reconnectAttempts:this.reconnectState.attempts,connectionState:this.connectionState,pingEnabled:this.pingOptions.enabled,lastPingTime:this.lastPingTime||void 0,pingFailureCount:this.pingFailureCount,isPinging:this.isPinging}}isConnected(){return this.connectionState==="connected"&&this.initialized}enableReconnect(){this.reconnectOptions.enabled=!0,this.logger.info(`${this.config.name} \u81EA\u52A8\u91CD\u8FDE\u5DF2\u542F\u7528`)}disableReconnect(){this.reconnectOptions.enabled=!1,this.stopReconnect(),this.logger.info(`${this.config.name} \u81EA\u52A8\u91CD\u8FDE\u5DF2\u7981\u7528`)}updateReconnectOptions(e){this.reconnectOptions={...this.reconnectOptions,...e},this.logger.info(`${this.config.name} \u91CD\u8FDE\u914D\u7F6E\u5DF2\u66F4\u65B0`,e)}getReconnectOptions(){return{...this.reconnectOptions}}resetReconnectState(){this.stopReconnect(),this.reconnectState.attempts=0,this.reconnectState.nextInterval=this.reconnectOptions.initialInterval,this.reconnectState.lastError=null,this.logger.info(`${this.config.name} \u91CD\u8FDE\u72B6\u6001\u5DF2\u91CD\u7F6E`)}startPingMonitoring(){!this.pingOptions.enabled||this.pingTimer||!this.isConnected()||(this.logger.info(`${this.config.name} \u542F\u52A8ping\u76D1\u63A7\uFF0C\u95F4\u9694: ${this.pingOptions.interval}ms`),setTimeout(()=>{this.isConnected()&&!this.pingTimer&&(this.pingTimer=setInterval(()=>{this.performPing()},this.pingOptions.interval))},this.pingOptions.startDelay))}stopPingMonitoring(){this.pingTimer&&(clearInterval(this.pingTimer),this.pingTimer=null,this.logger.debug(`${this.config.name} \u505C\u6B62ping\u76D1\u63A7`))}async performPing(){if(!this.client||this.isPinging||!this.isConnected())return;this.isPinging=!0;let e=performance.now();try{this.logger.debug(`${this.config.name} \u53D1\u9001ping\u8BF7\u6C42\uFF08\u901A\u8FC7listTools\u68C0\u6D4B\u8FDE\u63A5\uFF09`);let t=this.client.listTools(),n=new Promise((i,s)=>{setTimeout(()=>{s(new Error(`Ping\u8D85\u65F6 (${this.pingOptions.timeout}ms)`))},this.pingOptions.timeout)});await Promise.race([t,n]);let r=performance.now()-e;this.handlePingSuccess(r)}catch(t){let n=performance.now()-e;this.handlePingFailure(t,n)}finally{this.isPinging=!1}}handlePingSuccess(e){this.pingFailureCount=0,this.lastPingTime=new Date,this.logger.debug(`${this.config.name} ping\u6210\u529F\uFF0C\u5EF6\u8FDF: ${e.toFixed(2)}ms`)}handlePingFailure(e,t){if(this.pingFailureCount++,this.logger.warn(`${this.config.name} ping\u5931\u8D25 (${this.pingFailureCount}/${this.pingOptions.maxFailures})\uFF0C\u5EF6\u8FDF: ${t.toFixed(2)}ms\uFF0C\u9519\u8BEF: ${e.message}`),this.pingFailureCount>=this.pingOptions.maxFailures){this.logger.error(`${this.config.name} \u8FDE\u7EEDping\u5931\u8D25\u8FBE\u5230\u9608\u503C\uFF0C\u89E6\u53D1\u91CD\u8FDE\u673A\u5236`),this.stopPingMonitoring();let n=new Error(`Ping\u68C0\u6D4B\u5931\u8D25\uFF0C\u8FDE\u7EED\u5931\u8D25${this.pingFailureCount}\u6B21\uFF0C\u8FDE\u63A5\u53EF\u80FD\u5DF2\u65AD\u5F00`);this.handleConnectionError(n)}}resetPingState(){this.pingFailureCount=0,this.lastPingTime=null,this.isPinging=!1}enablePing(){this.pingOptions.enabled=!0,this.logger.info(`${this.config.name} ping\u76D1\u63A7\u5DF2\u542F\u7528`),this.isConnected()&&this.startPingMonitoring()}disablePing(){this.pingOptions.enabled=!1,this.stopPingMonitoring(),this.logger.info(`${this.config.name} ping\u76D1\u63A7\u5DF2\u7981\u7528`)}updatePingOptions(e){let t=this.pingOptions.enabled;this.pingOptions={...this.pingOptions,...e},this.logger.info(`${this.config.name} ping\u914D\u7F6E\u5DF2\u66F4\u65B0`,e),t!==this.pingOptions.enabled&&(this.pingOptions.enabled&&this.isConnected()?this.startPingMonitoring():this.pingOptions.enabled||this.stopPingMonitoring())}getPingOptions(){return{...this.pingOptions}}}});function xt(o){if(!o||typeof o!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u6709\u6548\u7684\u5BF9\u8C61");if("command"in o&&typeof o.command=="string")return"stdio";if("type"in o&&o.type==="sse")return"sse";if("type"in o&&o.type==="streamable-http"||"url"in o&&typeof o.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 he(o,e){if(!e||typeof e!="object")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61`};try{switch(xt(e)){case"stdio":if(!e.command||typeof e.command!="string")return{valid:!1,error:`\u670D\u52A1 "${o}" \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 "${o}" \u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4`};if(e.env&&typeof e.env!="object")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;case"sse":if(e.type!=="sse")return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684 type \u5B57\u6BB5\u5FC5\u987B\u662F "sse"`};if(!e.url||typeof e.url!="string")return{valid:!1,error:`\u670D\u52A1 "${o}" \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 "${o}" \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 "${o}" \u7684 type \u5B57\u6BB5\u5982\u679C\u5B58\u5728\uFF0C\u5FC5\u987B\u662F "streamable-http"`};break;default:return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684\u914D\u7F6E\u7C7B\u578B\u65E0\u6CD5\u8BC6\u522B`}}return{valid:!0}}catch(t){return{valid:!1,error:`\u670D\u52A1 "${o}" \u7684\u914D\u7F6E\u65E0\u6548: ${t instanceof Error?t.message:"\u672A\u77E5\u9519\u8BEF"}`}}}var Re=N(()=>{"use strict";c(xt,"getMcpServerCommunicationType");c(he,"validateMcpServerConfig")});import{copyFileSync as $t,existsSync as pe,readFileSync as Rt,writeFileSync as Ot}from"fs";import{dirname as At,resolve as B}from"path";import{fileURLToPath as Nt}from"url";import*as re from"comment-json";import Dt from"dayjs";import fe from"json5";import*as Oe from"json5-writer";var zt,ue,me,g,z=N(()=>{"use strict";x();Re();zt=At(Nt(import.meta.url)),ue={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},me=class o{static{c(this,"ConfigManager")}static instance;defaultConfigPath;config=null;currentConfigPath=null;json5Writer=null;constructor(){this.defaultConfigPath=B(zt,"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 n of t){let r=B(e,n);if(pe(r))return r}return B(e,"xiaozhi.config.json")}getConfigFileFormat(e){return e.endsWith(".json5")?"json5":e.endsWith(".jsonc")?"jsonc":"json"}static getInstance(){return o.instance||(o.instance=new o),o.instance}configExists(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let n of t){let r=B(e,n);if(pe(r))return!0}return!1}initConfig(e="json"){if(!pe(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(),n=`xiaozhi.config.${e}`,r=B(t,n);$t(this.defaultConfigPath,r),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),r=Rt(e,"utf8").replace(/^\uFEFF/,""),i;switch(t){case"json5":i=fe.parse(r),this.json5Writer=Oe.load(r);break;case"jsonc":i=re.parse(r);break;default:i=JSON.parse(r);break}return this.validateConfig(i),i}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 n of t.mcpEndpoint)if(typeof n!="string"||n.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[n,r]of Object.entries(t.mcpServers)){if(!r||typeof r!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${n} \u65E0\u6548`);let i=he(n,r);if(!i.valid)throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A${i.error}`)}}getConfig(){return 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 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.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(),n=this.getMcpEndpoints();if(n.includes(e))throw new Error(`MCP \u7AEF\u70B9 ${e} \u5DF2\u5B58\u5728`);let r=[...n,e];t.mcpEndpoint=r,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(),n=this.getMcpEndpoints();if(n.indexOf(e)===-1)throw new Error(`MCP \u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728`);if(n.length===1)throw new Error("\u4E0D\u80FD\u5220\u9664\u6700\u540E\u4E00\u4E2A MCP \u7AEF\u70B9");let i=n.filter(s=>s!==e);t.mcpEndpoint=i,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 n=he(e,t);if(!n.valid)throw new Error(n.error||"\u670D\u52A1\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");let r=this.getMutableConfig();r.mcpServers[e]=t,this.saveConfig(r)}removeMcpServer(e){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getConfig();if(!t.mcpServers[e])throw new Error(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728`);let n={...t.mcpServers};delete n[e];let r={...t,mcpServers:n};this.saveConfig(r)}updateServerToolsConfig(e,t){let n=this.getMutableConfig();n.mcpServerConfig||(n.mcpServerConfig={}),Object.keys(t).length===0?delete n.mcpServerConfig[e]:n.mcpServerConfig[e]={tools:t},this.saveConfig(n)}removeServerToolsConfig(e){let n={...this.getConfig()};n.mcpServerConfig&&(delete n.mcpServerConfig[e],this.saveConfig(n))}setToolEnabled(e,t,n,r){let i=this.getMutableConfig();i.mcpServerConfig||(i.mcpServerConfig={}),i.mcpServerConfig[e]||(i.mcpServerConfig[e]={tools:{}}),i.mcpServerConfig[e].tools[t]={...i.mcpServerConfig[e].tools[t],enable:n,...r&&{description:r}},this.saveConfig(i)}saveConfig(e){try{this.validateConfig(e);let t;this.currentConfigPath?t=this.currentConfigPath:(t=this.getConfigFilePath(),this.currentConfigPath=t);let n=this.getConfigFileFormat(t),r;switch(n){case"json5":try{this.json5Writer?(this.json5Writer.write(e),r=this.json5Writer.toSource()):(console.warn("\u6CA1\u6709 json5Writer \u5B9E\u4F8B\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON5 \u683C\u5F0F"),r=fe.stringify(e,null,2))}catch(i){console.warn("\u4F7F\u7528 json5-writer \u4FDD\u5B58\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON5 \u683C\u5F0F:",i),r=fe.stringify(e,null,2)}break;case"jsonc":try{r=re.stringify(e,null,2)}catch(i){console.warn("\u4F7F\u7528 comment-json \u4FDD\u5B58\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON \u683C\u5F0F:",i),r=JSON.stringify(e,null,2)}break;default:r=JSON.stringify(e,null,2);break}Ot(t,r,"utf8"),this.config=e,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??ue.heartbeatInterval,heartbeatTimeout:t.heartbeatTimeout??ue.heartbeatTimeout,reconnectInterval:t.reconnectInterval??ue.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)}async updateToolUsageStats(e,t,n){try{let r=this.getMutableConfig();r.mcpServerConfig||(r.mcpServerConfig={}),r.mcpServerConfig[e]||(r.mcpServerConfig[e]={tools:{}}),r.mcpServerConfig[e].tools[t]||(r.mcpServerConfig[e].tools[t]={enable:!0});let i=r.mcpServerConfig[e].tools[t],s=i.usageCount||0,l=i.lastUsedTime;i.usageCount=s+1,(!l||new Date(n)>new Date(l))&&(i.lastUsedTime=Dt(n).format("YYYY-MM-DD HH:mm:ss")),this.saveConfig(r),E.debug(`\u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5DF2\u66F4\u65B0: ${e}/${t}, \u4F7F\u7528\u6B21\u6570: ${i.usageCount}`)}catch(r){E.error(`\u66F4\u65B0\u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5931\u8D25 (${e}/${t}): ${r instanceof Error?r.message:String(r)}`)}}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})}},g=me.getInstance()});var G,Ae,de=N(()=>{"use strict";x();ne();z();G=class{static{c(this,"MCPServiceManager")}services=new Map;configs={};logger;tools=new Map;constructor(e){this.logger=new C().withTag("MCPManager"),this.configs=e||{}}async startAllServices(){this.logger.info("\u6B63\u5728\u542F\u52A8\u6240\u6709 MCP \u670D\u52A1...");let e=Object.entries(this.configs);if(e.length===0){this.logger.warn("\u6CA1\u6709\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1\uFF0C\u8BF7\u4F7F\u7528 addServiceConfig() \u6DFB\u52A0\u670D\u52A1\u914D\u7F6E");return}for(let[t]of e)await this.startService(t);this.logger.info("\u6240\u6709 MCP \u670D\u52A1\u542F\u52A8\u5B8C\u6210")}async startService(e){this.logger.info(`\u542F\u52A8 MCP \u670D\u52A1: ${e}`);let t=this.configs[e];if(!t)throw new Error(`\u672A\u627E\u5230\u670D\u52A1\u914D\u7F6E: ${e}`);try{this.services.has(e)&&await this.stopService(e);let n=new oe(t);await n.connect(),this.services.set(e,n),await this.refreshToolsCache();let r=n.getTools();this.logger.info(`${e} \u670D\u52A1\u542F\u52A8\u6210\u529F\uFF0C\u52A0\u8F7D\u4E86 ${r.length} \u4E2A\u5DE5\u5177:`,r.map(i=>i.name).join(", "))}catch(n){throw this.logger.error(`\u542F\u52A8 ${e} \u670D\u52A1\u5931\u8D25:`,n.message),n}}async stopService(e){this.logger.info(`\u505C\u6B62 MCP \u670D\u52A1: ${e}`);let t=this.services.get(e);if(!t){this.logger.warn(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728\u6216\u672A\u542F\u52A8`);return}try{await t.disconnect(),this.services.delete(e),await this.refreshToolsCache(),this.logger.info(`${e} \u670D\u52A1\u5DF2\u505C\u6B62`)}catch(n){throw this.logger.error(`\u505C\u6B62 ${e} \u670D\u52A1\u5931\u8D25:`,n.message),n}}async refreshToolsCache(){this.tools.clear();for(let[e,t]of this.services)if(t.isConnected()){let n=t.getTools();for(let r of n){let i=`${e}__${r.name}`;this.tools.set(i,{serviceName:e,originalName:r.name,tool:r})}}}getAllTools(){let e=[];for(let[t,n]of this.tools)e.push({name:t,description:n.tool.description||"",inputSchema:n.tool.inputSchema,serviceName:n.serviceName,originalName:n.originalName});return e}async callTool(e,t){this.logger.info(`\u8C03\u7528\u5DE5\u5177: ${e}\uFF0C\u53C2\u6570:`,t);let n=this.tools.get(e);if(!n)throw new Error(`\u672A\u627E\u5230\u5DE5\u5177: ${e}`);let r=this.services.get(n.serviceName);if(!r)throw new Error(`\u670D\u52A1 ${n.serviceName} \u4E0D\u53EF\u7528`);if(!r.isConnected())throw new Error(`\u670D\u52A1 ${n.serviceName} \u672A\u8FDE\u63A5`);try{let i=await r.callTool(n.originalName,t||{});return this.logger.info(`\u5DE5\u5177 ${e} \u8C03\u7528\u6210\u529F\uFF0C\u7ED3\u679C:`,i),i}catch(i){throw this.logger.error(`\u5DE5\u5177 ${e} \u8C03\u7528\u5931\u8D25:`,i.message),i}}async stopAllServices(){this.logger.info("\u6B63\u5728\u505C\u6B62\u6240\u6709 MCP \u670D\u52A1...");for(let[e,t]of this.services)try{await t.disconnect(),this.logger.info(`${e} \u670D\u52A1\u5DF2\u505C\u6B62`)}catch(n){this.logger.error(`\u505C\u6B62 ${e} \u670D\u52A1\u5931\u8D25:`,n.message)}this.services.clear(),this.tools.clear(),this.logger.info("\u6240\u6709 MCP \u670D\u52A1\u5DF2\u505C\u6B62")}getStatus(){let e={services:{},totalTools:this.tools.size,availableTools:Array.from(this.tools.keys())};for(let[t,n]of this.services){let r=n.getStatus();e.services[t]={connected:r.connected,clientName:`xiaozhi-${t}-client`}}return e}getService(e){return this.services.get(e)}getAllServices(){return new Map(this.services)}enhanceServiceConfig(e){let t={...e};try{if(e.type==="modelscope-sse"){let n=g.getModelScopeApiKey();if(n)t.apiKey=n,this.logger.info(`\u4E3A ${e.name} \u670D\u52A1\u6DFB\u52A0 ModelScope API Key`);else throw this.logger.warn(`${e.name} \u670D\u52A1\u9700\u8981 ModelScope API Key\uFF0C\u4F46\u672A\u5728\u914D\u7F6E\u4E2D\u627E\u5230`),new Error(`ModelScope SSE \u670D\u52A1 ${e.name} \u9700\u8981 API Key\uFF0C\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E modelscope.apiKey`)}return t}catch(n){throw this.logger.error(`\u914D\u7F6E\u589E\u5F3A\u5931\u8D25: ${e.name}`,n),n}}addServiceConfig(e,t){let n,r;if(typeof e=="string"&&t)r=e,n=t;else if(typeof e=="object")r=e.name,n=e;else throw new Error("Invalid arguments for addServiceConfig");let i=this.enhanceServiceConfig(n);this.configs[r]=i,this.logger.info(`\u5DF2\u6DFB\u52A0\u5E76\u589E\u5F3A\u670D\u52A1\u914D\u7F6E: ${r}`)}updateServiceConfig(e,t){let n=this.enhanceServiceConfig(t);this.configs[e]=n,this.logger.info(`\u5DF2\u66F4\u65B0\u5E76\u589E\u5F3A\u670D\u52A1\u914D\u7F6E: ${e}`)}removeServiceConfig(e){delete this.configs[e],this.logger.info(`\u5DF2\u79FB\u9664\u670D\u52A1\u914D\u7F6E: ${e}`)}},Ae=G});var Je={};et(Je,{MCPServer:()=>we});import{spawn as on}from"child_process";import{randomUUID as rn}from"crypto";import{EventEmitter as sn}from"events";import se from"fs";import an from"os";import b from"path";import{fileURLToPath as Ge}from"url";import Pe from"express";var cn,K,u,V,ln,we,Ze=N(()=>{"use strict";te();z();x();de();cn=Ge(import.meta.url),K=b.dirname(cn),u=E.withTag("mcp-server"),V="mcpServerProxy.js",ln=5,we=class extends sn{static{c(this,"MCPServer")}app;server=null;clients=new Map;mcpProxy=null;proxyMCPServer=null;mcpServiceManager=null;mcpProxyPath=null;port;constructor(e=3e3){super(),this.port=e,this.app=Pe(),this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){this.app.use(Pe.json()),this.app.use(Pe.urlencoded({extended:!0})),this.app.use((e,t,n)=>{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"),n()})}setupRoutes(){this.app.get("/sse",(e,t)=>{let n=Date.now().toString(),r=rn();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(r,{id:n,sessionId:r,response:t}),u.info(`MCP\u5BA2\u6237\u7AEF\u5DF2\u8FDE\u63A5: ${n} (\u4F1A\u8BDD: ${r})`),t.write(`event: endpoint
4
+ data: /messages?sessionId=${r}
8
5
 
9
- `),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)}
10
- `),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)}
6
+ `),e.on("close",()=>{this.clients.delete(r),u.info(`MCP\u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00\u8FDE\u63A5: ${n} (\u4F1A\u8BDD: ${r})`)})}),this.app.post("/messages",async(e,t)=>{try{let n=e.query.sessionId,r=e.body;if(u.info(`\u901A\u8FC7SSE\u4F20\u8F93\u6536\u5230\u6D88\u606F (\u4F1A\u8BDD: ${n}):`,JSON.stringify(r)),!n||!this.clients.has(n)){t.status(400).json({jsonrpc:"2.0",error:{code:-32600,message:"\u65E0\u6548\u6216\u7F3A\u5C11sessionId"},id:r.id});return}if(!this.mcpProxy){t.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP\u4EE3\u7406\u672A\u8FD0\u884C"},id:r.id});return}if(r.id===void 0)u.info(`\u8F6C\u53D1\u901A\u77E5: ${r.method}`),this.mcpProxy.stdin.write(`${JSON.stringify(r)}
7
+ `),t.status(202).send();else{let i=await this.forwardToProxy(r),s=this.clients.get(n);s&&this.sendToClient(s,i),t.status(202).send()}}catch(n){u.error("SSE\u6D88\u606F\u9519\u8BEF:",n),t.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:n instanceof Error?n.message:"\u5185\u90E8\u9519\u8BEF"},id:e.body.id})}}),this.app.post("/rpc",async(e,t)=>{try{let n=e.body;if(u.debug("\u6536\u5230RPC\u6D88\u606F:",n),!this.mcpProxy){t.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP\u4EE3\u7406\u672A\u8FD0\u884C"},id:n.id});return}let r=await this.forwardToProxy(n);t.json(r)}catch(n){u.error("RPC\u9519\u8BEF:",n),t.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:n instanceof Error?n.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,n)=>{if(!this.mcpProxy||!this.mcpProxy.stdin||!this.mcpProxy.stdout){n(new Error("MCP\u4EE3\u7406\u4E0D\u53EF\u7528"));return}let r=setTimeout(()=>{this.pendingRequests.delete(e.id),u.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:n,timeoutId:r}),u.info(`\u8F6C\u53D1\u6D88\u606F\u5230\u4EE3\u7406: ${JSON.stringify(e)}`),this.mcpProxy.stdin.write(`${JSON.stringify(e)}
11
8
  `)})}handleProxyResponse(e){try{this.responseBuffer+=e.toString();let t=this.responseBuffer.split(`
12
- `);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
9
+ `);this.responseBuffer=t.pop()||"";for(let n of t)if(n.trim())try{let r=JSON.parse(n);if(u.debug(`\u6536\u5230\u4EE3\u7406\u54CD\u5E94: ${n.substring(0,200)}...`),r.id!==void 0&&this.pendingRequests.has(r.id)){let i=this.pendingRequests.get(r.id);clearTimeout(i.timeoutId),this.pendingRequests.delete(r.id),i.resolve(r)}}catch{u.debug(`\u6765\u81EA\u4EE3\u7406\u7684\u975EJSON\u884C: ${n}`)}}catch(t){u.error("\u5904\u7406\u4EE3\u7406\u54CD\u5E94\u65F6\u51FA\u9519:",t)}}sendToClient(e,t){try{let n=`event: message
13
10
  data: ${JSON.stringify(t)}
14
11
 
15
- `;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=P.normalize(process.env.MCP_SERVER_PROXY_PATH),s=P.resolve(n),c=[D,P.join(D,".."),P.join(D,"..",".."),P.join(D,"..","..","dist"),tt.tmpdir()];if(U.existsSync(s)&&P.basename(s)===z&&c.some(a=>s.startsWith(a)))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=Se(import.meta.url),t=P.dirname(e),o=null;for(let n=0;n<nt;n++){let s=P.join(t,z);if(U.existsSync(s)){o=s;break}let c=P.join(t,"dist",z);if(U.existsSync(c)){o=c;break}t=P.dirname(t)}if(!o){let n=P.resolve(D,"..",".."),s=P.join(n,"dist",z);U.existsSync(s)&&(o=s)}if(!o)throw new Error(`\u5728\u9879\u76EE\u7ED3\u6784\u4E2D\u627E\u4E0D\u5230 ${z}`);return this.mcpProxyPath=o,this.mcpProxyPath}async startMCPProxy(){let e=this.findMCPProxyPath();m.info(`\u6B63\u5728\u542F\u52A8MCP\u4EE3\u7406: ${e}`),this.mcpProxy=Ke("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=g(c=>{let a=c.toString();(a.includes("MCP proxy ready")||a.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{l.configExists()&&(e=l.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 te}from"child_process";import b from"fs";import f from"path";import{fileURLToPath as j}from"url";import i from"chalk";import{Command as rt}from"commander";import I from"ora";x();import He from"omelette";function Le(){try{if(!l.configExists())return[];let r=l.getMcpServers();return Object.keys(r)}catch{return[]}}g(Le,"getMcpServerNames");function Ge(r){try{if(!l.configExists())return[];let e=l.getServerToolsConfig(r);return Object.keys(e)}catch{return[]}}g(Ge,"getServerToolNames");function ae(){let r=He("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+/),a=t!==t.trim()?s.length:s.length-1;if(s[1]==="mcp"){let u=s[2];if(a===2){let h=["list","server","tool"],y=s[2]||"",C=h.filter(S=>S.startsWith(y));n(C);return}if(a===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=Le(),y=s[3]||"",C=h.filter(S=>S.startsWith(y));n(C);break}default:n([])}return}if(a===4&&u==="tool"){let h=s[3],y=Ge(h),C=s[4]||"",S=y.filter(R=>R.startsWith(C));n(S);return}if(a===5&&u==="tool"){let h=["enable","disable"],y=s[5]||"",C=h.filter(S=>S.startsWith(y));n(C);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(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")}g(le,"showCompletionHelp");x();$();x();import p from"chalk";import ge from"cli-table3";import Y from"ora";function pe(r){let e=0;for(let t of r)/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(t)?e+=2:e+=1;return e}g(pe,"getDisplayWidth");function fe(r,e){if(pe(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}g(fe,"truncateToWidth");async function de(r={}){let e=Y("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868...").start();try{let t=l.getMcpServers(),o=Object.keys(t);if(o.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 ${o.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 o){let u=l.getServerToolsConfig(a),h=Object.keys(u);s.push(...h)}for(let a of s){let u=pe(a);u>n&&(n=u)}n=Math.max(10,Math.min(n+2,30));let c=new ge({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 o){let u=l.getServerToolsConfig(a),h=Object.keys(u);if(h.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 h){let C=u[y],S=C.enable?p.green("\u542F\u7528"):p.red("\u7981\u7528"),R=fe(C.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 o){let s=t[n],c=l.getServerToolsConfig(n),a=Object.keys(c).length,u=Object.values(c).filter(h=>h.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(u)} \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(t){e.fail("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868\u5931\u8D25"),console.error(p.red(`\u9519\u8BEF: ${t instanceof Error?t.message:String(t)}`)),process.exit(1)}}g(de,"listMcpServers");async function ue(r){let e=Y(`\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 o=l.getServerToolsConfig(r),n=Object.keys(o);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 ge({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=o[c],u=a.enable?p.green("\u542F\u7528"):p.red("\u7981\u7528"),h=fe(a.description||"",40);s.push([c,u,h])}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(t){e.fail("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25"),console.error(p.red(`\u9519\u8BEF: ${t instanceof Error?t.message:String(t)}`)),process.exit(1)}}g(ue,"listServerTools");async function me(r,e,t){let o=t?"\u542F\u7528":"\u7981\u7528",n=Y(`${o}\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,t,c[e].description),n.succeed(`\u6210\u529F${o}\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(`${o}\u5DE5\u5177\u5931\u8D25`),console.error(p.red(`\u9519\u8BEF: ${s instanceof Error?s.message:String(s)}`)),process.exit(1)}}g(me,"setToolEnabled");import{spawn as he}from"child_process";import{existsSync as K}from"fs";import{readFile as ye}from"fs/promises";import{createServer as Ue}from"http";import{dirname as Je,join as E}from"path";import{fileURLToPath as Xe}from"url";import{serve as Be}from"@hono/node-server";import{Hono as Ze}from"hono";import{cors as Ve}from"hono/cors";import{WebSocketServer as qe}from"ws";x();$();var F=class{static{g(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=l.getWebUIPort()}catch{this.port=9999}else this.port=e;this.logger=new A,this.app=new Ze,this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){this.app.use("*",Ve({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=l.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=Je(Xe(import.meta.url)),s=[E(o,"..","web","dist"),E(o,"..","web"),E(process.cwd(),"web","dist"),E(process.cwd(),"web")].find(S=>K(S));if(!s)return e.html(`
12
+ `;e.response.write(n)}catch(n){u.error(`\u53D1\u9001\u5230\u5BA2\u6237\u7AEF ${e.id} \u5931\u8D25:`,n),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(r=>{this.server=this.app.listen(this.port,"0.0.0.0",()=>{u.info(`MCP\u670D\u52A1\u5668\u76D1\u542C\u7AEF\u53E3 ${this.port} (\u6240\u6709\u7F51\u7EDC\u63A5\u53E3)`),u.info(`SSE\u7AEF\u70B9: http://0.0.0.0:${this.port}/sse`),u.info(`\u6D88\u606F\u7AEF\u70B9: http://0.0.0.0:${this.port}/messages`),u.info(`RPC\u7AEF\u70B9: http://0.0.0.0:${this.port}/rpc`),u.info(`\u672C\u5730\u8BBF\u95EE: http://localhost:${this.port}`),r()})})]),[t,n]=e;if(t.status==="rejected"&&u.error("MCP\u4EE3\u7406\u542F\u52A8\u5931\u8D25:",t.reason),n.status==="rejected")throw u.error("HTTP\u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25:",n.reason),n.reason;this.startMCPClient().catch(r=>{u.error("\u542F\u52A8\u8FDE\u63A5\u5230xiaozhi.me\u7684MCP\u5BA2\u6237\u7AEF\u5931\u8D25:",r)}),this.emit("started")}catch(e){throw u.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 r=b.normalize(process.env.MCP_SERVER_PROXY_PATH),i=b.resolve(r),s=[K,b.join(K,".."),b.join(K,"..",".."),b.join(K,"..","..","dist"),an.tmpdir()];if(se.existsSync(i)&&b.basename(i)===V&&s.some(l=>i.startsWith(l)))return this.mcpProxyPath=i,this.mcpProxyPath;throw u.warn(`MCP_SERVER_PROXY_PATH \u8DEF\u5F84\u4E0D\u5B89\u5168: ${r}`),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=Ge(import.meta.url),t=b.dirname(e),n=null;for(let r=0;r<ln;r++){let i=b.join(t,V);if(se.existsSync(i)){n=i;break}let s=b.join(t,"dist",V);if(se.existsSync(s)){n=s;break}t=b.dirname(t)}if(!n){let r=b.resolve(K,"..",".."),i=b.join(r,"dist",V);se.existsSync(i)&&(n=i)}if(!n)throw new Error(`\u5728\u9879\u76EE\u7ED3\u6784\u4E2D\u627E\u4E0D\u5230 ${V}`);return this.mcpProxyPath=n,this.mcpProxyPath}async startMCPProxy(){let e=this.findMCPProxyPath();u.info(`\u6B63\u5728\u542F\u52A8MCP\u4EE3\u7406: ${e}`),this.mcpProxy=on("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=>{u.error("MCP\u4EE3\u7406\u9519\u8BEF:",t)}),this.mcpProxy.on("exit",(t,n)=>{u.warn(`MCP\u4EE3\u7406\u9000\u51FA\uFF0C\u4EE3\u7801 ${t}\uFF0C\u4FE1\u53F7 ${n}`),this.mcpProxy=null}),this.mcpProxy.stderr&&this.mcpProxy.stderr.on("data",t=>{let n=t.toString().trim();n.includes("[ERROR]")||n.includes("Error:")||n.includes("Failed")?u.error("MCP\u4EE3\u7406stderr:",n):u.info("MCP\u4EE3\u7406\u8F93\u51FA:",n)}),this.mcpProxy.stdout&&this.mcpProxy.stdout.on("data",t=>{this.handleProxyResponse(t)}),await new Promise((t,n)=>{let r=setTimeout(()=>{n(new Error("MCP\u4EE3\u7406\u542F\u52A8\u8D85\u65F6"))},1e4),i=c(s=>{let l=s.toString();(l.includes("MCP proxy ready")||l.includes("started"))&&(clearTimeout(r),this.mcpProxy?.stdout?.removeListener("data",i),t())},"dataHandler");this.mcpProxy?.stdout?.on("data",i)}),u.info("MCP\u4EE3\u7406\u542F\u52A8\u6210\u529F")}async startMCPClient(){try{this.mcpServiceManager=new G;let e=null;try{g.configExists()&&(e=g.getMcpEndpoints().find(n=>n&&!n.includes("<\u8BF7\u586B\u5199"))||null)}catch(t){u.warn("\u4ECE\u914D\u7F6E\u4E2D\u8BFB\u53D6\u5C0F\u667A\u63A5\u5165\u70B9\u5931\u8D25:",t)}e?(this.proxyMCPServer=new D(e),this.proxyMCPServer.setServiceManager(this.mcpServiceManager),await this.proxyMCPServer.connect(),u.info("\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u6210\u529F")):u.info("\u672A\u914D\u7F6E\u6709\u6548\u7684\u5C0F\u667A\u63A5\u5165\u70B9\uFF0C\u8DF3\u8FC7\u8FDE\u63A5")}catch(e){u.error("\u542F\u52A8MCP\u5BA2\u6237\u7AEF\u5931\u8D25:",e)}}async stop(){u.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.proxyMCPServer&&(await this.proxyMCPServer.disconnect(),this.proxyMCPServer=null),this.mcpServiceManager&&(await this.mcpServiceManager.stopAllServices(),this.mcpServiceManager=null),this.mcpProxyPath=null,this.emit("stopped"),u.info("MCP\u670D\u52A1\u5668\u5DF2\u505C\u6B62")}}});import{spawn as gn}from"child_process";import d from"fs";import m from"path";import{fileURLToPath as U}from"url";import a from"chalk";import{Command as hn}from"commander";import M from"ora";te();import{spawn as Fe}from"child_process";import{existsSync as ve}from"fs";import{readFile as Le}from"fs/promises";import{createServer as Kt}from"http";import{dirname as Vt,join as H}from"path";import{fileURLToPath as Yt}from"url";import{serve as Qt}from"@hono/node-server";import{Hono as en}from"hono";import{cors as tn}from"hono/cors";import{WebSocketServer as nn}from"ws";x();ne();var ge=E.withTag("ConfigAdapter"),v=class extends Error{constructor(t,n){super(t);this.configName=n;this.name="ConfigValidationError"}static{c(this,"ConfigValidationError")}};function $e(o,e){ge.debug(`\u8F6C\u6362\u914D\u7F6E: ${o}`,e);try{if(!o||typeof o!="string")throw new v("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!e||typeof e!="object")throw new v("\u914D\u7F6E\u5BF9\u8C61\u4E0D\u80FD\u4E3A\u7A7A",o);let t=vt(o,e);return It(t),ge.info(`\u914D\u7F6E\u8F6C\u6362\u6210\u529F: ${o} -> ${t.type}`),t}catch(t){throw ge.error(`\u914D\u7F6E\u8F6C\u6362\u5931\u8D25: ${o}`,t),t instanceof v?t:new v(`\u914D\u7F6E\u8F6C\u6362\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`,o)}}c($e,"convertLegacyToNew");function vt(o,e){if(bt(e))return yt(o,e);if(Mt(e))return Pt(o,e);if(Et(e))return wt(o,e);throw new v("\u65E0\u6CD5\u8BC6\u522B\u7684\u914D\u7F6E\u7C7B\u578B",o)}c(vt,"convertByConfigType");function yt(o,e){if(!e.command)throw new v("\u672C\u5730\u914D\u7F6E\u5FC5\u987B\u5305\u542B command \u5B57\u6BB5",o);return{name:o,type:"stdio",command:e.command,args:e.args||[],reconnect:{enabled:!0,maxAttempts:5,initialInterval:3e3,maxInterval:3e4,backoffStrategy:"exponential",backoffMultiplier:1.5,timeout:1e4,jitter:!0},ping:{enabled:!0,interval:3e4,timeout:5e3,maxFailures:3,startDelay:5e3},timeout:3e4}}c(yt,"convertLocalConfig");function Pt(o,e){if(!e.url)throw new v("SSE \u914D\u7F6E\u5FC5\u987B\u5305\u542B url \u5B57\u6BB5",o);let t=Tt(e.url),n={name:o,type:t?"modelscope-sse":"sse",url:e.url,reconnect:{enabled:!0,maxAttempts:10,initialInterval:3e3,maxInterval:3e4,backoffStrategy:"exponential",backoffMultiplier:1.5,timeout:15e3,jitter:!0},ping:{enabled:!0,interval:3e4,timeout:5e3,maxFailures:3,startDelay:5e3},timeout:3e4};return t&&(n.modelScopeAuth=!0),n}c(Pt,"convertSSEConfig");function wt(o,e){if(!e.url)throw new v("Streamable HTTP \u914D\u7F6E\u5FC5\u987B\u5305\u542B url \u5B57\u6BB5",o);return{name:o,type:"streamable-http",url:e.url,reconnect:{enabled:!0,maxAttempts:5,initialInterval:3e3,maxInterval:3e4,backoffStrategy:"exponential",backoffMultiplier:1.5,timeout:15e3,jitter:!0},ping:{enabled:!1,interval:6e4,timeout:1e4,maxFailures:3,startDelay:1e4},timeout:3e4}}c(wt,"convertStreamableHTTPConfig");function bt(o){return"command"in o&&typeof o.command=="string"}c(bt,"isLocalConfig");function Mt(o){return"type"in o&&o.type==="sse"&&"url"in o}c(Mt,"isSSEConfig");function Et(o){return"url"in o&&(!("type"in o)||o.type==="streamable-http")}c(Et,"isStreamableHTTPConfig");function Tt(o){return o.includes("modelscope.net")||o.includes("modelscope.cn")}c(Tt,"isModelScopeURL");function It(o){if(!o.name||typeof o.name!="string")throw new v("\u914D\u7F6E\u5FC5\u987B\u5305\u542B\u6709\u6548\u7684 name \u5B57\u6BB5");if(!Object.values(X).includes(o.type))throw new v(`\u65E0\u6548\u7684\u4F20\u8F93\u7C7B\u578B: ${o.type}`);switch(o.type){case"stdio":if(!o.command)throw new v("STDIO \u914D\u7F6E\u5FC5\u987B\u5305\u542B command \u5B57\u6BB5");break;case"sse":case"modelscope-sse":case"streamable-http":if(!o.url)throw new v(`${o.type} \u914D\u7F6E\u5FC5\u987B\u5305\u542B url \u5B57\u6BB5`);break;default:throw new v(`\u4E0D\u652F\u6301\u7684\u4F20\u8F93\u7C7B\u578B: ${o.type}`)}}c(It,"validateNewConfig");z();x();de();var R=null,$=null,y="not_initialized",J=null,k=null;async function kt(){return console.log("\u{1F680} \u6B63\u5728\u521D\u59CB\u5316 MCPServiceManager \u5355\u4F8B..."),new Ae}c(kt,"createInstance");async function Ne(){if(R&&y==="initialized")return R;if($&&y==="initializing")return $;y==="failed"&&Se(),y="initializing",$=kt();try{return R=await $,y="initialized",k=`mcp-manager-${Date.now()}-${Math.random().toString(36).substring(2,11)}`,J=null,console.log(`\u2705 MCPServiceManager \u5355\u4F8B\u521D\u59CB\u5316\u6210\u529F\uFF0C\u5B9E\u4F8BID: ${k}`),R}catch(o){throw y="failed",J=o,$=null,console.error("\u274C MCPServiceManager \u5355\u4F8B\u521D\u59CB\u5316\u5931\u8D25:",o.message),o}}c(Ne,"getInstance");async function De(){if(y==="cleanup"){console.log("\u26A0\uFE0F MCPServiceManager \u5355\u4F8B\u5DF2\u5728\u6E05\u7406\u4E2D\uFF0C\u8DF3\u8FC7\u91CD\u590D\u6E05\u7406");return}console.log("\u{1F9F9} \u6B63\u5728\u6E05\u7406 MCPServiceManager \u5355\u4F8B\u8D44\u6E90..."),y="cleanup";try{if($){try{await(await $).stopAllServices()}catch(o){console.error("\u6E05\u7406\u521D\u59CB\u5316\u4E2D\u7684\u5B9E\u4F8B\u5931\u8D25:",o.message)}$=null}R&&(await R.stopAllServices(),R=null),y="not_initialized",J=null,k=null,console.log("\u2705 MCPServiceManager \u5355\u4F8B\u8D44\u6E90\u6E05\u7406\u5B8C\u6210")}catch(o){throw console.error("\u274C MCPServiceManager \u5355\u4F8B\u6E05\u7406\u5931\u8D25:",o.message),Se(),o}}c(De,"cleanup");function Se(){console.log("\u{1F504} \u91CD\u7F6E MCPServiceManager \u5355\u4F8B\u72B6\u6001"),R=null,$=null,y="not_initialized",J=null,k=null}c(Se,"reset");function jt(){return y==="initialized"&&R!==null}c(jt,"isInitialized");function Ft(){return{state:y,initializationTime:k?new Date:void 0,lastError:J||void 0,instanceId:k||void 0}}c(Ft,"getStatus");async function Lt(){return console.log("\u{1F504} \u5F3A\u5236\u91CD\u65B0\u521D\u59CB\u5316 MCPServiceManager \u5355\u4F8B..."),await De(),Ne()}c(Lt,"forceReinitialize");function Ht(){return R}c(Ht,"getCurrentInstance");async function _t(){if(y==="initialized")return!0;if(y==="initializing"&&$)try{return await $,!0}catch{return!1}return!1}c(_t,"waitForInitialization");var j={getInstance:Ne,cleanup:De,reset:Se,isInitialized:jt,getStatus:Ft,forceReinitialize:Lt,getCurrentInstance:Ht,waitForInitialization:_t};process.on("exit",()=>{j.isInitialized()&&(console.log("\u{1F504} \u8FDB\u7A0B\u9000\u51FA\uFF0C\u6B63\u5728\u6E05\u7406 MCPServiceManager \u5355\u4F8B..."),j.reset())});process.on("uncaughtException",async o=>{console.error("\u{1F4A5} \u672A\u6355\u83B7\u7684\u5F02\u5E38\uFF0C\u6E05\u7406 MCPServiceManager \u5355\u4F8B:",o);try{await j.cleanup()}catch(e){console.error("\u6E05\u7406\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",e)}});process.on("unhandledRejection",async o=>{console.error("\u{1F4A5} \u672A\u5904\u7406\u7684Promise\u62D2\u7EDD\uFF0C\u6E05\u7406 MCPServiceManager \u5355\u4F8B:",o);try{await j.cleanup()}catch(e){console.error("\u6E05\u7406\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",e)}});te();x();import{EventEmitter as Ut}from"events";var ze=(r=>(r.EXPONENTIAL_BACKOFF="exponential_backoff",r.LINEAR_BACKOFF="linear_backoff",r.FIXED_INTERVAL="fixed_interval",r.ADAPTIVE="adaptive",r))(ze||{});var Wt={healthCheckInterval:3e4,reconnectInterval:5e3,maxReconnectAttempts:10,loadBalanceStrategy:"round-robin",connectionTimeout:1e4,reconnectStrategy:"exponential_backoff",maxReconnectDelay:3e4,reconnectBackoffMultiplier:2,jitterEnabled:!0},ie=class extends Ut{static{c(this,"XiaozhiConnectionManager")}connections=new Map;connectionStates=new Map;mcpServiceManager=null;logger;isInitialized=!1;isConnecting=!1;options;healthCheckInterval=null;reconnectTimers=new Map;roundRobinIndex=0;lastSelectedEndpoint=null;performanceMetrics={connectionStartTime:0,totalConnectionTime:0,averageConnectionTime:0,connectionCount:0,memoryUsage:{initial:0,current:0,peak:0},prewarmedConnections:new Set};constructor(e){super(),this.logger=new C,this.options={...Wt,...e},this.logger.info("XiaozhiConnectionManager \u5B9E\u4F8B\u5DF2\u521B\u5EFA"),this.logger.debug("\u914D\u7F6E\u9009\u9879:",this.options)}async initialize(e,t){if(this.isInitialized){this.logger.warn("XiaozhiConnectionManager \u5DF2\u7ECF\u521D\u59CB\u5316\uFF0C\u8DF3\u8FC7\u91CD\u590D\u521D\u59CB\u5316");return}this.logger.info(`\u5F00\u59CB\u521D\u59CB\u5316 XiaozhiConnectionManager\uFF0C\u7AEF\u70B9\u6570\u91CF: ${e.length}`);try{this.validateInitializeParams(e,t),await this.cleanup();for(let n of e)await this.createConnection(n,t);this.isInitialized=!0,this.performanceMetrics.memoryUsage.initial=process.memoryUsage().heapUsed,this.performanceMetrics.memoryUsage.current=this.performanceMetrics.memoryUsage.initial,this.performanceMetrics.memoryUsage.peak=this.performanceMetrics.memoryUsage.initial,this.logger.info(`XiaozhiConnectionManager \u521D\u59CB\u5316\u5B8C\u6210\uFF0C\u7BA1\u7406 ${this.connections.size} \u4E2A\u8FDE\u63A5`)}catch(n){throw this.logger.error("XiaozhiConnectionManager \u521D\u59CB\u5316\u5931\u8D25:",n),await this.cleanup(),n}}async connect(){if(!this.isInitialized)throw new Error("XiaozhiConnectionManager \u672A\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u8C03\u7528 initialize()");if(this.isConnecting){this.logger.warn("\u8FDE\u63A5\u64CD\u4F5C\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210");return}this.isConnecting=!0,this.performanceMetrics.connectionStartTime=Date.now(),this.logger.info(`\u5F00\u59CB\u8FDE\u63A5\u6240\u6709\u7AEF\u70B9\uFF0C\u603B\u6570: ${this.connections.size}`);try{let e=[];for(let[s,l]of this.connections)e.push(this.connectSingleEndpoint(s,l));let t=await Promise.allSettled(e),n=t.filter(s=>s.status==="fulfilled").length,r=t.length-n,i=Date.now()-this.performanceMetrics.connectionStartTime;if(this.performanceMetrics.totalConnectionTime+=i,this.performanceMetrics.connectionCount++,this.performanceMetrics.averageConnectionTime=this.performanceMetrics.totalConnectionTime/this.performanceMetrics.connectionCount,this.logger.info(`\u8FDE\u63A5\u5B8C\u6210 - \u6210\u529F: ${n}, \u5931\u8D25: ${r}, \u8017\u65F6: ${i}ms`),n===0)throw new Error("\u6240\u6709\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u5931\u8D25");this.startHealthCheck()}finally{this.isConnecting=!1}}async disconnect(){this.logger.info("\u5F00\u59CB\u65AD\u5F00\u6240\u6709\u8FDE\u63A5"),this.stopHealthCheck(),this.clearAllReconnectTimers();let e=[];for(let[t,n]of this.connections)e.push(this.disconnectSingleEndpoint(t,n));await Promise.allSettled(e),this.logger.info("\u6240\u6709\u8FDE\u63A5\u5DF2\u65AD\u5F00")}async addEndpoint(e){if(!this.isInitialized)throw new Error("XiaozhiConnectionManager \u672A\u521D\u59CB\u5316");if(this.connections.has(e)){this.logger.warn(`\u7AEF\u70B9 ${e} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u6DFB\u52A0`);return}this.logger.info(`\u52A8\u6001\u6DFB\u52A0\u7AEF\u70B9: ${e}`);try{let t=this.getCurrentTools();if(await this.createConnection(e,t),this.isAnyConnected()){let n=this.connections.get(e);await this.connectSingleEndpoint(e,n)}this.logger.info(`\u7AEF\u70B9 ${e} \u6DFB\u52A0\u6210\u529F`)}catch(t){throw this.logger.error(`\u6DFB\u52A0\u7AEF\u70B9 ${e} \u5931\u8D25:`,t),this.connections.delete(e),this.connectionStates.delete(e),t}}async removeEndpoint(e){if(!this.connections.has(e)){this.logger.warn(`\u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u79FB\u9664`);return}this.logger.info(`\u52A8\u6001\u79FB\u9664\u7AEF\u70B9: ${e}`);try{let t=this.connections.get(e);await this.disconnectSingleEndpoint(e,t),this.connections.delete(e),this.connectionStates.delete(e);let n=this.reconnectTimers.get(e);n&&(clearTimeout(n),this.reconnectTimers.delete(e)),this.logger.info(`\u7AEF\u70B9 ${e} \u79FB\u9664\u6210\u529F`)}catch(t){throw this.logger.error(`\u79FB\u9664\u7AEF\u70B9 ${e} \u5931\u8D25:`,t),t}}getHealthyConnections(){let e=[];for(let[t,n]of this.connections){let r=this.connectionStates.get(t);r?.connected&&r.healthScore>50&&e.push(n)}return e}getConnectionStatus(){return Array.from(this.connectionStates.values())}isAnyConnected(){for(let e of this.connectionStates.values())if(e.connected)return!0;return!1}setServiceManager(e){this.mcpServiceManager=e,this.logger.info("\u5DF2\u8BBE\u7F6E MCPServiceManager"),this.connections.size>0&&this.syncToolsToAllConnections()}setHealthCheckEnabled(e,t){let n=this.connectionStates.get(e);n?(n.healthCheckEnabled=t,this.logger.info(`\u7AEF\u70B9 ${e} \u5065\u5EB7\u68C0\u67E5\u5DF2${t?"\u542F\u7528":"\u7981\u7528"}`)):this.logger.warn(`\u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u8BBE\u7F6E\u5065\u5EB7\u68C0\u67E5\u72B6\u6001`)}getHealthCheckStats(){let e={};for(let[t,n]of this.connectionStates){let r=n.totalRequests>0?n.successfulRequests/n.totalRequests*100:0;e[t]={endpoint:t,healthScore:n.healthScore,successRate:Math.round(r*100)/100,averageResponseTime:n.responseTime||0,consecutiveFailures:n.consecutiveFailures,lastHealthCheck:n.lastHealthCheck,lastSuccessTime:n.lastSuccessTime}}return e}async triggerHealthCheck(){this.logger.info("\u624B\u52A8\u89E6\u53D1\u5065\u5EB7\u68C0\u67E5"),await this.performHealthCheck()}async triggerReconnect(e){let t=this.connectionStates.get(e);if(!t)throw new Error(`\u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728`);if(t.connected){this.logger.warn(`\u7AEF\u70B9 ${e} \u5DF2\u8FDE\u63A5\uFF0C\u65E0\u9700\u91CD\u8FDE`);return}this.logger.info(`\u624B\u52A8\u89E6\u53D1\u91CD\u8FDE: ${e}`);let n=this.reconnectTimers.get(e);n&&(clearTimeout(n),this.reconnectTimers.delete(e)),await this.performReconnect(e)}stopReconnect(e){let t=this.connectionStates.get(e);if(!t){this.logger.warn(`\u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728`);return}let n=this.reconnectTimers.get(e);n&&(clearTimeout(n),this.reconnectTimers.delete(e),t.isReconnecting=!1,t.nextReconnectTime=void 0,this.logger.info(`\u5DF2\u505C\u6B62\u7AEF\u70B9 ${e} \u7684\u91CD\u8FDE`))}stopAllReconnects(){this.logger.info("\u505C\u6B62\u6240\u6709\u7AEF\u70B9\u7684\u91CD\u8FDE");for(let[e]of this.reconnectTimers)this.stopReconnect(e)}getReconnectStats(){let e={};for(let[t,n]of this.connectionStates)e[t]={endpoint:t,reconnectAttempts:n.reconnectAttempts,isReconnecting:n.isReconnecting,nextReconnectTime:n.nextReconnectTime,lastReconnectAttempt:n.lastReconnectAttempt,reconnectDelay:n.reconnectDelay,errorType:n.errorType,recentReconnectHistory:n.reconnectHistory.slice(-5)};return e}validateEndpoints(e){let t=[],n=[];for(let r of e){if(!r||typeof r!="string"){n.push(r);continue}if(!r.startsWith("ws://")&&!r.startsWith("wss://")){n.push(r);continue}try{new URL(r),t.push(r)}catch{n.push(r)}}return{valid:t,invalid:n}}validateOptions(e){let t=[];if(e.healthCheckInterval!==void 0&&(typeof e.healthCheckInterval!="number"||e.healthCheckInterval<1e3)&&t.push("healthCheckInterval \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 1000 \u7684\u6570\u5B57"),e.reconnectInterval!==void 0&&(typeof e.reconnectInterval!="number"||e.reconnectInterval<100)&&t.push("reconnectInterval \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 100 \u7684\u6570\u5B57"),e.maxReconnectAttempts!==void 0&&(typeof e.maxReconnectAttempts!="number"||e.maxReconnectAttempts<0)&&t.push("maxReconnectAttempts \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 0 \u7684\u6570\u5B57"),e.connectionTimeout!==void 0&&(typeof e.connectionTimeout!="number"||e.connectionTimeout<1e3)&&t.push("connectionTimeout \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 1000 \u7684\u6570\u5B57"),e.maxReconnectDelay!==void 0&&(typeof e.maxReconnectDelay!="number"||e.maxReconnectDelay<1e3)&&t.push("maxReconnectDelay \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 1000 \u7684\u6570\u5B57"),e.reconnectBackoffMultiplier!==void 0&&(typeof e.reconnectBackoffMultiplier!="number"||e.reconnectBackoffMultiplier<1)&&t.push("reconnectBackoffMultiplier \u5FC5\u987B\u662F\u5927\u4E8E\u7B49\u4E8E 1 \u7684\u6570\u5B57"),e.loadBalanceStrategy!==void 0){let n=["round-robin","random","health-based"];n.includes(e.loadBalanceStrategy)||t.push(`loadBalanceStrategy \u5FC5\u987B\u662F\u4EE5\u4E0B\u503C\u4E4B\u4E00: ${n.join(", ")}`)}if(e.reconnectStrategy!==void 0){let n=Object.values(ze);n.includes(e.reconnectStrategy)||t.push(`reconnectStrategy \u5FC5\u987B\u662F\u4EE5\u4E0B\u503C\u4E4B\u4E00: ${n.join(", ")}`)}return{valid:t.length===0,errors:t}}async updateEndpoints(e,t=[]){if(!this.isInitialized)throw new Error("XiaozhiConnectionManager \u672A\u521D\u59CB\u5316");this.logger.info(`\u66F4\u65B0\u7AEF\u70B9\u914D\u7F6E\uFF0C\u65B0\u7AEF\u70B9\u6570\u91CF: ${e.length}`);let{valid:n,invalid:r}=this.validateEndpoints(e);if(r.length>0&&this.logger.warn(`\u53D1\u73B0\u65E0\u6548\u7AEF\u70B9: ${r.join(", ")}`),n.length===0)throw new Error("\u6CA1\u6709\u6709\u6548\u7684\u7AEF\u70B9");let i=Array.from(this.connections.keys()),s=n.filter(f=>!i.includes(f)),l=i.filter(f=>!n.includes(f)),p=i.filter(f=>n.includes(f));this.logger.info(`\u7AEF\u70B9\u53D8\u66F4 - \u6DFB\u52A0: ${s.length}, \u79FB\u9664: ${l.length}, \u4FDD\u6301: ${p.length}`);try{for(let S of l)await this.removeEndpoint(S);for(let S of s)await this.addEndpoint(S);let f={type:s.length>0&&l.length>0?"endpoints_updated":s.length>0?"endpoints_added":"endpoints_removed",data:{added:s.length>0?s:void 0,removed:l.length>0?l:void 0,updated:s.length>0&&l.length>0?n:void 0},timestamp:new Date};this.emit("configChange",f),this.logger.info("\u7AEF\u70B9\u914D\u7F6E\u66F4\u65B0\u5B8C\u6210")}catch(f){throw this.logger.error("\u7AEF\u70B9\u914D\u7F6E\u66F4\u65B0\u5931\u8D25:",f),f}}updateOptions(e){this.logger.info("\u66F4\u65B0\u8FDE\u63A5\u9009\u9879");let{valid:t,errors:n}=this.validateOptions(e);if(!t)throw new Error(`\u65E0\u6548\u7684\u8FDE\u63A5\u9009\u9879: ${n.join(", ")}`);let r={...this.options};this.options={...this.options,...e};let i={type:"options_updated",data:{oldOptions:r,newOptions:e},timestamp:new Date};this.emit("configChange",i),this.logger.info("\u8FDE\u63A5\u9009\u9879\u66F4\u65B0\u5B8C\u6210"),this.logger.debug("\u65B0\u7684\u914D\u7F6E\u9009\u9879:",this.options)}getCurrentConfig(){return{endpoints:Array.from(this.connections.keys()),options:{...this.options}}}async reloadConfig(e){this.logger.info("\u5F00\u59CB\u70ED\u91CD\u8F7D\u914D\u7F6E");try{e.options&&this.updateOptions(e.options),e.endpoints&&await this.updateEndpoints(e.endpoints,e.tools||[]),this.logger.info("\u914D\u7F6E\u70ED\u91CD\u8F7D\u5B8C\u6210")}catch(t){throw this.logger.error("\u914D\u7F6E\u70ED\u91CD\u8F7D\u5931\u8D25:",t),t}}selectBestConnection(e=[]){let t=this.getHealthyConnections();if(t.length===0)return this.logger.warn("\u6CA1\u6709\u5065\u5EB7\u7684\u8FDE\u63A5\u53EF\u7528"),null;let n=t.filter(i=>{let s=this.getEndpointByConnection(i);return s&&!e.includes(s)});if(n.length===0)return this.logger.warn("\u6CA1\u6709\u53EF\u7528\u7684\u8FDE\u63A5\uFF08\u6392\u9664\u6307\u5B9A\u7AEF\u70B9\u540E\uFF09"),null;let r;switch(this.options.loadBalanceStrategy){case"round-robin":r=this.selectRoundRobin(n);break;case"random":r=this.selectRandom(n);break;case"health-based":r=this.selectHealthBased(n);break;default:r=this.selectRoundRobin(n)}return this.lastSelectedEndpoint=this.getEndpointByConnection(r),r}selectRoundRobin(e){if(e.length===0)throw new Error("\u6CA1\u6709\u53EF\u7528\u7684\u8FDE\u63A5");let t=e[this.roundRobinIndex%e.length];return this.roundRobinIndex=(this.roundRobinIndex+1)%e.length,t}selectRandom(e){if(e.length===0)throw new Error("\u6CA1\u6709\u53EF\u7528\u7684\u8FDE\u63A5");let t=Math.floor(Math.random()*e.length);return e[t]}selectHealthBased(e){if(e.length===0)throw new Error("\u6CA1\u6709\u53EF\u7528\u7684\u8FDE\u63A5");let t=e.map(i=>{let s=this.getEndpointByConnection(i),l=s?this.connectionStates.get(s):null;return{connection:i,endpoint:s,healthScore:l?.healthScore||0,responseTime:l?.responseTime||Number.POSITIVE_INFINITY,successRate:l&&l.totalRequests>0?l.successfulRequests/l.totalRequests*100:0}});t.sort((i,s)=>i.healthScore!==s.healthScore?s.healthScore-i.healthScore:i.successRate!==s.successRate?s.successRate-i.successRate:i.responseTime-s.responseTime);let n=t.reduce((i,s)=>i+(s.healthScore+1),0),r=Math.random()*n;for(let i of t)if(r-=i.healthScore+1,r<=0)return i.connection;return t[0].connection}getEndpointByConnection(e){for(let[t,n]of this.connections)if(n===e)return t;return null}getLoadBalanceStats(){let e=this.getHealthyConnections(),t={};for(let[n,r]of this.connectionStates){let i=r.totalRequests>0?r.successfulRequests/r.totalRequests*100:0,s=r.healthScore+1;t[n]={healthScore:r.healthScore,responseTime:r.responseTime||0,successRate:Math.round(i*100)/100,weight:s}}return{strategy:this.options.loadBalanceStrategy,totalConnections:this.connections.size,healthyConnections:e.length,lastSelectedEndpoint:this.lastSelectedEndpoint,roundRobinIndex:this.roundRobinIndex,connectionWeights:t}}setLoadBalanceStrategy(e){let t=this.options.loadBalanceStrategy;this.options.loadBalanceStrategy=e,e==="round-robin"&&(this.roundRobinIndex=0),this.logger.info(`\u8D1F\u8F7D\u5747\u8861\u7B56\u7565\u5DF2\u4ECE ${t} \u5207\u6362\u5230 ${e}`);let n={type:"options_updated",data:{oldOptions:{loadBalanceStrategy:t},newOptions:{loadBalanceStrategy:e}},timestamp:new Date};this.emit("configChange",n)}async performFailover(e){this.logger.warn(`\u6267\u884C\u6545\u969C\u8F6C\u79FB\uFF0C\u5931\u8D25\u7AEF\u70B9: ${e}`);let t=this.selectBestConnection([e]);if(!t)return this.logger.error("\u6545\u969C\u8F6C\u79FB\u5931\u8D25\uFF1A\u6CA1\u6709\u53EF\u7528\u7684\u5907\u7528\u8FDE\u63A5"),null;let n=this.getEndpointByConnection(t);return this.logger.info(`\u6545\u969C\u8F6C\u79FB\u6210\u529F\uFF0C\u5207\u6362\u5230\u7AEF\u70B9: ${n}`),t}async prewarmConnections(e=[]){let t=e.length>0?e:Array.from(this.connections.keys());this.logger.info(`\u5F00\u59CB\u9884\u70ED\u8FDE\u63A5\uFF0C\u7AEF\u70B9\u6570\u91CF: ${t.length}`);let n=t.map(async r=>{if(this.performanceMetrics.prewarmedConnections.has(r)){this.logger.debug(`\u7AEF\u70B9 ${r} \u5DF2\u9884\u70ED\uFF0C\u8DF3\u8FC7`);return}try{this.connections.get(r)&&(await this.performHealthCheck(),this.performanceMetrics.prewarmedConnections.add(r),this.logger.debug(`\u7AEF\u70B9 ${r} \u9884\u70ED\u5B8C\u6210`))}catch(i){this.logger.warn(`\u7AEF\u70B9 ${r} \u9884\u70ED\u5931\u8D25:`,i)}});await Promise.all(n),this.logger.info(`\u8FDE\u63A5\u9884\u70ED\u5B8C\u6210\uFF0C\u6210\u529F\u9884\u70ED ${this.performanceMetrics.prewarmedConnections.size} \u4E2A\u7AEF\u70B9`)}updatePerformanceMetrics(){let e=process.memoryUsage().heapUsed;this.performanceMetrics.memoryUsage.current=e,e>this.performanceMetrics.memoryUsage.peak&&(this.performanceMetrics.memoryUsage.peak=e)}getPerformanceMetrics(){this.updatePerformanceMetrics();let e=this.performanceMetrics.memoryUsage.current-this.performanceMetrics.memoryUsage.initial,t=this.performanceMetrics.memoryUsage.initial>0?e/this.performanceMetrics.memoryUsage.initial*100:0;return{connectionTime:{total:this.performanceMetrics.totalConnectionTime,average:this.performanceMetrics.averageConnectionTime,count:this.performanceMetrics.connectionCount},memoryUsage:{initial:this.performanceMetrics.memoryUsage.initial,current:this.performanceMetrics.memoryUsage.current,peak:this.performanceMetrics.memoryUsage.peak,growth:e,growthPercentage:Math.round(t*100)/100},prewarmedConnections:this.performanceMetrics.prewarmedConnections.size,totalConnections:this.connections.size,healthyConnections:this.getHealthyConnections().length}}optimizeMemoryUsage(){this.logger.info("\u5F00\u59CB\u5185\u5B58\u4F18\u5316");for(let[,e]of this.connectionStates)if(e.reconnectHistory&&e.reconnectHistory.length>10&&(e.reconnectHistory=e.reconnectHistory.slice(-10)),e.totalRequests>1e4){let t=e.successfulRequests/e.totalRequests;e.totalRequests=1e3,e.successfulRequests=Math.round(t*1e3)}global.gc&&global.gc(),this.updatePerformanceMetrics(),this.logger.info("\u5185\u5B58\u4F18\u5316\u5B8C\u6210")}async cleanup(){this.logger.info("\u5F00\u59CB\u6E05\u7406 XiaozhiConnectionManager \u8D44\u6E90");try{await this.disconnect(),this.connections.clear(),this.connectionStates.clear(),this.isInitialized=!1,this.isConnecting=!1,this.roundRobinIndex=0,this.lastSelectedEndpoint=null,this.logger.info("XiaozhiConnectionManager \u8D44\u6E90\u6E05\u7406\u5B8C\u6210")}catch(e){throw this.logger.error("XiaozhiConnectionManager \u8D44\u6E90\u6E05\u7406\u5931\u8D25:",e),e}}validateInitializeParams(e,t){if(!Array.isArray(e)||e.length===0)throw new Error("\u7AEF\u70B9\u5217\u8868\u4E0D\u80FD\u4E3A\u7A7A");if(!Array.isArray(t))throw new Error("\u5DE5\u5177\u5217\u8868\u5FC5\u987B\u662F\u6570\u7EC4");for(let n of e){if(!n||typeof n!="string")throw new Error(`\u65E0\u6548\u7684\u7AEF\u70B9\u5730\u5740: ${n}`);if(!n.startsWith("ws://")&&!n.startsWith("wss://"))throw new Error(`\u7AEF\u70B9\u5730\u5740\u5FC5\u987B\u662F WebSocket URL: ${n}`)}}async createConnection(e,t){this.logger.debug(`\u521B\u5EFA\u8FDE\u63A5\u5B9E\u4F8B: ${e}`);try{let n=new D(e);this.mcpServiceManager&&n.setServiceManager(this.mcpServiceManager),this.connections.set(e,n),this.connectionStates.set(e,{endpoint:e,connected:!1,initialized:!1,reconnectAttempts:0,healthScore:100,consecutiveFailures:0,totalRequests:0,successfulRequests:0,healthCheckEnabled:!0,isReconnecting:!1,reconnectDelay:this.options.reconnectInterval,reconnectHistory:[]}),this.logger.debug(`\u8FDE\u63A5\u5B9E\u4F8B\u521B\u5EFA\u6210\u529F: ${e}`)}catch(n){throw this.logger.error(`\u521B\u5EFA\u8FDE\u63A5\u5B9E\u4F8B\u5931\u8D25 ${e}:`,n),n}}async connectSingleEndpoint(e,t){let n=this.connectionStates.get(e);if(!n)throw new Error(`\u7AEF\u70B9\u72B6\u6001\u4E0D\u5B58\u5728: ${e}`);this.logger.debug(`\u8FDE\u63A5\u7AEF\u70B9: ${e}`);try{n.connected=!1,n.initialized=!1,await t.connect(),n.connected=!0,n.initialized=!0,n.lastConnected=new Date,n.lastError=void 0,n.reconnectAttempts=0,n.healthScore=100,this.logger.info(`\u7AEF\u70B9\u8FDE\u63A5\u6210\u529F: ${e}`)}catch(r){throw n.connected=!1,n.initialized=!1,n.lastError=r instanceof Error?r.message:String(r),n.reconnectAttempts++,n.healthScore=Math.max(0,n.healthScore-20),this.logger.error(`\u7AEF\u70B9\u8FDE\u63A5\u5931\u8D25 ${e}:`,r),this.scheduleReconnect(e),r}}async disconnectSingleEndpoint(e,t){let n=this.connectionStates.get(e);if(n){this.logger.debug(`\u65AD\u5F00\u7AEF\u70B9: ${e}`);try{t.disconnect(),n.connected=!1,n.initialized=!1,this.logger.debug(`\u7AEF\u70B9\u65AD\u5F00\u6210\u529F: ${e}`)}catch(r){this.logger.error(`\u7AEF\u70B9\u65AD\u5F00\u5931\u8D25 ${e}:`,r),n.connected=!1,n.initialized=!1}}}getCurrentTools(){if(!this.mcpServiceManager)return[];try{return this.mcpServiceManager.getAllTools()}catch(e){return this.logger.error("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25:",e),[]}}syncToolsToAllConnections(){if(this.mcpServiceManager){this.logger.debug("\u540C\u6B65\u5DE5\u5177\u5230\u6240\u6709\u8FDE\u63A5");for(let[e,t]of this.connections)try{t.setServiceManager(this.mcpServiceManager),this.logger.debug(`\u5DE5\u5177\u540C\u6B65\u6210\u529F: ${e}`)}catch(n){this.logger.error(`\u5DE5\u5177\u540C\u6B65\u5931\u8D25 ${e}:`,n)}}}startHealthCheck(){this.healthCheckInterval||(this.logger.debug(`\u542F\u52A8\u5065\u5EB7\u68C0\u67E5\uFF0C\u95F4\u9694: ${this.options.healthCheckInterval}ms`),this.healthCheckInterval=setInterval(()=>{this.performHealthCheck()},this.options.healthCheckInterval))}stopHealthCheck(){this.healthCheckInterval&&(clearInterval(this.healthCheckInterval),this.healthCheckInterval=null,this.logger.debug("\u5065\u5EB7\u68C0\u67E5\u5DF2\u505C\u6B62"))}async performHealthCheck(){this.logger.debug("\u6267\u884C\u5065\u5EB7\u68C0\u67E5");let e=[];for(let[t,n]of this.connectionStates)n.healthCheckEnabled&&e.push(this.performSingleHealthCheck(t,n));await Promise.allSettled(e)}async performSingleHealthCheck(e,t){let n=Date.now();t.lastHealthCheck=new Date,t.totalRequests++;try{let r=this.connections.get(e);if(!r)throw new Error(`\u8FDE\u63A5\u5B9E\u4F8B\u4E0D\u5B58\u5728: ${e}`);await this.checkConnectionHealth(r,e);let i=Date.now()-n;this.handleHealthCheckSuccess(t,i)}catch(r){let i=Date.now()-n;this.handleHealthCheckFailure(t,r,i)}}async checkConnectionHealth(e,t){if(!e)throw new Error("\u8FDE\u63A5\u5B9E\u4F8B\u4E0D\u5B58\u5728");if(await new Promise(r=>setTimeout(r,10)),!this.connectionStates.get(t)?.connected)throw new Error("\u8FDE\u63A5\u5DF2\u65AD\u5F00")}handleHealthCheckSuccess(e,t){e.successfulRequests++,e.consecutiveFailures=0,e.responseTime=t,e.lastSuccessTime=new Date,this.updateHealthScore(e,!0,t),this.logger.debug(`\u5065\u5EB7\u68C0\u67E5\u6210\u529F: ${e.endpoint}, \u54CD\u5E94\u65F6\u95F4: ${t}ms, \u5065\u5EB7\u5EA6: ${e.healthScore}`)}handleHealthCheckFailure(e,t,n){e.consecutiveFailures++,e.responseTime=n,e.lastError=t.message,this.updateHealthScore(e,!1,n),this.logger.warn(`\u5065\u5EB7\u68C0\u67E5\u5931\u8D25: ${e.endpoint}, \u9519\u8BEF: ${t.message}, \u8FDE\u7EED\u5931\u8D25: ${e.consecutiveFailures}, \u5065\u5EB7\u5EA6: ${e.healthScore}`),e.consecutiveFailures>=3&&e.connected&&this.logger.warn(`\u7AEF\u70B9 ${e.endpoint} \u8FDE\u7EED\u5931\u8D25 ${e.consecutiveFailures} \u6B21\uFF0C\u53EF\u80FD\u9700\u8981\u91CD\u8FDE`)}updateHealthScore(e,t,n){let r=e.healthScore;if(t){let i=5;n<100?i=10:n<500?i=7:n<1e3?i=5:i=2,e.healthScore=Math.min(100,r+i)}else{let i=15;e.consecutiveFailures>=5?i=30:e.consecutiveFailures>=3&&(i=20),e.healthScore=Math.max(0,r-i)}if(e.totalRequests>0){let i=e.successfulRequests/e.totalRequests;i<.5?e.healthScore=Math.max(0,e.healthScore-10):i>.9&&(e.healthScore=Math.min(100,e.healthScore+5))}}classifyConnectionError(e){let t=e.message.toLowerCase();return t.includes("timeout")||t.includes("timed out")?"timeout_error":t.includes("network")||t.includes("connection refused")||t.includes("econnrefused")||t.includes("enotfound")?"network_error":t.includes("auth")||t.includes("unauthorized")||t.includes("forbidden")||t.includes("401")||t.includes("403")?"authentication_error":t.includes("server")||t.includes("500")||t.includes("502")||t.includes("503")||t.includes("504")?"server_error":"unknown_error"}calculateReconnectDelay(e){let t=this.options.reconnectInterval,n=this.options.maxReconnectDelay,r=this.options.reconnectBackoffMultiplier,i=e.reconnectAttempts,s;switch(this.options.reconnectStrategy){case"fixed_interval":s=t;break;case"linear_backoff":s=t*(i+1);break;case"exponential_backoff":s=t*r**i;break;case"adaptive":s=this.calculateAdaptiveDelay(e,t,r,i);break;default:s=t*r**i}if(s=Math.min(s,n),this.options.jitterEnabled){let l=s*.1*Math.random();s+=l}return Math.round(s)}calculateAdaptiveDelay(e,t,n,r){let i=t;switch(e.errorType){case"network_error":i=t*n**r;break;case"authentication_error":i=t*n**r*2;break;case"server_error":i=t*(1+r);break;case"timeout_error":i=t*(1+r*.5);break;default:i=t*n**r}if(e.reconnectHistory.length>0){let s=e.reconnectHistory.slice(-5),l=s.filter(p=>p.success).length/s.length;l<.2?i*=1.5:l>.8&&(i*=.8)}return i}shouldReconnect(e){return e.reconnectAttempts>=this.options.maxReconnectAttempts?(this.logger.warn(`\u7AEF\u70B9 ${e.endpoint} \u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8FDE\u6B21\u6570 ${this.options.maxReconnectAttempts}`),!1):e.errorType==="authentication_error"&&e.reconnectAttempts>=3?(this.logger.warn(`\u7AEF\u70B9 ${e.endpoint} \u8BA4\u8BC1\u9519\u8BEF\uFF0C\u505C\u6B62\u91CD\u8FDE`),!1):e.consecutiveFailures>=10?(this.logger.warn(`\u7AEF\u70B9 ${e.endpoint} \u8FDE\u7EED\u5931\u8D25\u6B21\u6570\u8FC7\u591A\uFF0C\u505C\u6B62\u91CD\u8FDE`),!1):!0}scheduleReconnect(e){let t=this.connectionStates.get(e);if(!t)return;if(t.lastError&&(t.errorType=this.classifyConnectionError(new Error(t.lastError))),!this.shouldReconnect(t)){t.isReconnecting=!1;return}let n=this.reconnectTimers.get(e);n&&clearTimeout(n);let r=this.calculateReconnectDelay(t);t.reconnectDelay=r,t.isReconnecting=!0,t.nextReconnectTime=new Date(Date.now()+r),this.logger.info(`\u5B89\u6392\u91CD\u8FDE ${e}\uFF0C\u5EF6\u8FDF: ${r}ms\uFF0C\u5C1D\u8BD5\u6B21\u6570: ${t.reconnectAttempts+1}\uFF0C\u9519\u8BEF\u7C7B\u578B: ${t.errorType}`);let i=setTimeout(async()=>{this.reconnectTimers.delete(e),await this.performReconnect(e)},r);this.reconnectTimers.set(e,i)}async performReconnect(e){let t=this.connectionStates.get(e),n=this.connections.get(e);if(!(!t||!n)){t.lastReconnectAttempt=new Date,t.isReconnecting=!0,this.logger.info(`\u5F00\u59CB\u91CD\u8FDE ${e}\uFF0C\u7B2C ${t.reconnectAttempts+1} \u6B21\u5C1D\u8BD5`);try{await this.connectSingleEndpoint(e,n),t.isReconnecting=!1,t.reconnectHistory.push({timestamp:new Date,success:!0,delay:t.reconnectDelay}),this.logger.info(`\u91CD\u8FDE\u6210\u529F ${e}`)}catch(r){t.isReconnecting=!1,t.reconnectHistory.push({timestamp:new Date,success:!1,error:r instanceof Error?r.message:String(r),delay:t.reconnectDelay}),this.logger.error(`\u91CD\u8FDE\u5931\u8D25 ${e}:`,r),this.scheduleReconnect(e)}t.reconnectHistory.length>20&&(t.reconnectHistory=t.reconnectHistory.slice(-20))}}clearAllReconnectTimers(){for(let[,e]of this.reconnectTimers)clearTimeout(e);this.reconnectTimers.clear()}};var O=null,T=null,P="not_initialized",Z=null,F=null;async function Xt(o){return console.log("\u{1F680} \u6B63\u5728\u521D\u59CB\u5316 XiaozhiConnectionManager \u5355\u4F8B..."),new ie(o)}c(Xt,"createInstance");async function ke(o){if(O&&P==="initialized")return O;if(T&&P==="initializing")return T;P==="failed"&&Ce(),P="initializing",T=Xt(o);try{return O=await T,P="initialized",F=`xiaozhi-connection-manager-${Date.now()}-${Math.random().toString(36).substring(2,11)}`,Z=null,console.log(`\u2705 XiaozhiConnectionManager \u5355\u4F8B\u521D\u59CB\u5316\u6210\u529F\uFF0C\u5B9E\u4F8BID: ${F}`),O}catch(e){throw P="failed",Z=e,T=null,console.error("\u274C XiaozhiConnectionManager \u5355\u4F8B\u521D\u59CB\u5316\u5931\u8D25:",e.message),e}}c(ke,"getInstance");async function je(){if(P==="cleanup"){console.log("\u26A0\uFE0F XiaozhiConnectionManager \u5355\u4F8B\u5DF2\u5728\u6E05\u7406\u4E2D\uFF0C\u8DF3\u8FC7\u91CD\u590D\u6E05\u7406");return}console.log("\u{1F9F9} \u6B63\u5728\u6E05\u7406 XiaozhiConnectionManager \u5355\u4F8B\u8D44\u6E90..."),P="cleanup";try{if(T){try{await(await T).cleanup()}catch(o){console.error("\u6E05\u7406\u521D\u59CB\u5316\u4E2D\u7684\u5B9E\u4F8B\u5931\u8D25:",o.message)}T=null}O&&(await O.cleanup(),O=null),P="not_initialized",Z=null,F=null,console.log("\u2705 XiaozhiConnectionManager \u5355\u4F8B\u8D44\u6E90\u6E05\u7406\u5B8C\u6210")}catch(o){throw console.error("\u274C XiaozhiConnectionManager \u5355\u4F8B\u6E05\u7406\u5931\u8D25:",o.message),Ce(),o}}c(je,"cleanup");function Ce(){console.log("\u{1F504} \u91CD\u7F6E XiaozhiConnectionManager \u5355\u4F8B\u72B6\u6001..."),T&&(T=null),O=null,P="not_initialized",Z=null,F=null,console.log("\u2705 XiaozhiConnectionManager \u5355\u4F8B\u72B6\u6001\u5DF2\u91CD\u7F6E")}c(Ce,"reset");function Bt(){return P==="initialized"&&O!==null}c(Bt,"isInitialized");function Gt(){return{state:P,initializationTime:F?new Date:void 0,lastError:Z||void 0,instanceId:F||void 0}}c(Gt,"getStatus");async function Jt(o){return console.log("\u{1F504} \u5F3A\u5236\u91CD\u65B0\u521D\u59CB\u5316 XiaozhiConnectionManager \u5355\u4F8B..."),await je(),ke(o)}c(Jt,"forceReinitialize");function Zt(){return O}c(Zt,"getCurrentInstance");async function qt(){if(P==="initialized")return!0;if(P==="initializing"&&T)try{return await T,!0}catch{return!1}return!1}c(qt,"waitForInitialization");var L={getInstance:ke,cleanup:je,reset:Ce,isInitialized:Bt,getStatus:Gt,forceReinitialize:Jt,getCurrentInstance:Zt,waitForInitialization:qt};process.on("exit",()=>{L.isInitialized()&&(console.log("\u{1F504} \u8FDB\u7A0B\u9000\u51FA\uFF0C\u6B63\u5728\u6E05\u7406 XiaozhiConnectionManager \u5355\u4F8B..."),L.reset())});process.on("uncaughtException",async o=>{console.error("\u{1F4A5} \u672A\u6355\u83B7\u7684\u5F02\u5E38\uFF0C\u6E05\u7406 XiaozhiConnectionManager \u5355\u4F8B:",o);try{await L.cleanup()}catch(e){console.error("\u6E05\u7406\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",e)}});process.on("unhandledRejection",async o=>{console.error("\u{1F4A5} \u672A\u5904\u7406\u7684Promise\u62D2\u7EDD\uFF0C\u6E05\u7406 XiaozhiConnectionManager \u5355\u4F8B:",o);try{await L.cleanup()}catch(e){console.error("\u6E05\u7406\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",e)}});var q=class{static{c(this,"WebServer")}app;httpServer=null;wss=null;logger;port;clientInfo={status:"disconnected",mcpEndpoint:"",activeMCPServers:[]};heartbeatTimeout;HEARTBEAT_TIMEOUT=35e3;proxyMCPServer;xiaozhiConnectionManager;mcpServiceManager;constructor(e){this.port=e??g.getWebUIPort()??9999,this.logger=new C,this.app=new en,this.setupMiddleware(),this.setupRoutes()}async initializeConnections(){try{this.logger.info("\u5F00\u59CB\u521D\u59CB\u5316\u8FDE\u63A5...");let e=await this.loadConfiguration();this.mcpServiceManager=await j.getInstance(),await this.loadMCPServicesFromConfig(e.mcpServers);let t=this.mcpServiceManager.getAllTools();this.logger.info(`\u5DF2\u52A0\u8F7D ${t.length} \u4E2A\u5DE5\u5177`),await this.initializeXiaozhiConnection(e.mcpEndpoint,t),this.logger.info("\u6240\u6709\u8FDE\u63A5\u521D\u59CB\u5316\u5B8C\u6210")}catch(e){throw this.logger.error("\u8FDE\u63A5\u521D\u59CB\u5316\u5931\u8D25:",e),e}}async loadConfiguration(){if(!g.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C 'xiaozhi init' \u521D\u59CB\u5316\u914D\u7F6E");let e=g.getConfig();return{mcpEndpoint:e.mcpEndpoint,mcpServers:e.mcpServers,webUIPort:e.webUI?.port??9999}}async loadMCPServicesFromConfig(e){if(!this.mcpServiceManager)throw new Error("MCPServiceManager \u672A\u521D\u59CB\u5316");for(let[t,n]of Object.entries(e)){this.logger.info(`\u6DFB\u52A0 MCP \u670D\u52A1\u914D\u7F6E: ${t}`);let r=$e(t,n);this.mcpServiceManager.addServiceConfig(t,r)}await this.mcpServiceManager.startAllServices(),this.logger.info("\u6240\u6709 MCP \u670D\u52A1\u5DF2\u542F\u52A8")}async initializeXiaozhiConnection(e,t){let r=(Array.isArray(e)?e:[e]).filter(i=>i&&!i.includes("<\u8BF7\u586B\u5199"));if(r.length===0){this.logger.warn("\u672A\u914D\u7F6E\u6709\u6548\u7684\u5C0F\u667A\u63A5\u5165\u70B9\uFF0C\u8DF3\u8FC7\u8FDE\u63A5");return}this.logger.info(`\u521D\u59CB\u5316\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u7BA1\u7406\u5668\uFF0C\u7AEF\u70B9\u6570\u91CF: ${r.length}`),this.logger.debug("\u6709\u6548\u7AEF\u70B9\u5217\u8868:",r);try{this.xiaozhiConnectionManager=await L.getInstance({healthCheckInterval:3e4,reconnectInterval:5e3,maxReconnectAttempts:10,loadBalanceStrategy:"round-robin",connectionTimeout:1e4}),this.mcpServiceManager&&this.xiaozhiConnectionManager.setServiceManager(this.mcpServiceManager),await this.xiaozhiConnectionManager.initialize(r,t),await this.xiaozhiConnectionManager.connect(),this.xiaozhiConnectionManager.on("configChange",i=>{this.logger.info(`\u5C0F\u667A\u8FDE\u63A5\u914D\u7F6E\u53D8\u66F4: ${i.type}`,i.data)}),this.logger.info(`\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u7BA1\u7406\u5668\u521D\u59CB\u5316\u5B8C\u6210\uFF0C\u7BA1\u7406 ${r.length} \u4E2A\u7AEF\u70B9`)}catch(i){this.logger.error("\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u7BA1\u7406\u5668\u521D\u59CB\u5316\u5931\u8D25:",i),this.logger.warn("\u56DE\u9000\u5230\u5355\u8FDE\u63A5\u6A21\u5F0F");let s=r[0];this.logger.info(`\u521D\u59CB\u5316\u5355\u4E2A\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5: ${s}`),this.proxyMCPServer=new D(s),this.mcpServiceManager&&this.proxyMCPServer.setServiceManager(this.mcpServiceManager),await this.connectWithRetry(()=>this.proxyMCPServer.connect(),"\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5"),this.logger.info("\u5C0F\u667A\u63A5\u5165\u70B9\u8FDE\u63A5\u6210\u529F\uFF08\u5355\u8FDE\u63A5\u6A21\u5F0F\uFF09")}}getBestXiaozhiConnection(){return this.xiaozhiConnectionManager?this.xiaozhiConnectionManager.selectBestConnection():this.proxyMCPServer||null}getXiaozhiConnectionStatus(){return this.xiaozhiConnectionManager?{type:"multi-endpoint",manager:{healthyConnections:this.xiaozhiConnectionManager.getHealthyConnections().length,totalConnections:this.xiaozhiConnectionManager.getConnectionStatus().length,loadBalanceStats:this.xiaozhiConnectionManager.getLoadBalanceStats(),healthCheckStats:this.xiaozhiConnectionManager.getHealthCheckStats(),reconnectStats:this.xiaozhiConnectionManager.getReconnectStats()},connections:this.xiaozhiConnectionManager.getConnectionStatus()}:this.proxyMCPServer?{type:"single-endpoint",connected:!0,endpoint:"unknown"}:{type:"none",connected:!1}}async connectWithRetry(e,t,n=5,r=1e3,i=3e4,s=2){let l=null;for(let p=1;p<=n;p++)try{return this.logger.info(`${t} - \u5C1D\u8BD5\u8FDE\u63A5 (${p}/${n})`),await e()}catch(f){if(l=f,this.logger.warn(`${t} - \u8FDE\u63A5\u5931\u8D25:`,f),p<n){let S=Math.min(r*s**(p-1),i);this.logger.info(`${t} - ${S}ms \u540E\u91CD\u8BD5...`),await this.sleep(S)}}throw new Error(`${t} - \u8FDE\u63A5\u5931\u8D25\uFF0C\u5DF2\u8FBE\u5230\u6700\u5927\u91CD\u8BD5\u6B21\u6570: ${l?.message}`)}sleep(e){return new Promise(t=>setTimeout(t,e))}setupMiddleware(){this.app?.use("*",tn({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=g.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=>{let t=this.proxyMCPServer?.getStatus();return e.json({...this.clientInfo,mcpConnection:t})}),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 n=Vt(Yt(import.meta.url)),i=[H(n,"..","web","dist"),H(n,"..","web"),H(process.cwd(),"web","dist"),H(process.cwd(),"web")].find(A=>ve(A));if(!i)return e.html(`
16
13
  <!DOCTYPE html>
17
14
  <html>
18
15
  <head>
@@ -32,13 +29,11 @@ data: ${JSON.stringify(t)}
32
29
  </div>
33
30
  </body>
34
31
  </html>
35
- `);let c=t;if(c==="/"&&(c="/index.html"),c.includes(".."))return e.text("Forbidden",403);let a=E(s,c);if(!K(a)){let S=E(s,"index.html");if(K(S)){let R=await ye(S);return e.html(R.toString())}return e.text("Not Found",404)}let u=await ye(a),h=a.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=l.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=l.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=l.getConfig();e.send(JSON.stringify({type:"config",data:t})),e.send(JSON.stringify({type:"status",data:this.clientInfo})),setTimeout(()=>{let o=l.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!==l.getMcpEndpoint()&&l.updateMcpEndpoint(e.mcpEndpoint);let t=l.getMcpServers();for(let[o,n]of Object.entries(e.mcpServers))JSON.stringify(t[o])!==JSON.stringify(n)&&l.updateMcpServer(o,n);for(let o of Object.keys(t))o in e.mcpServers||(l.removeMcpServer(o),l.removeServerToolsConfig(o));if(e.connection&&l.updateConnectionConfig(e.connection),e.modelscope&&l.updateModelScopeConfig(e.modelscope),e.webUI&&l.updateWebUIConfig(e.webUI),e.mcpServerConfig)for(let[o,n]of Object.entries(e.mcpServerConfig))for(let[s,c]of Object.entries(n.tools))l.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=T();if(!e.running){this.logger.warn("MCP \u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u5C1D\u8BD5\u542F\u52A8\u670D\u52A1"),he("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"),he("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=Be({fetch:this.app.fetch,port:this.port,hostname:"0.0.0.0",createServer:Ue});this.httpServer=o,this.wss=new qe({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=g(()=>{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()})}};var v=new rt,st="xiaozhi-mcp-service";function Me(){try{let r=j(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"}}g(Me,"getVersion");var ne=g(()=>{let r=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return f.join(r,`.${st}.pid`)},"getPidFile");function T(){try{let r=ne();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),a=it(Date.now()-c);return{running:!0,pid:s,uptime:a,mode:n||"foreground"}}catch{return b.unlinkSync(r),{running:!1}}}catch{return{running:!1}}}g(T,"getServiceStatus");function it(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`}g(it,"formatUptime");function oe(r,e){let t=`${r}|${Date.now()}|${e}`;b.writeFileSync(ne(),t)}g(oe,"savePidInfo");function N(){try{let r=ne();b.existsSync(r)&&b.unlinkSync(r)}catch{}}g(N,"cleanupPidFile");function ct(){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 e=l.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}}g(ct,"checkEnvironment");function at(){let r=f.dirname(j(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}}g(at,"getServiceCommand");async function Pe(){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\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)}`))}}g(Pe,"startWebUIInBackground");async function xe(r=!1,e=!1){let t=I("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let o=T();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...",!ct()){t.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}let{command:n,args:s,cwd:c}=at();if(t.text=`\u542F\u52A8\u670D\u52A1 (${r?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,r){let a=te(n,s,{cwd:c,detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true"}});oe(a.pid,"daemon");let u=process.cwd();w.initLogFile(u),w.enableFileLogging(!0);let h=f.join(u,"xiaozhi.log"),y=b.createWriteStream(h,{flags:"a"});a.stdout?.pipe(y),a.stderr?.pipe(y),a.on("exit",(C,S)=>{C!==0&&C!==null&&w.error(`\u540E\u53F0\u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${C}, \u4FE1\u53F7: ${S})`),N()}),a.on("error",C=>{w.error(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u9519\u8BEF: ${C.message}`),N(),t.fail(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u5931\u8D25: ${C.message}`)}),a.unref(),t.succeed(`\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${a.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 Pe()}else{t.succeed("\u670D\u52A1\u542F\u52A8\u4E2D...");let a=te(n,s,{cwd:c,stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.FORCE_CONFIG_DIR||process.cwd()}});oe(a.pid,"foreground"),a.on("exit",(u,h)=>{N(),console.log(u!==0?i.red(`
36
- \u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${u}, \u4FE1\u53F7: ${h})`):i.green(`
37
- \u670D\u52A1\u5DF2\u505C\u6B62`))}),e&&setTimeout(()=>{Pe()},1e3),process.on("SIGINT",async()=>{if(console.log(i.yellow(`
38
- \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(o){t.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(xe,"startService");async function $e(){let r=I("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=T();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{}N(),r.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(t){N(),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)}`)}}g($e,"stopService");async function lt(){let r=I("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=T();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)}`)}}g(lt,"checkStatus");async function gt(){let r=I("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=T();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(`
39
- \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(`
40
- \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(gt,"attachService");async function pt(r=!1,e=!1){console.log(i.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await $e(),await new Promise(t=>setTimeout(t,1e3)),await xe(r,e)}g(pt,"restartService");async function ft(r,e=!1){let t=I("\u542F\u52A8 MCP Server \u6A21\u5F0F...").start();try{if(!l.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(()=>(we(),ve));if(e){let n=j(import.meta.url),s=f.dirname(n),c=te("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"}});oe(c.pid,"daemon");let a=f.join(process.cwd(),"xiaozhi-mcp-server.log"),u=b.createWriteStream(a,{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: ${a}`))}else{let n=new o(r),s=g(async()=>{console.log(i.yellow(`
41
- \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)}`)}}g(ft,"startMCPServerMode");function dt(){let r=Me();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(dt,"showDetailedInfo");async function ut(r="json"){let e=I("\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 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)}`)}}g(ut,"initConfig");function mt(){let r=f.dirname(j(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()}):[]}g(mt,"getAvailableTemplates");function Ie(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 a=1;a<=o;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(t,o);return s===0?1:(s-n[t][o])/s}g(Ie,"calculateSimilarity");function ht(r,e){if(e.length===0)return null;let t=e[0],o=Ie(r.toLowerCase(),t.toLowerCase());for(let n of e.slice(1)){let s=Ie(r.toLowerCase(),n.toLowerCase());s>o&&(o=s,t=n)}return o>.5?t:null}g(ht,"findSimilarTemplate");async function yt(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=g(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)})})}g(yt,"askUserConfirmation");function bt(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")}g(bt,"createBasicConfig");async function Ct(r,e){let t=I("\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=mt();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=ht(e.template,n);if(y)if(console.log(i.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${y}" \u5417\uFF1F`)),await yt(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(j(import.meta.url)),a=[f.join(s,"..","templates"),f.join(s,"templates"),f.join(s,"..","..","templates")].find(y=>b.existsSync(y)),u=f.join(a,e.template);t.text=`\u4ECE\u6A21\u677F "${e.template}" \u521B\u5EFA\u9879\u76EE "${r}"...`,Ee(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}),bt(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)}`)}}g(Ct,"createProject");function Ee(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()?Ee(s,c,t):b.copyFileSync(s,c)}}g(Ee,"copyDirectory");async function St(){let r=I("\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 t=l.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(`
42
- \u5F3A\u5236\u9000\u51FA...`)),process.exit(1)),s=!0,console.log(i.yellow(`
43
- \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(St,"startUIService");async function vt(r,e){let t=I("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!l.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":l.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}l.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}l.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}l.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=l.getConfig();switch(r){case"mcpEndpoint":{t.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":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=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":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${l.getHeartbeatInterval()}ms`));break;case"heartbeatTimeout":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${l.getHeartbeatTimeout()}ms`));break;case"reconnectInterval":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(i.green(`\u91CD\u8FDE\u95F4\u9694: ${l.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)}`)}}g(vt,"configCommand");function wt(){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(wt,"showHelp");v.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(Me(),"-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 Ct(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 ut(e)});v.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(r,e)=>{await vt(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=j(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 ft(e,r.daemon)}else await xe(r.daemon,r.ui)});v.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await $e()});v.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await lt()});v.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await gt()});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 pt(r.daemon,r.ui)});var re=v.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");re.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)});re.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async r=>{await ue(r)});re.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 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=I("\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((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)}`)}});J.command("add <url>").description("\u6DFB\u52A0\u65B0\u7684 MCP \u7AEF\u70B9").action(async r=>{let e=I("\u6DFB\u52A0\u7AEF\u70B9...").start();try{l.addMcpEndpoint(r),e.succeed(`\u6210\u529F\u6DFB\u52A0\u7AEF\u70B9: ${r}`);let t=l.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)}`)}});J.command("remove <url>").description("\u79FB\u9664\u6307\u5B9A\u7684 MCP \u7AEF\u70B9").action(async r=>{let e=I("\u79FB\u9664\u7AEF\u70B9...").start();try{l.removeMcpEndpoint(r),e.succeed(`\u6210\u529F\u79FB\u9664\u7AEF\u70B9: ${r}`);let t=l.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)}`)}});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=I("\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[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 St()});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&&(dt(),process.exit(0))});ae();process.argv.length<=2&&(wt(),process.exit(0));v.parse(process.argv);export{Ie as calculateSimilarity,ct as checkEnvironment,it as formatUptime,T as getServiceStatus,Me as getVersion};
32
+ `);let s=t;if(s==="/"&&(s="/index.html"),s.includes(".."))return e.text("Forbidden",403);let l=H(i,s);if(!ve(l)){let A=H(i,"index.html");if(ve(A)){let ce=await Le(A);return e.html(ce.toString())}return e.text("Not Found",404)}let p=await Le(l),f=l.split(".").pop()?.toLowerCase(),I={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"}[f||""]||"application/octet-stream";return I.startsWith("text/")||I.includes("javascript")||I.includes("json")?e.text(p.toString(),200,{"Content-Type":I}):e.body(p,200,{"Content-Type":I})}catch(n){return this.logger.error("Serve static file error:",n),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 n=JSON.parse(t.toString());await this.handleWebSocketMessage(e,n)}catch(n){this.logger.error("WebSocket message error:",n),e.send(JSON.stringify({type:"error",error:n instanceof Error?n.message:String(n)}))}}),e.on("close",()=>{this.logger.debug("WebSocket client disconnected")}),this.sendInitialData(e)})}async handleWebSocketMessage(e,t){switch(t.type){case"getConfig":{let n=g.getConfig();this.logger.debug("getConfig ws getConfig",n),e.send(JSON.stringify({type:"config",data:n}));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 n=g.getConfig();e.send(JSON.stringify({type:"configUpdate",data:n}));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(n){this.logger.error(`\u624B\u52A8\u91CD\u542F\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`),this.broadcastRestartStatus("failed",n instanceof Error?n.message:"\u672A\u77E5\u9519\u8BEF")}},500);break}}async sendInitialData(e){let t=g.getConfig();e.send(JSON.stringify({type:"config",data:t})),e.send(JSON.stringify({type:"status",data:this.clientInfo})),setTimeout(()=>{let n=g.getConfig();e.send(JSON.stringify({type:"configUpdate",data:n}))},2e3)}broadcastConfigUpdate(e){if(!this.wss)return;let t=JSON.stringify({type:"configUpdate",data:e});for(let n of this.wss.clients)n.readyState===1&&n.send(t)}broadcastRestartStatus(e,t){if(!this.wss)return;let n=JSON.stringify({type:"restartStatus",data:{status:e,error:t,timestamp:Date.now()}});for(let r of this.wss.clients)r.readyState===1&&r.send(n)}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!==g.getMcpEndpoint()&&g.updateMcpEndpoint(e.mcpEndpoint);let t=g.getMcpServers();for(let[n,r]of Object.entries(e.mcpServers))JSON.stringify(t[n])!==JSON.stringify(r)&&g.updateMcpServer(n,r);for(let n of Object.keys(t))n in e.mcpServers||(g.removeMcpServer(n),g.removeServerToolsConfig(n));if(e.connection&&g.updateConnectionConfig(e.connection),e.modelscope&&g.updateModelScopeConfig(e.modelscope),e.webUI&&g.updateWebUIConfig(e.webUI),e.mcpServerConfig)for(let[n,r]of Object.entries(e.mcpServerConfig))for(let[i,s]of Object.entries(r.tools))g.setToolEnabled(n,i,s.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=_();if(!e.running){this.logger.warn("MCP \u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u5C1D\u8BD5\u542F\u52A8\u670D\u52A1"),Fe("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",n=["restart"];t&&n.push("--daemon"),Fe("xiaozhi",n,{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()}async start(){let e=Qt({fetch:this.app.fetch,port:this.port,hostname:"0.0.0.0",createServer:Kt});this.httpServer=e,this.wss=new nn({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}`);try{await this.initializeConnections(),this.logger.info("\u6240\u6709\u8FDE\u63A5\u521D\u59CB\u5316\u5B8C\u6210")}catch(t){this.logger.error("\u8FDE\u63A5\u521D\u59CB\u5316\u5931\u8D25\uFF0C\u4F46 Web \u670D\u52A1\u5668\u7EE7\u7EED\u8FD0\u884C:",t)}}stop(){return new Promise(e=>{let t=!1,n=c(()=>{t||(t=!0,e())},"doResolve");if(this.proxyMCPServer?.disconnect(),this.heartbeatTimeout&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=void 0),this.wss){for(let r of this.wss.clients)r.terminate();this.wss.close(()=>{this.httpServer?this.httpServer.close(()=>{this.logger.info("Web server stopped"),n()}):(this.logger.info("Web server stopped"),n()),setTimeout(()=>{this.logger.info("Web server force stopped"),n()},2e3)})}else this.logger.info("Web server stopped"),n()})}};z();x();z();import h from"chalk";import He from"cli-table3";import ye from"ora";function _e(o){let e=0;for(let t of o)/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(t)?e+=2:e+=1;return e}c(_e,"getDisplayWidth");function Ue(o,e){if(_e(o)<=e)return o;if(e<=3)return"";let t="",n=0,r=!1;for(let i of o){let s=/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(i)?2:1;if(n+s>e-3){if(!r)return"";t+="...";break}t+=i,n+=s,r=!0}return t}c(Ue,"truncateToWidth");async function We(o={}){let e=ye("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868...").start();try{let t=g.getMcpServers(),n=Object.keys(t);if(n.length===0){e.warn("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1"),console.log(h.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi config' \u547D\u4EE4\u914D\u7F6E MCP \u670D\u52A1"));return}if(e.succeed(`\u627E\u5230 ${n.length} \u4E2A MCP \u670D\u52A1`),o.tools){console.log(),console.log(h.bold("MCP \u670D\u52A1\u5DE5\u5177\u5217\u8868:")),console.log();let r=8,i=[];for(let l of n){let p=g.getServerToolsConfig(l),f=Object.keys(p);i.push(...f)}for(let l of i){let p=_e(l);p>r&&(r=p)}r=Math.max(10,Math.min(r+2,30));let s=new He({head:[h.bold("MCP"),h.bold("\u5DE5\u5177\u540D\u79F0"),h.bold("\u72B6\u6001"),h.bold("\u63CF\u8FF0")],colWidths:[15,r,8,40],wordWrap:!0,style:{head:[],border:[]}});for(let l of n){let p=g.getServerToolsConfig(l),f=Object.keys(p);if(f.length===0)s.push([h.gray(l),h.gray("-"),h.gray("-"),h.gray("\u6682\u672A\u8BC6\u522B\u5230\u76F8\u5173\u5DE5\u5177")]);else{s.length>0&&s.push([{colSpan:4,content:""}]);for(let S of f){let I=p[S],A=I.enable?h.green("\u542F\u7528"):h.red("\u7981\u7528"),ce=Ue(I.description||"",32);s.push([l,S,A,ce])}}}console.log(s.toString())}else{console.log(),console.log(h.bold("MCP \u670D\u52A1\u5217\u8868:")),console.log();for(let r of n){let i=t[r],s=g.getServerToolsConfig(r),l=Object.keys(s).length,p=Object.values(s).filter(f=>f.enable!==!1).length;console.log(`${h.cyan("\u2022")} ${h.bold(r)}`),"url"in i?("type"in i&&i.type==="sse"?console.log(` \u7C7B\u578B: ${h.gray("SSE")}`):console.log(` \u7C7B\u578B: ${h.gray("Streamable HTTP")}`),console.log(` URL: ${h.gray(i.url)}`)):console.log(` \u547D\u4EE4: ${h.gray(i.command)} ${h.gray(i.args.join(" "))}`),l>0?console.log(` \u5DE5\u5177: ${h.green(p)} \u542F\u7528 / ${h.yellow(l)} \u603B\u8BA1`):console.log(` \u5DE5\u5177: ${h.gray("\u672A\u626B\u63CF (\u8BF7\u5148\u542F\u52A8\u670D\u52A1)")}`),console.log()}}console.log(h.gray("\u{1F4A1} \u63D0\u793A:")),console.log(h.gray(" - \u4F7F\u7528 'xiaozhi mcp list --tools' \u67E5\u770B\u6240\u6709\u5DE5\u5177")),console.log(h.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> list' \u67E5\u770B\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177")),console.log(h.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(h.red(`\u9519\u8BEF: ${t instanceof Error?t.message:String(t)}`)),process.exit(1)}}c(We,"listMcpServers");async function Xe(o){let e=ye(`\u83B7\u53D6 ${o} \u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868...`).start();try{if(!g.getMcpServers()[o]){e.fail(`\u670D\u52A1 '${o}' \u4E0D\u5B58\u5728`),console.log(h.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let n=g.getServerToolsConfig(o),r=Object.keys(n);if(r.length===0){e.warn(`\u670D\u52A1 '${o}' \u6682\u65E0\u5DE5\u5177\u4FE1\u606F`),console.log(h.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u542F\u52A8\u670D\u52A1\u4EE5\u626B\u63CF\u5DE5\u5177\u5217\u8868"));return}e.succeed(`\u670D\u52A1 '${o}' \u5171\u6709 ${r.length} \u4E2A\u5DE5\u5177`),console.log(),console.log(h.bold(`${o} \u670D\u52A1\u5DE5\u5177\u5217\u8868:`)),console.log();let i=new He({head:[h.bold("\u5DE5\u5177\u540D\u79F0"),h.bold("\u72B6\u6001"),h.bold("\u63CF\u8FF0")],colWidths:[30,8,50],wordWrap:!0,style:{head:[],border:[]}});for(let s of r){let l=n[s],p=l.enable?h.green("\u542F\u7528"):h.red("\u7981\u7528"),f=Ue(l.description||"",40);i.push([s,p,f])}console.log(i.toString()),console.log(),console.log(h.gray("\u{1F4A1} \u63D0\u793A:")),console.log(h.gray(` - \u4F7F\u7528 'xiaozhi mcp ${o} <\u5DE5\u5177\u540D> enable' \u542F\u7528\u5DE5\u5177`)),console.log(h.gray(` - \u4F7F\u7528 'xiaozhi mcp ${o} <\u5DE5\u5177\u540D> disable' \u7981\u7528\u5DE5\u5177`))}catch(t){e.fail("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25"),console.error(h.red(`\u9519\u8BEF: ${t instanceof Error?t.message:String(t)}`)),process.exit(1)}}c(Xe,"listServerTools");async function Be(o,e,t){let n=t?"\u542F\u7528":"\u7981\u7528",r=ye(`${n}\u5DE5\u5177 ${o}/${e}...`).start();try{if(!g.getMcpServers()[o]){r.fail(`\u670D\u52A1 '${o}' \u4E0D\u5B58\u5728`),console.log(h.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let s=g.getServerToolsConfig(o);if(!s[e]){r.fail(`\u5DE5\u5177 '${e}' \u5728\u670D\u52A1 '${o}' \u4E2D\u4E0D\u5B58\u5728`),console.log(h.yellow(`\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp ${o} list' \u67E5\u770B\u8BE5\u670D\u52A1\u7684\u6240\u6709\u5DE5\u5177`));return}g.setToolEnabled(o,e,t,s[e].description),r.succeed(`\u6210\u529F${n}\u5DE5\u5177 ${h.cyan(o)}/${h.cyan(e)}`),console.log(),console.log(h.gray("\u{1F4A1} \u63D0\u793A: \u5DE5\u5177\u72B6\u6001\u66F4\u6539\u5C06\u5728\u4E0B\u6B21\u542F\u52A8\u670D\u52A1\u65F6\u751F\u6548"))}catch(i){r.fail(`${n}\u5DE5\u5177\u5931\u8D25`),console.error(h.red(`\u9519\u8BEF: ${i instanceof Error?i.message:String(i)}`)),process.exit(1)}}c(Be,"setToolEnabled");var w=new hn,pn="xiaozhi-mcp-service";function Ke(){try{let o=U(import.meta.url),e=m.dirname(o),t=[m.join(e,"..","package.json"),m.join(e,"..","package.json"),m.join(e,"..","..","package.json"),m.join(e,"package.json")];for(let n of t)if(d.existsSync(n)){let r=JSON.parse(d.readFileSync(n,"utf8"));if(r.version)return r.version}return"unknown"}catch(o){return console.warn("\u65E0\u6CD5\u4ECE package.json \u8BFB\u53D6\u7248\u672C\u4FE1\u606F:",o),"unknown"}}c(Ke,"getVersion");var be=c(()=>{let o=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return m.join(o,`.${pn}.pid`)},"getPidFile");function _(){try{let o=be();if(!d.existsSync(o))return{running:!1};let e=d.readFileSync(o,"utf8").trim(),[t,n,r]=e.split("|"),i=Number.parseInt(t);if(Number.isNaN(i))return d.unlinkSync(o),{running:!1};try{process.kill(i,0);let s=Number.parseInt(n),l=fn(Date.now()-s);return{running:!0,pid:i,uptime:l,mode:r||"foreground"}}catch{return d.unlinkSync(o),{running:!1}}}catch{return{running:!1}}}c(_,"getServiceStatus");function fn(o){let e=Math.floor(o/1e3),t=Math.floor(e/60),n=Math.floor(t/60),r=Math.floor(n/24);return r>0?`${r}\u5929 ${n%24}\u5C0F\u65F6 ${t%60}\u5206\u949F`:n>0?`${n}\u5C0F\u65F6 ${t%60}\u5206\u949F`:t>0?`${t}\u5206\u949F ${e%60}\u79D2`:`${e}\u79D2`}c(fn,"formatUptime");function Me(o,e){let t=`${o}|${Date.now()}|${e}`;d.writeFileSync(be(),t)}c(Me,"savePidInfo");function Y(){try{let o=be();d.existsSync(o)&&d.unlinkSync(o)}catch{}}c(Y,"cleanupPidFile");function un(){if(!g.configExists())return console.error(a.red("\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728")),console.log(a.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E')),!1;try{let e=g.getMcpEndpoints().filter(t=>t&&!t.includes("<\u8BF7\u586B\u5199"));return e.length===0?(console.log(a.yellow("\u26A0\uFE0F \u8B66\u544A: MCP \u7AEF\u70B9\u672A\u914D\u7F6E")),console.log(a.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(a.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(a.green(`\u2705 \u5DF2\u914D\u7F6E ${e.length} \u4E2A\u6709\u6548\u7684 MCP \u7AEF\u70B9`)),!0}catch(o){return console.error(a.red(`\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u65E0\u6548 - ${o instanceof Error?o.message:String(o)}`)),console.log(a.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u91CD\u65B0\u521D\u59CB\u5316\u914D\u7F6E')),!1}}c(un,"checkEnvironment");async function Ve(o=!1,e=!1){let t=M("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let n=_();if(n.running){t.fail(`\u670D\u52A1\u5DF2\u7ECF\u5728\u8FD0\u884C (PID: ${n.pid})`);return}if(t.text="\u68C0\u67E5\u73AF\u5883\u914D\u7F6E...",!un()){t.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}t.text=`\u542F\u52A8\u670D\u52A1 (${o?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,o?(await mn(e),t.succeed("\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8")):(await dn(e),t.succeed("\u670D\u52A1\u5DF2\u542F\u52A8"))}catch(n){t.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}c(Ve,"startService");async function mn(o=!1){let{spawn:e}=await import("child_process"),t=m.dirname(U(import.meta.url)),n="node",r=[m.join(t,"webServerStandalone.js"),o?"--open-browser":""].filter(Boolean),i=e(n,r,{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.FORCE_CONFIG_DIR||process.cwd(),XIAOZHI_DAEMON:"true"}});Me(i.pid,"daemon");let s=process.cwd();E.initLogFile(s),E.enableFileLogging(!0);let l=m.join(s,"xiaozhi.log"),p=d.createWriteStream(l,{flags:"a"});i.stdout?.pipe(p),i.stderr?.pipe(p),i.on("exit",(f,S)=>{f!==0&&f!==null&&E.error(`\u540E\u53F0\u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${f}, \u4FE1\u53F7: ${S})`),Y()}),i.on("error",f=>{throw E.error(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u9519\u8BEF: ${f.message}`),Y(),f}),i.unref(),console.log(a.green(`\u2705 \u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${i.pid})`)),console.log(a.gray(`\u65E5\u5FD7\u6587\u4EF6: ${l}`)),console.log(a.gray("\u4F7F\u7528 'xiaozhi attach' \u53EF\u4EE5\u67E5\u770B\u5B9E\u65F6\u65E5\u5FD7")),o&&console.log(a.green("\u{1F310} \u6D4F\u89C8\u5668\u5C06\u81EA\u52A8\u6253\u5F00"))}c(mn,"startWebServerInDaemon");async function dn(o=!1){let e=new q,t=c(async()=>{console.log(a.yellow(`
33
+ \u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),await e.stop(),Y(),process.exit(0)},"cleanup");if(process.on("SIGINT",t),process.on("SIGTERM",t),Me(process.pid,"foreground"),await e.start(),o){let r=`http://localhost:${g.getWebUIPort()}`;await Sn(r)}}c(dn,"startWebServerInForeground");async function Sn(o){try{let{spawn:e}=await import("child_process"),t=process.platform,n,r;t==="darwin"?(n="open",r=[o]):t==="win32"?(n="start",r=["",o]):(n="xdg-open",r=[o]),e(n,r,{detached:!0,stdio:"ignore"}),console.log(a.green(`\u{1F310} \u5DF2\u5C1D\u8BD5\u6253\u5F00\u6D4F\u89C8\u5668: ${o}`))}catch{console.log(a.yellow(`\u26A0\uFE0F \u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE: ${o}`))}}c(Sn,"openBrowserUrl");async function Ye(){let o=M("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=_();if(!e.running){o.warn("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}o.text=`\u505C\u6B62\u670D\u52A1 (PID: ${e.pid})...`;try{process.kill(e.pid,"SIGTERM");let t=0,n=30;for(;t<n;){await new Promise(r=>setTimeout(r,100));try{process.kill(e.pid,0),t++}catch{break}}try{process.kill(e.pid,0),o.text="\u5F3A\u5236\u505C\u6B62\u670D\u52A1...",process.kill(e.pid,"SIGKILL"),await new Promise(r=>setTimeout(r,500))}catch{}Y(),o.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(t){Y(),o.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}catch(e){o.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}c(Ye,"stopService");async function Cn(){let o=M("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=_();if(e.running){if(o.succeed("\u670D\u52A1\u72B6\u6001"),console.log(a.green("\u2705 \u670D\u52A1\u6B63\u5728\u8FD0\u884C")),console.log(a.gray(` PID: ${e.pid}`)),console.log(a.gray(` \u8FD0\u884C\u65F6\u95F4: ${e.uptime}`)),console.log(a.gray(` \u8FD0\u884C\u6A21\u5F0F: ${e.mode==="daemon"?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"}`)),e.mode==="daemon"){let t=m.join(process.cwd(),"xiaozhi.log");console.log(a.gray(` \u65E5\u5FD7\u6587\u4EF6: ${t}`))}}else o.succeed("\u670D\u52A1\u72B6\u6001"),console.log(a.red("\u274C \u670D\u52A1\u672A\u8FD0\u884C"))}catch(e){o.fail(`\u68C0\u67E5\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}c(Cn,"checkStatus");async function vn(){let o=M("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=_();if(!e.running){o.fail("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}if(e.mode!=="daemon"){o.fail("\u670D\u52A1\u4E0D\u662F\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C");return}o.succeed("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1..."),console.log(a.green(`\u5DF2\u8FDE\u63A5\u5230\u670D\u52A1 (PID: ${e.pid})`)),console.log(a.gray("\u6309 Ctrl+C \u53EF\u4EE5\u65AD\u5F00\u8FDE\u63A5\uFF08\u4E0D\u4F1A\u505C\u6B62\u670D\u52A1\uFF09")),console.log(a.gray("=".repeat(50)));let t=m.join(process.cwd(),"xiaozhi.log");if(d.existsSync(t))if(process.platform==="win32"){let{spawn:n}=await import("child_process"),r=n("powershell",["-Command",`Get-Content -Path "${t}" -Wait`],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(a.yellow(`
34
+ \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),r.kill(),process.exit(0)}),r.on("exit",()=>{process.exit(0)})}else{let{spawn:n}=await import("child_process"),r=n("tail",["-f",t],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(a.yellow(`
35
+ \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),r.kill(),process.exit(0)}),r.on("exit",()=>{process.exit(0)})}else console.log(a.yellow("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728"))}catch(e){o.fail(`\u8FDE\u63A5\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}c(vn,"attachService");async function yn(o=!1,e=!1){console.log(a.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await Ye(),await new Promise(t=>setTimeout(t,1e3)),await Ve(o,e)}c(yn,"restartService");async function Pn(o,e=!1){let t=M("\u542F\u52A8 MCP Server \u6A21\u5F0F...").start();try{if(!g.configExists()){t.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(a.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}let{MCPServer:n}=await Promise.resolve().then(()=>(Ze(),Je));if(e){let r=U(import.meta.url),i=m.dirname(r),s=gn("node",[m.join(i,"cli.js"),"start","--server",o.toString()],{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true",MCP_SERVER_MODE:"true"}});Me(s.pid,"daemon");let l=m.join(process.cwd(),"xiaozhi-mcp-server.log"),p=d.createWriteStream(l,{flags:"a"});s.stdout?.pipe(p),s.stderr?.pipe(p),s.unref(),t.succeed(`MCP Server \u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${s.pid}, Port: ${o})`),console.log(a.gray(`\u65E5\u5FD7\u6587\u4EF6: ${l}`))}else{let r=new n(o),i=c(async()=>{console.log(a.yellow(`
36
+ \u6B63\u5728\u505C\u6B62 MCP Server...`)),await r.stop(),process.exit(0)},"cleanup");process.on("SIGINT",i),process.on("SIGTERM",i),await r.start(),t.succeed("MCP Server \u5DF2\u542F\u52A8"),console.log(a.green("\u2705 MCP Server \u7AEF\u70B9\u5DF2\u542F\u52A8\uFF0C\u53EF\u901A\u8FC7\u4EE5\u4E0B\u5730\u5740\u8BBF\u95EE:")),console.log(a.green(` SSE endpoint: http://localhost:${o}/sse`)),console.log(a.green(` Messages endpoint: http://localhost:${o}/messages`)),console.log(a.green(` RPC endpoint: http://localhost:${o}/rpc`)),console.log(a.green(" \u7F51\u7EDC\u8BBF\u95EE: \u5C06 localhost \u66FF\u6362\u4E3A\u4F60\u7684IP\u5730\u5740")),console.log(a.yellow("\u{1F4A1} \u63D0\u793A: \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1"))}}catch(n){t.fail(`\u542F\u52A8 MCP Server \u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}c(Pn,"startMCPServerMode");function wn(){let o=Ke();console.log(a.blue(`xiaozhi v${o}`)),console.log(a.gray("MCP Calculator Service CLI Tool")),console.log(a.gray("Built with Node.js and TypeScript")),console.log(a.gray(`Node.js: ${process.version}`)),console.log(a.gray(`Platform: ${process.platform} ${process.arch}`))}c(wn,"showDetailedInfo");async function bn(o="json"){let e=M("\u521D\u59CB\u5316\u914D\u7F6E...").start();try{if(g.configExists()){e.warn("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728"),console.log(a.yellow("\u5982\u9700\u91CD\u65B0\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u5220\u9664\u73B0\u6709\u7684\u914D\u7F6E\u6587\u4EF6"));return}g.initConfig(o),e.succeed("\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u6210\u529F");let t=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),n=`xiaozhi.config.${o}`,r=m.join(t,n);console.log(a.green(`\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u521B\u5EFA: ${n}`)),console.log(a.yellow("\u{1F4DD} \u8BF7\u7F16\u8F91\u914D\u7F6E\u6587\u4EF6\u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9:")),console.log(a.gray(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${r}`)),console.log(a.yellow("\u{1F4A1} \u6216\u8005\u4F7F\u7528\u547D\u4EE4\u8BBE\u7F6E:")),console.log(a.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)}`)}}c(bn,"initConfig");function Mn(){let o=m.dirname(U(import.meta.url)),t=[m.join(o,"..","templates"),m.join(o,"templates"),m.join(o,"..","..","templates")].find(n=>d.existsSync(n));return t?d.readdirSync(t).filter(n=>{let r=m.join(t,n);return d.statSync(r).isDirectory()}):[]}c(Mn,"getAvailableTemplates");function qe(o,e){let t=o.length,n=e.length,r=Array(t+1).fill(null).map(()=>Array(n+1).fill(0));for(let s=0;s<=t;s++)r[s][0]=s;for(let s=0;s<=n;s++)r[0][s]=s;for(let s=1;s<=t;s++)for(let l=1;l<=n;l++)o[s-1]===e[l-1]?r[s][l]=r[s-1][l-1]:r[s][l]=Math.min(r[s-1][l]+1,r[s][l-1]+1,r[s-1][l-1]+1);let i=Math.max(t,n);return i===0?1:(i-r[t][n])/i}c(qe,"calculateSimilarity");function En(o,e){if(e.length===0)return null;let t=e[0],n=qe(o.toLowerCase(),t.toLowerCase());for(let r of e.slice(1)){let i=qe(o.toLowerCase(),r.toLowerCase());i>n&&(n=i,t=r)}return n>.5?t:null}c(En,"findSimilarTemplate");async function Tn(o){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(o);let n=e.createInterface({input:process.stdin,output:process.stdout}),r=c(i=>{let s=i.trim().toLowerCase();s==="y"||s==="yes"?(n.close(),t(!0)):s==="n"||s==="no"||s===""?(n.close(),t(!1)):process.stdout.write("\u8BF7\u8F93\u5165 y \u6216 n: ")},"handleInput");n.on("line",r),n.on("SIGINT",()=>{n.close(),t(!1)})})}c(Tn,"askUserConfirmation");function In(o){let e={mcpEndpoint:"<\u8BF7\u586B\u5199\u4F60\u7684\u63A5\u5165\u70B9\u5730\u5740\uFF08\u83B7\u53D6\u5730\u5740\u5728 xiaozhi.me\uFF09>",mcpServers:{}},t=m.join(o,"xiaozhi.config.json");d.writeFileSync(t,JSON.stringify(e,null,2),"utf8")}c(In,"createBasicConfig");async function xn(o,e){let t=M("\u521D\u59CB\u5316\u9879\u76EE...").start();try{let n=m.join(process.cwd(),o);if(d.existsSync(n)){t.fail(`\u76EE\u5F55 "${o}" \u5DF2\u5B58\u5728`),console.log(a.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 r=Mn();if(r.length===0){t.fail("\u627E\u4E0D\u5230 templates \u76EE\u5F55"),console.log(a.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u786E\u4FDD xiaozhi-client \u6B63\u786E\u5B89\u88C5"));return}if(!r.includes(e.template)){t.fail(`\u6A21\u677F "${e.template}" \u4E0D\u5B58\u5728`);let S=En(e.template,r);if(S)if(console.log(a.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${S}" \u5417\uFF1F`)),await Tn(a.cyan("\u786E\u8BA4\u4F7F\u7528\u6B64\u6A21\u677F\uFF1F(y/n): ")))e.template=S;else{console.log(a.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let A of r)console.log(a.gray(` - ${A}`));return}else{console.log(a.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let I of r)console.log(a.gray(` - ${I}`));return}}let i=m.dirname(U(import.meta.url)),l=[m.join(i,"..","templates"),m.join(i,"templates"),m.join(i,"..","..","templates")].find(S=>d.existsSync(S)),p=m.join(l,e.template);t.text=`\u4ECE\u6A21\u677F "${e.template}" \u521B\u5EFA\u9879\u76EE "${o}"...`,Qe(p,n,["node_modules",".pnpm-debug.log","pnpm-lock.yaml"]);let f=m.join(n,"xiaozhi.log");d.existsSync(f)||d.writeFileSync(f,"","utf8"),t.succeed(`\u9879\u76EE "${o}" \u521B\u5EFA\u6210\u529F`),console.log(a.green("\u2705 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(a.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(a.gray(` cd ${o}`)),console.log(a.gray(" pnpm install # \u5B89\u88C5\u4F9D\u8D56")),console.log(a.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9")),console.log(a.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1"))}else{t.text=`\u521B\u5EFA\u57FA\u672C\u9879\u76EE "${o}"...`,d.mkdirSync(n,{recursive:!0}),In(n);let r=m.join(n,"xiaozhi.log");d.writeFileSync(r,"","utf8"),t.succeed(`\u9879\u76EE "${o}" \u521B\u5EFA\u6210\u529F`),console.log(a.green("\u2705 \u57FA\u672C\u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(a.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(a.gray(` cd ${o}`)),console.log(a.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9\u548C\u670D\u52A1")),console.log(a.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1")),console.log(a.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 --template \u9009\u9879\u53EF\u4EE5\u4ECE\u6A21\u677F\u521B\u5EFA\u9879\u76EE"))}}catch(n){t.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}c(xn,"createProject");function Qe(o,e,t=[]){d.existsSync(e)||d.mkdirSync(e,{recursive:!0});let n=d.readdirSync(o);for(let r of n){if(t.some(p=>r.includes(p)))continue;let i=m.join(o,r),s=m.join(e,r);d.statSync(i).isDirectory()?Qe(i,s,t):d.copyFileSync(i,s)}}c(Qe,"copyDirectory");async function $n(){let o=M("\u542F\u52A8 UI \u670D\u52A1...").start();try{if(!g.configExists()){o.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(a.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}let e=new q;await e.start(),o.succeed("UI \u670D\u52A1\u5DF2\u542F\u52A8");let t=g.getWebUIPort();console.log(a.green("\u2705 \u914D\u7F6E\u7BA1\u7406\u7F51\u9875\u5DF2\u542F\u52A8\uFF0C\u53EF\u901A\u8FC7\u4EE5\u4E0B\u5730\u5740\u8BBF\u95EE:")),console.log(a.green(` \u672C\u5730\u8BBF\u95EE: http://localhost:${t}`)),console.log(a.green(` \u7F51\u7EDC\u8BBF\u95EE: http://<\u4F60\u7684IP\u5730\u5740>:${t}`)),console.log(a.yellow("\u{1F4A1} \u63D0\u793A: \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1"));let{spawn:n}=await import("child_process"),r=`http://localhost:${t}`;try{let s;process.platform==="darwin"?s=n("open",[r],{detached:!0,stdio:"ignore"}):process.platform==="win32"?s=n("cmd",["/c","start",r],{detached:!0,stdio:"ignore"}):s=n("xdg-open",[r],{detached:!0,stdio:"ignore"}),s.on("error",()=>{console.log(a.gray(`\u{1F4A1} \u63D0\u793A: \u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE: ${r}`))}),s.unref()}catch{console.log(a.gray(`\u{1F4A1} \u63D0\u793A: \u65E0\u6CD5\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u624B\u52A8\u8BBF\u95EE: ${r}`))}let i=!1;process.on("SIGINT",async()=>{i&&(console.log(a.red(`
37
+ \u5F3A\u5236\u9000\u51FA...`)),process.exit(1)),i=!0,console.log(a.yellow(`
38
+ \u6B63\u5728\u505C\u6B62 UI \u670D\u52A1...`));try{await e.stop(),console.log(a.green("UI \u670D\u52A1\u5DF2\u505C\u6B62"))}catch{console.log(a.red("\u505C\u6B62\u670D\u52A1\u65F6\u51FA\u9519\uFF0C\u5F3A\u5236\u9000\u51FA"))}process.exit(0)}),process.on("SIGTERM",async()=>{i=!0,await e.stop(),process.exit(0)})}catch(e){o.fail(`\u542F\u52A8 UI \u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}c($n,"startUIService");async function Rn(o,e){let t=M("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!g.configExists()){t.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(a.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}if(e)switch(o){case"mcpEndpoint":g.updateMcpEndpoint(e),t.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${e}`);break;case"heartbeatInterval":{let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<=0){t.fail("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}g.setHeartbeatInterval(n),t.succeed(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${n}ms`);break}case"heartbeatTimeout":{let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<=0){t.fail("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}g.setHeartbeatTimeout(n),t.succeed(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5DF2\u66F4\u65B0\u4E3A: ${n}ms`);break}case"reconnectInterval":{let n=Number.parseInt(e,10);if(Number.isNaN(n)||n<=0){t.fail("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}g.setReconnectInterval(n),t.succeed(`\u91CD\u8FDE\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${n}ms`);break}default:t.fail(`\u914D\u7F6E\u9879 ${o} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(a.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}else{t.text="\u8BFB\u53D6\u914D\u7F6E...";let n=g.getConfig();switch(o){case"mcpEndpoint":{t.succeed("\u914D\u7F6E\u4FE1\u606F");let r=g.getMcpEndpoints();r.length===0?console.log(a.yellow("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9")):r.length===1?console.log(a.green(`MCP \u7AEF\u70B9: ${r[0]}`)):(console.log(a.green(`MCP \u7AEF\u70B9 (${r.length} \u4E2A):`)),r.forEach((i,s)=>{console.log(a.gray(` ${s+1}. ${i}`))}));break}case"mcpServers":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(a.green("MCP \u670D\u52A1:"));for(let[r,i]of Object.entries(n.mcpServers))"type"in i&&i.type==="sse"?console.log(a.gray(` ${r}: [SSE] ${i.url}`)):console.log(a.gray(` ${r}: ${i.command} ${i.args.join(" ")}`));break;case"connection":{t.succeed("\u914D\u7F6E\u4FE1\u606F");let r=g.getConnectionConfig();console.log(a.green("\u8FDE\u63A5\u914D\u7F6E:")),console.log(a.gray(` \u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${r.heartbeatInterval}ms`)),console.log(a.gray(` \u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${r.heartbeatTimeout}ms`)),console.log(a.gray(` \u91CD\u8FDE\u95F4\u9694: ${r.reconnectInterval}ms`));break}case"heartbeatInterval":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(a.green(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${g.getHeartbeatInterval()}ms`));break;case"heartbeatTimeout":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(a.green(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${g.getHeartbeatTimeout()}ms`));break;case"reconnectInterval":t.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(a.green(`\u91CD\u8FDE\u95F4\u9694: ${g.getReconnectInterval()}ms`));break;default:t.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${o}`),console.log(a.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers, connection, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}}}catch(n){t.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}c(Rn,"configCommand");function On(){console.log(a.blue.bold("xiaozhi - MCP Calculator Service CLI")),console.log(),console.log(a.yellow("\u4F7F\u7528\u65B9\u6CD5:")),console.log(" xiaozhi <command> [options]"),console.log(),console.log(a.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(),console.log(a.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(a.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(a.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(a.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(a.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()}c(On,"showHelp");w.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(Ke(),"-v, --version","\u663E\u793A\u7248\u672C\u4FE1\u606F").helpOption("-h, --help","\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");w.command("create <projectName>").description("\u521B\u5EFA\u9879\u76EE").option("-t, --template <templateName>","\u4F7F\u7528\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u9879\u76EE").action(async(o,e)=>{await xn(o,e)});w.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 o=>{let e=o.format;e!=="json"&&e!=="json5"&&e!=="jsonc"&&(console.error(a.red("\u9519\u8BEF: \u683C\u5F0F\u5FC5\u987B\u662F json, json5 \u6216 jsonc")),process.exit(1)),await bn(e)});w.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(o,e)=>{await Rn(o,e)});w.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 o=>{if(o.stdio){let{spawn:e}=await import("child_process"),t=U(import.meta.url),n=m.dirname(t),r=m.join(n,"mcpServerProxy.js");e("node",[r],{stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}})}else if(o.server){let e=typeof o.server=="string"?Number.parseInt(o.server):3e3;await Pn(e,o.daemon)}else await Ve(o.daemon,o.ui)});w.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await Ye()});w.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await Cn()});w.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await vn()});w.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 o=>{await yn(o.daemon,o.ui)});var Ee=w.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 o=>{await We(o)});Ee.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async o=>{await Xe(o)});Ee.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(o,e,t)=>{t!=="enable"&&t!=="disable"&&(console.error(a.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await Be(o,e,t==="enable")});var ae=w.command("endpoint").description("\u7BA1\u7406 MCP \u7AEF\u70B9");ae.command("list").description("\u5217\u51FA\u6240\u6709 MCP \u7AEF\u70B9").action(async()=>{let o=M("\u8BFB\u53D6\u7AEF\u70B9\u914D\u7F6E...").start();try{let e=g.getMcpEndpoints();o.succeed("\u7AEF\u70B9\u5217\u8868"),e.length===0?console.log(a.yellow("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9")):(console.log(a.green(`\u5171 ${e.length} \u4E2A\u7AEF\u70B9:`)),e.forEach((t,n)=>{console.log(a.gray(` ${n+1}. ${t}`))}))}catch(e){o.fail(`\u8BFB\u53D6\u7AEF\u70B9\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}});ae.command("add <url>").description("\u6DFB\u52A0\u65B0\u7684 MCP \u7AEF\u70B9").action(async o=>{let e=M("\u6DFB\u52A0\u7AEF\u70B9...").start();try{g.addMcpEndpoint(o),e.succeed(`\u6210\u529F\u6DFB\u52A0\u7AEF\u70B9: ${o}`);let t=g.getMcpEndpoints();console.log(a.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)}`)}});ae.command("remove <url>").description("\u79FB\u9664\u6307\u5B9A\u7684 MCP \u7AEF\u70B9").action(async o=>{let e=M("\u79FB\u9664\u7AEF\u70B9...").start();try{g.removeMcpEndpoint(o),e.succeed(`\u6210\u529F\u79FB\u9664\u7AEF\u70B9: ${o}`);let t=g.getMcpEndpoints();console.log(a.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)}`)}});ae.command("set <urls...>").description("\u8BBE\u7F6E MCP \u7AEF\u70B9\uFF08\u53EF\u4EE5\u662F\u5355\u4E2A\u6216\u591A\u4E2A\uFF09").action(async o=>{let e=M("\u8BBE\u7F6E\u7AEF\u70B9...").start();try{if(o.length===1)g.updateMcpEndpoint(o[0]),e.succeed(`\u6210\u529F\u8BBE\u7F6E\u7AEF\u70B9: ${o[0]}`);else{g.updateMcpEndpoint(o),e.succeed(`\u6210\u529F\u8BBE\u7F6E ${o.length} \u4E2A\u7AEF\u70B9`);for(let[t,n]of o.entries())console.log(a.gray(` ${t+1}. ${n}`))}}catch(t){e.fail(`\u8BBE\u7F6E\u7AEF\u70B9\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}});w.command("ui").description("\u542F\u52A8\u914D\u7F6E\u7BA1\u7406\u7F51\u9875").action(async()=>{await $n()});w.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(o=>{o.V&&(wn(),process.exit(0))});process.argv.length<=2&&(On(),process.exit(0));w.parse(process.argv);export{qe as calculateSimilarity,un as checkEnvironment,fn as formatUptime,_ as getServiceStatus,Ke as getVersion};
44
39
  //# sourceMappingURL=cli.js.map