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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +98 -0
  2. package/dist/adaptiveMCPPipe.js +10 -10
  3. package/dist/adaptiveMCPPipe.js.map +1 -1
  4. package/dist/autoCompletion.js +1 -1
  5. package/dist/autoCompletion.js.map +1 -1
  6. package/dist/cli.js +19 -19
  7. package/dist/cli.js.map +1 -1
  8. package/dist/configManager.d.ts +12 -1
  9. package/dist/configManager.js +1 -1
  10. package/dist/configManager.js.map +1 -1
  11. package/dist/mcpCommands.js +1 -1
  12. package/dist/mcpCommands.js.map +1 -1
  13. package/dist/mcpServerProxy.js +7 -7
  14. package/dist/mcpServerProxy.js.map +1 -1
  15. package/dist/modelScopeMCPClient.js +2 -2
  16. package/dist/modelScopeMCPClient.js.map +1 -1
  17. package/dist/multiEndpointMCPPipe.js +6 -6
  18. package/dist/multiEndpointMCPPipe.js.map +1 -1
  19. package/dist/package.json +14 -2
  20. package/dist/services/mcpServer.js +9 -9
  21. package/dist/services/mcpServer.js.map +1 -1
  22. package/dist/streamableHttpMCPClient.js +2 -2
  23. package/dist/streamableHttpMCPClient.js.map +1 -1
  24. package/dist/templates/docker/mcpServers/calculator.js +106 -0
  25. package/dist/templates/docker/mcpServers/datetime.js +390 -0
  26. package/dist/templates/docker/package.json +13 -0
  27. package/dist/templates/docker/xiaozhi.config.json +21 -0
  28. package/dist/templates/modelscope/xiaozhi.config.json +20 -0
  29. package/dist/webServer.d.ts +6 -2
  30. package/dist/webServer.js +19 -19
  31. package/dist/webServer.js.map +1 -1
  32. package/docs/images/web-ui-preview.png +0 -0
  33. package/package.json +12 -2
  34. package/templates/docker/mcpServers/calculator.js +106 -0
  35. package/templates/docker/mcpServers/datetime.js +390 -0
  36. package/templates/docker/package.json +13 -0
  37. package/templates/docker/xiaozhi.config.json +21 -0
  38. package/templates/modelscope/xiaozhi.config.json +20 -0
  39. package/web/dist/assets/index-Da0jgqOv.css +1 -0
  40. package/web/dist/assets/index-DaMLY0Ce.js +236 -0
  41. package/web/dist/assets/index-DaMLY0Ce.js.map +1 -0
  42. package/web/dist/index.html +2 -2
  43. package/web/dist/assets/index-LtUI_xx4.css +0 -1
  44. package/web/dist/assets/index-lAiGa4ms.js +0 -169
  45. package/web/dist/assets/index-lAiGa4ms.js.map +0 -1
package/README.md CHANGED
@@ -67,6 +67,104 @@ pnpm install
67
67
  npx -y xiaozhi-client start
68
68
  ```
69
69
 
70
+ ### 使用 Docker 运行
71
+
72
+ 我们提供了预配置的 Docker 镜像,可以快速启动 xiaozhi-client 环境。
73
+
74
+ #### 准备工作
75
+
76
+ 1. **获取小智接入点地址**:
77
+
78
+ - 访问 [xiaozhi.me](https://xiaozhi.me) 获取你的接入点地址
79
+ - 参考文档:[小智 AI 配置 MCP 接入点使用说明](https://ccnphfhqs21z.feishu.cn/wiki/HiPEwZ37XiitnwktX13cEM5KnSb)
80
+
81
+ 2. **创建工作目录**(用于配置文件持久化):
82
+
83
+ ```bash
84
+ mkdir -p ~/.xiaozhi-client
85
+ ```
86
+
87
+ #### 快速启动
88
+
89
+ ```bash
90
+ # 拉取并运行 Docker 镜像(后台运行)
91
+ docker run -d \
92
+ --name xiaozhi-client \
93
+ -p 9999:9999 \
94
+ -p 3000:3000 \
95
+ -v ~/.xiaozhi-client:/workspaces \
96
+ shenjingnan/xiaozhi-client
97
+ ```
98
+
99
+ **端口说明**:
100
+
101
+ - `9999`:Web UI 配置界面端口
102
+ - `3000`:HTTP Server 模式端口(用于与其他 MCP 客户端集成)
103
+
104
+ #### 配置服务
105
+
106
+ 容器启动后,有两种方式配置 xiaozhi-client:
107
+
108
+ ##### 方式一:通过 Web UI 配置(推荐)
109
+
110
+ 1. 打开浏览器访问:<http://localhost:9999>
111
+ 2. 在 Web UI 界面中设置你的小智接入点地址
112
+ 3. 配置其他 MCP 服务(可选)
113
+
114
+ ##### 方式二:直接编辑配置文件
115
+
116
+ 1. 编辑配置文件:
117
+
118
+ ```bash
119
+ # 配置文件位于挂载的工作目录中
120
+ vim ~/.xiaozhi-client/xiaozhi.config.json
121
+ ```
122
+
123
+ 2. 修改 `mcpEndpoint` 字段:
124
+
125
+ ```json
126
+ {
127
+ "mcpEndpoint": "wss://api.xiaozhi.me/mcp/your-endpoint-id",
128
+ "mcpServers": {
129
+ // ... 其他配置
130
+ }
131
+ }
132
+ ```
133
+
134
+ 3. 重启容器使配置生效:
135
+
136
+ ```bash
137
+ docker restart xiaozhi-client
138
+ ```
139
+
140
+ #### 常用操作
141
+
142
+ ```bash
143
+ # 查看日志
144
+ docker logs -f xiaozhi-client
145
+
146
+ # 停止服务
147
+ docker stop xiaozhi-client
148
+
149
+ # 启动服务
150
+ docker start xiaozhi-client
151
+
152
+ # 重启服务
153
+ docker restart xiaozhi-client
154
+
155
+ # 删除容器(注意:配置文件会保留在 ~/.xiaozhi-client 中)
156
+ docker rm -f xiaozhi-client
157
+
158
+ # 检查服务状态
159
+ docker exec -it xiaozhi-client xiaozhi status
160
+
161
+ # 列出所有mcp服务
162
+ docker exec -it xiaozhi-client xiaozhi mcp list
163
+
164
+ # 列出所有mcp所提供的tools
165
+ docker exec -it xiaozhi-client xiaozhi mcp list --tools
166
+ ```
167
+
70
168
  ## 可用命令
71
169
 
72
170
  ```bash
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- var A=Object.defineProperty;var p=(s,e)=>A(s,"name",{value:e,configurable:!0});import a from"process";import{fileURLToPath as L}from"url";import{config as z}from"dotenv";import{copyFileSync as R,existsSync as S,readFileSync as O,writeFileSync as F}from"fs";import{dirname as D,resolve as d}from"path";import{fileURLToPath as k}from"url";import N from"json5";import*as T from"jsonc-parser";var W=D(k(import.meta.url)),E={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},I=class s{static{p(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=d(W,"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=d(e,o);if(S(n))return n}return d(e,"xiaozhi.config.json")}getConfigFileFormat(e){return e.endsWith(".json5")?"json5":e.endsWith(".jsonc")?"jsonc":"json"}static getInstance(){return s.instance||(s.instance=new s),s.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=d(e,o);if(S(n))return!0}return!1}initConfig(e="json"){if(!S(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=d(t,o);R(this.defaultConfigPath,n),this.config=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let e=this.getConfigFilePath(),t=this.getConfigFileFormat(e),o=O(e,"utf8"),n;switch(t){case"json5":n=N.parse(o);break;case"jsonc":n=T.parse(o);break;default:n=JSON.parse(o);break}return this.validateConfig(n),n}catch(e){throw e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let t=e;if(t.mcpEndpoint===void 0||t.mcpEndpoint===null)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(typeof t.mcpEndpoint!="string")if(Array.isArray(t.mcpEndpoint)){if(t.mcpEndpoint.length===0)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E0D\u80FD\u4E3A\u7A7A");for(let o of t.mcpEndpoint)if(typeof o!="string"||o.trim()==="")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5B57\u7B26\u4E32\u6570\u7EC4");if(!t.mcpServers||typeof t.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[o,n]of Object.entries(t.mcpServers)){if(!n||typeof n!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o} \u65E0\u6548`);let i=n;if(i.url&&typeof i.url=="string"){if(i.type&&i.type!=="sse"&&i.type!=="streamable-http")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.type \u5FC5\u987B\u662F "sse" \u6216 "streamable-http"`)}else{if(!i.command||typeof i.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.command \u65E0\u6548`);if(!Array.isArray(i.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.args \u5FC5\u987B\u662F\u6570\u7EC4`);if(i.env&&typeof i.env!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.env \u5FC5\u987B\u662F\u5BF9\u8C61`)}}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMcpEndpoint(){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 o={...this.getConfig(),mcpEndpoint:e};this.saveConfig(o)}addMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getConfig(),o=this.getMcpEndpoints();if(o.includes(e))throw new Error(`MCP \u7AEF\u70B9 ${e} \u5DF2\u5B58\u5728`);let n=[...o,e],i={...t,mcpEndpoint:n};this.saveConfig(i)}removeMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getConfig(),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 i=o.filter(h=>h!==e),c={...t,mcpEndpoint:i};this.saveConfig(c)}updateMcpServer(e,t){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if("type"in t&&t.type==="sse"){if(!t.url||typeof t.url!="string")throw new Error("SSE \u670D\u52A1\u914D\u7F6E\u7684 url \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else{let i=t;if(!i.command||typeof i.command!="string")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 command \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!Array.isArray(i.args))throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4");if(i.env&&typeof i.env!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61")}let o=this.getConfig(),n={...o,mcpServers:{...o.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 n={...this.getConfig()};n.mcpServerConfig||(n.mcpServerConfig={}),Object.keys(t).length===0?delete n.mcpServerConfig[e]:n.mcpServerConfig[e]={tools:t},this.saveConfig(n)}removeServerToolsConfig(e){let o={...this.getConfig()};o.mcpServerConfig&&(delete o.mcpServerConfig[e],this.saveConfig(o))}setToolEnabled(e,t,o,n){let c={...this.getConfig()};c.mcpServerConfig||(c.mcpServerConfig={}),c.mcpServerConfig[e]||(c.mcpServerConfig[e]={tools:{}}),c.mcpServerConfig[e].tools[t]={enable:o,...n&&{description:n}},this.saveConfig(c)}saveConfig(e){try{this.validateConfig(e);let t=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),o=d(t,"xiaozhi.config.json"),n=JSON.stringify(e,null,2);F(o,n,"utf8"),this.config=e}catch(t){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}reloadConfig(){this.config=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let t=this.getConfig().connection||{};return{heartbeatInterval:t.heartbeatInterval??E.heartbeatInterval,heartbeatTimeout:t.heartbeatTimeout??E.heartbeatTimeout,reconnectInterval:t.reconnectInterval??E.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let t=this.getConfig(),n={...t.connection||{},...e},i={...t,connection:n};this.saveConfig(i)}setHeartbeatInterval(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatInterval:e})}setHeartbeatTimeout(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatTimeout:e})}setReconnectInterval(e){if(e<=0)throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({reconnectInterval:e})}getModelScopeConfig(){return this.getConfig().modelscope||{}}getModelScopeApiKey(){return this.getModelScopeConfig().apiKey||process.env.MODELSCOPE_API_TOKEN}updateModelScopeConfig(e){let t=this.getConfig(),n={...t.modelscope||{},...e},i={...t,modelscope:n};this.saveConfig(i)}setModelScopeApiKey(e){if(!e||typeof e!="string")throw new Error("API Key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");this.updateModelScopeConfig({apiKey:e})}getWebUIConfig(){return this.getConfig().webUI||{}}getWebUIPort(){return this.getWebUIConfig().port??9999}updateWebUIConfig(e){let t=this.getConfig(),n={...t.webUI||{},...e},i={...t,webUI:n};this.saveConfig(i)}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=I.getInstance();import v from"fs";import _ from"path";import C from"chalk";import{createConsola as j}from"consola";function H(s){let e=s.getFullYear(),t=String(s.getMonth()+1).padStart(2,"0"),o=String(s.getDate()).padStart(2,"0"),n=String(s.getHours()).padStart(2,"0"),i=String(s.getMinutes()).padStart(2,"0"),c=String(s.getSeconds()).padStart(2,"0");return`${e}-${t}-${o} ${n}:${i}:${c}`}p(H,"formatDateTime");var P=class{static{p(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=j({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:p(t=>{let o={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},n={info:C.blue,success:C.green,warn:C.yellow,error:C.red,debug:C.gray,log:p(m=>m,"log")},i=o[t.type]||t.type.toUpperCase(),c=n[t.type]||(m=>m),h=H(new Date),$=c(`[${i}]`),x=`[${h}] ${$} ${t.args.join(" ")}`;if(!e)try{console.error(x)}catch(m){if(m instanceof Error&&m.message?.includes("EPIPE"))return;throw m}},"log")}])}initLogFile(e){this.logFilePath=_.join(e,"xiaozhi.log"),v.existsSync(this.logFilePath)||v.writeFileSync(this.logFilePath,""),this.writeStream=v.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(e,t,...o){if(this.writeStream){let i=`[${new Date().toISOString()}] [${e.toUpperCase()}] ${t}`,c=o.length>0?`${i} ${o.map(h=>typeof h=="object"?JSON.stringify(h):String(h)).join(" ")}`:i;this.writeStream.write(`${c}
3
- `)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=v.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)}},u=new P;import{spawn as G}from"child_process";import g from"process";import b from"ws";var M=p(()=>g.env.NODE_ENV==="test"||g.env.VITEST==="true","isTestEnvironment"),r=u.withTag("MULTI_MCP_PIPE");g.env.XIAOZHI_DAEMON==="true"&&g.env.XIAOZHI_CONFIG_DIR&&(u.initLogFile(g.env.XIAOZHI_CONFIG_DIR),u.enableFileLogging(!0));var w=class{static{p(this,"MultiEndpointMCPPipe")}mcpScript;endpoints;shouldReconnect;shutdownResolve;connectionConfig;constructor(e,t){this.mcpScript=e,this.endpoints=new Map,this.shouldReconnect=!0,r.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(),r.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},r.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),r.info(`\u6B63\u5728\u8FDE\u63A5\u5230 WebSocket \u670D\u52A1\u5668: ${e}`);let o=new b(e);t.websocket=o,o.on("open",()=>{r.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 i=n.toString();r.info(`<< [${e}] WebSocket\u6536\u5230\u6D88\u606F: ${i}`);try{let c=JSON.parse(i);(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(`${i}
4
- `)}),o.on("close",(n,i)=>{r.error(`[${e}] WebSocket \u8FDE\u63A5\u5DF2\u5173\u95ED: ${n} ${i}`),t.isConnected=!1,t.websocket=null,this.stopHeartbeat(e),this.reportStatusToWebUI(),this.shouldReconnect&&(n===4004?t.reconnectAttempt<t.maxReconnectAttempts?(r.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)):r.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=>{r.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,i=Math.min(o*2**(t.reconnectAttempt-1),6e4);r.info(`[${e}] \u8BA1\u5212\u5728 ${(i/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)&&r.info(`[${e}] MCP \u8FDB\u7A0B\u672A\u8FD0\u884C\uFF0C\u5C06\u5728\u91CD\u8FDE\u65F6\u542F\u52A8...`),this.connectToEndpoint(e))},i)}startMCPProcessForEndpoint(e){let t=this.endpoints.get(e);if(!t){r.error(`\u7AEF\u70B9\u4E0D\u5B58\u5728: ${e}`);return}if(t.process){r.info(`[${e}] MCP \u8FDB\u7A0B\u5DF2\u5728\u8FD0\u884C`);return}r.info(`[${e}] \u6B63\u5728\u542F\u52A8 MCP \u8FDB\u7A0B`),t.process=G("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 i of n)i.trim()&&this.handleMCPMessage(e,i)}),t.process.stderr?.on("data",o=>{if(g.env.XIAOZHI_DAEMON!=="true")try{g.stderr.write(o)}catch{}}),t.process.on("exit",(o,n)=>{r.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"&&r.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=>{r.error(`[${e}] \u8FDB\u7A0B\u9519\u8BEF: ${o.message}`),t.process=null,this.shouldReconnect&&r.info(`[${e}] MCP \u8FDB\u7A0B\u53D1\u751F\u9519\u8BEF\uFF0C\u5C06\u5728\u4E0B\u6B21\u91CD\u8FDE\u65F6\u5C1D\u8BD5\u91CD\u542F`)})}handleMCPMessage(e,t){r.info(`>> [${e}] mcpServerProxy\u53D1\u9001\u6D88\u606F\u957F\u5EA6: ${t.length} \u5B57\u8282`),r.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!==b.OPEN){r.warn(`[${e}] \u7AEF\u70B9\u4E0D\u53EF\u7528\uFF0C\u6D88\u606F\u65E0\u6CD5\u53D1\u9001`);return}try{o.websocket.send(`${t}
6
- `),r.info(`>> [${e}] \u6210\u529F\u53D1\u9001\u6D88\u606F\u5230 WebSocket`)}catch(n){r.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===b.OPEN&&(t.websocket.ping(),t.heartbeatTimeoutTimer=setTimeout(()=>{r.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(r.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===b.OPEN&&t.websocket.close()}catch(o){r.debug(`[${e}] \u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${o}`)}t.websocket=null}if(t.process&&!t.process.killed){try{r.debug(`[${e}] \u7EC8\u6B62 MCP \u8FDB\u7A0B...`),t.process.kill("SIGTERM"),await new Promise(o=>{let n=setTimeout(()=>{t.process&&!t.process.killed&&(r.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){r.warn(`[${e}] \u7EC8\u6B62 MCP \u8FDB\u7A0B\u65F6\u51FA\u9519: ${o}`)}t.process=null}t.stdoutBuffer="",t.isConnected=!1,r.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){r.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){r.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){r.warn(`[${e}] \u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${o}`)}t.websocket=null}}}shutdown(){r.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(),M()||setTimeout(()=>{g.exit(0)},100)}async reportStatusToWebUI(){if(!M())try{let e=l.getWebUIPort(),t=new b(`ws://localhost:${e}`);t.on("open",()=>{let o=[];for(let[i,c]of this.endpoints)o.push({url:i,connected:c.isConnected});let n={type:"clientStatus",data:{status:this.hasAnyConnection()?"connected":"disconnected",mcpEndpoints:o,activeMCPServers:[],lastHeartbeat:Date.now()}};t.send(JSON.stringify(n)),r.debug("\u5DF2\u5411 Web UI \u62A5\u544A\u72B6\u6001"),setTimeout(()=>{t.close()},1e3)}),t.on("error",o=>{r.debug(`Web UI \u8FDE\u63A5\u5931\u8D25\uFF08\u53EF\u80FD\u672A\u8FD0\u884C\uFF09: ${o.message}`)})}catch(e){r.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}};function y(s){let e=g.env.XIAOZHI_DAEMON==="true";g.on("SIGINT",()=>{r.info("\u6536\u5230\u4E2D\u65AD\u4FE1\u53F7\uFF0C\u6B63\u5728\u5173\u95ED..."),s.shutdown()}),g.on("SIGTERM",()=>{r.info("\u6536\u5230\u7EC8\u6B62\u4FE1\u53F7\uFF0C\u6B63\u5728\u5173\u95ED..."),s.shutdown()}),e&&(g.on("SIGHUP",()=>{r.info("\u6536\u5230 SIGHUP \u4FE1\u53F7\uFF08\u7EC8\u7AEF\u5DF2\u5173\u95ED\uFF09\uFF0C\u7EE7\u7EED\u5728\u5B88\u62A4\u8FDB\u7A0B\u6A21\u5F0F\u4E0B\u8FD0\u884C...")}),g.on("uncaughtException",t=>{t.message?.includes("EPIPE")||r.error(`\u672A\u6355\u83B7\u7684\u5F02\u5E38: ${t.message||t}
7
- ${t.stack||""}`)}),g.on("unhandledRejection",(t,o)=>{r.error(`\u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD: ${t instanceof Error?t.message:String(t)}`)}))}p(y,"setupSignalHandlers");z();var f=u.withTag("ADAPTIVE_MCP_PIPE");a.env.XIAOZHI_DAEMON==="true"&&a.env.XIAOZHI_CONFIG_DIR&&(u.initLogFile(a.env.XIAOZHI_CONFIG_DIR),u.enableFileLogging(!0));async function X(){a.argv.length<3&&(f.error("\u7528\u6CD5: node adaptiveMCPPipe.js <mcp_script>"),a.exit(1));let s=a.argv[2],e;try{if(a.env.XIAOZHI_DAEMON!=="true")try{a.stderr.write(`[DEBUG] XIAOZHI_CONFIG_DIR: ${a.env.XIAOZHI_CONFIG_DIR}
8
- `),a.stderr.write(`[DEBUG] process.cwd(): ${a.cwd()}
9
- `),a.stderr.write(`[DEBUG] configManager.getConfigPath(): ${l.getConfigPath()}
10
- `),a.stderr.write(`[DEBUG] configManager.configExists(): ${l.configExists()}
11
- `)}catch{}if(l.configExists())e=l.getMcpEndpoints(),f.info(`\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\u4E2D\u7684 MCP \u7AEF\u70B9\uFF08${e.length} \u4E2A\uFF09`);else{let n=a.env.MCP_ENDPOINT;n||(f.error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\u4E14\u672A\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF"),f.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),a.exit(1)),e=[n],f.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\uFF08\u5EFA\u8BAE\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\uFF09")}}catch(n){f.error(`\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`);let i=a.env.MCP_ENDPOINT;i||(f.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),a.exit(1)),e=[i],f.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\u4F5C\u4E3A\u5907\u7528\u65B9\u6848")}e.length===0&&(f.error("\u6CA1\u6709\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9"),a.exit(1));let t=e.filter(n=>!n||n.includes("<\u8BF7\u586B\u5199")?(f.warn(`\u8DF3\u8FC7\u65E0\u6548\u7AEF\u70B9: ${n}`),!1):!0);t.length===0&&(f.error("\u6CA1\u6709\u6709\u6548\u7684 MCP \u7AEF\u70B9"),f.error('\u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9'),a.exit(1)),f.info(t.length===1?"\u542F\u52A8\u5355\u7AEF\u70B9\u8FDE\u63A5":`\u542F\u52A8\u591A\u7AEF\u70B9\u8FDE\u63A5\uFF08${t.length} \u4E2A\u7AEF\u70B9\uFF09`);let o=new w(s,t);y(o);try{await o.start()}catch(n){f.error(`\u7A0B\u5E8F\u6267\u884C\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`),a.exit(1)}}p(X,"main");var Z=import.meta.url,B=L(Z),J=a.argv[1];B===J&&X().catch(s=>{f.error(`\u672A\u5904\u7406\u7684\u9519\u8BEF: ${s instanceof Error?s.message:String(s)}`),a.exit(1)});export{X as main};
2
+ var F=Object.defineProperty;var f=(r,e)=>F(r,"name",{value:e,configurable:!0});import c from"process";import{fileURLToPath as Z}from"url";import{config as z}from"dotenv";import{copyFileSync as W,existsSync as I,readFileSync as j,writeFileSync as D}from"fs";import{dirname as N,resolve as m}from"path";import{fileURLToPath as _}from"url";import*as S from"comment-json";import E from"json5";import*as $ from"json5-writer";function k(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")}f(k,"getMcpServerCommunicationType");function P(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(k(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"}`}}}f(P,"validateMcpServerConfig");var H=N(_(import.meta.url)),M={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},y=class r{static{f(this,"ConfigManager")}static instance;defaultConfigPath;config=null;currentConfigPath=null;json5Writer=null;constructor(){this.defaultConfigPath=m(H,"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 o=m(e,n);if(I(o))return o}return m(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 n of t){let o=m(e,n);if(I(o))return!0}return!1}initConfig(e="json"){if(!I(this.defaultConfigPath))throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.default.json \u4E0D\u5B58\u5728");if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let t=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),n=`xiaozhi.config.${e}`,o=m(t,n);W(this.defaultConfigPath,o),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=j(e,"utf8"),o;switch(t){case"json5":o=E.parse(n),this.json5Writer=$.load(n);break;case"jsonc":o=S.parse(n);break;default:o=JSON.parse(n);break}return this.validateConfig(o),o}catch(e){throw e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let t=e;if(t.mcpEndpoint===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,o]of Object.entries(t.mcpServers)){if(!o||typeof o!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${n} \u65E0\u6548`);let i=P(n,o);if(!i.valid)throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A${i.error}`)}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMutableConfig(){return this.config||(this.config=this.loadConfig()),this.config}getMcpEndpoint(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?e.mcpEndpoint[0]||"":e.mcpEndpoint}getMcpEndpoints(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?[...e.mcpEndpoint]:e.mcpEndpoint?[e.mcpEndpoint]:[]}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,t){return this.getServerToolsConfig(e)[t]?.enable!==!1}updateMcpEndpoint(e){if(Array.isArray(e)){if(e.length===0)throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E0D\u80FD\u4E3A\u7A7A");for(let 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 o=[...n,e];t.mcpEndpoint=o,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(g=>g!==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=P(e,t);if(!n.valid)throw new Error(n.error||"\u670D\u52A1\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");let o=this.getMutableConfig();o.mcpServers[e]=t,this.saveConfig(o)}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 o={...t,mcpServers:n};this.saveConfig(o)}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,o){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,...o&&{description:o}},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),o;switch(n){case"json5":try{this.json5Writer?(this.json5Writer.write(e),o=this.json5Writer.toSource()):(console.warn("\u6CA1\u6709 json5Writer \u5B9E\u4F8B\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON5 \u683C\u5F0F"),o=E.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),o=E.stringify(e,null,2)}break;case"jsonc":try{o=S.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),o=JSON.stringify(e,null,2)}break;default:o=JSON.stringify(e,null,2);break}D(t,o,"utf8"),this.config=e,logger.info("saveConfig",this.config),this.notifyConfigUpdate(e)}catch(t){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}reloadConfig(){this.config=null,this.currentConfigPath=null,this.json5Writer=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let t=this.getConfig().connection||{};return{heartbeatInterval:t.heartbeatInterval??M.heartbeatInterval,heartbeatTimeout:t.heartbeatTimeout??M.heartbeatTimeout,reconnectInterval:t.reconnectInterval??M.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let t=this.getMutableConfig();t.connection||(t.connection={}),Object.assign(t.connection,e),this.saveConfig(t)}setHeartbeatInterval(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatInterval:e})}setHeartbeatTimeout(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatTimeout:e})}setReconnectInterval(e){if(e<=0)throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({reconnectInterval:e})}getModelScopeConfig(){return this.getConfig().modelscope||{}}getModelScopeApiKey(){return this.getModelScopeConfig().apiKey||process.env.MODELSCOPE_API_TOKEN}updateModelScopeConfig(e){let t=this.getMutableConfig();t.modelscope||(t.modelscope={}),Object.assign(t.modelscope,e),this.saveConfig(t)}setModelScopeApiKey(e){if(!e||typeof e!="string")throw new Error("API Key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");this.updateModelScopeConfig({apiKey:e})}getWebUIConfig(){return this.getConfig().webUI||{}}getWebUIPort(){return this.getWebUIConfig().port??9999}notifyConfigUpdate(e){try{let t=global.__webServer;t&&typeof t.broadcastConfigUpdate=="function"&&(t.broadcastConfigUpdate(e),console.log("\u5DF2\u901A\u8FC7 WebSocket \u5E7F\u64AD\u914D\u7F6E\u66F4\u65B0"))}catch(t){console.warn("\u901A\u77E5 Web \u754C\u9762\u914D\u7F6E\u66F4\u65B0\u5931\u8D25:",t instanceof Error?t.message:String(t))}}updateWebUIConfig(e){let t=this.getMutableConfig();t.webUI||(t.webUI={}),Object.assign(t.webUI,e),this.saveConfig(t)}setWebUIPort(e){if(!Number.isInteger(e)||e<=0||e>65535)throw new Error("\u7AEF\u53E3\u53F7\u5FC5\u987B\u662F 1-65535 \u4E4B\u95F4\u7684\u6574\u6570");this.updateWebUIConfig({port:e})}},p=y.getInstance();import v from"fs";import G from"path";import C from"chalk";import{createConsola as L}from"consola";function J(r){let e=r.getFullYear(),t=String(r.getMonth()+1).padStart(2,"0"),n=String(r.getDate()).padStart(2,"0"),o=String(r.getHours()).padStart(2,"0"),i=String(r.getMinutes()).padStart(2,"0"),g=String(r.getSeconds()).padStart(2,"0");return`${e}-${t}-${n} ${o}:${i}:${g}`}f(J,"formatDateTime");var T=class{static{f(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=L({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:f(t=>{let n={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},o={info:C.blue,success:C.green,warn:C.yellow,error:C.red,debug:C.gray,log:f(h=>h,"log")},i=n[t.type]||t.type.toUpperCase(),g=o[t.type]||(h=>h),d=J(new Date),O=g(`[${i}]`),A=`[${d}] ${O} ${t.args.join(" ")}`;if(!e)try{console.error(A)}catch(h){if(h instanceof Error&&h.message?.includes("EPIPE"))return;throw h}},"log")}])}initLogFile(e){this.logFilePath=G.join(e,"xiaozhi.log"),v.existsSync(this.logFilePath)||v.writeFileSync(this.logFilePath,""),this.writeStream=v.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(e,t,...n){if(this.writeStream){let i=`[${new Date().toISOString()}] [${e.toUpperCase()}] ${t}`,g=n.length>0?`${i} ${n.map(d=>typeof d=="object"?JSON.stringify(d):String(d)).join(" ")}`:i;this.writeStream.write(`${g}
3
+ `)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=v.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)}},u=new T;import{spawn as X}from"child_process";import l from"process";import b from"ws";var x=f(()=>l.env.NODE_ENV==="test"||l.env.VITEST==="true","isTestEnvironment"),s=u.withTag("MULTI_MCP_PIPE");l.env.XIAOZHI_DAEMON==="true"&&l.env.XIAOZHI_CONFIG_DIR&&(u.initLogFile(l.env.XIAOZHI_CONFIG_DIR),u.enableFileLogging(!0));var w=class{static{f(this,"MultiEndpointMCPPipe")}mcpScript;endpoints;shouldReconnect;shutdownResolve;connectionConfig;constructor(e,t){this.mcpScript=e,this.endpoints=new Map,this.shouldReconnect=!0,s.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 n of t)this.endpoints.set(n,{url:n,websocket:null,isConnected:!1,reconnectAttempt:0,maxReconnectAttempts:5,process:null,stdoutBuffer:""});try{this.connectionConfig=p.getConnectionConfig(),s.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(n){this.connectionConfig={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},s.warn(`\u65E0\u6CD5\u83B7\u53D6\u8FDE\u63A5\u914D\u7F6E\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C: ${n instanceof Error?n.message:String(n)}`)}}async start(){return await this.connectToAllEndpoints(),this.reportStatusToWebUI(),new Promise(e=>{this.shutdownResolve=e})}async connectToAllEndpoints(){let e=[];for(let[t,n]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),s.info(`\u6B63\u5728\u8FDE\u63A5\u5230 WebSocket \u670D\u52A1\u5668: ${e}`);let n=new b(e);t.websocket=n,n.on("open",()=>{s.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)}),n.on("message",o=>{let i=o.toString();s.info(`<< [${e}] WebSocket\u6536\u5230\u6D88\u606F: ${i}`);try{let g=JSON.parse(i);(g.method==="notifications/initialized"||g.method==="tools/list"&&g.id||g?.result?.tools)&&setTimeout(()=>{this.reportStatusToWebUI()},1e3)}catch{}t.process?.stdin&&!t.process.stdin.destroyed&&t.process.stdin.write(`${i}
4
+ `)}),n.on("close",(o,i)=>{s.error(`[${e}] WebSocket \u8FDE\u63A5\u5DF2\u5173\u95ED: ${o} ${i}`),t.isConnected=!1,t.websocket=null,this.stopHeartbeat(e),this.reportStatusToWebUI(),this.shouldReconnect&&(o===4004?t.reconnectAttempt<t.maxReconnectAttempts?(s.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)):s.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))}),n.on("error",o=>{s.error(`[${e}] WebSocket \u9519\u8BEF: ${o.message}`),t.isConnected=!1,this.stopHeartbeat(e)}),n.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 n=this.connectionConfig.reconnectInterval,i=Math.min(n*2**(t.reconnectAttempt-1),6e4);s.info(`[${e}] \u8BA1\u5212\u5728 ${(i/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)&&s.info(`[${e}] MCP \u8FDB\u7A0B\u672A\u8FD0\u884C\uFF0C\u5C06\u5728\u91CD\u8FDE\u65F6\u542F\u52A8...`),this.connectToEndpoint(e))},i)}startMCPProcessForEndpoint(e){let t=this.endpoints.get(e);if(!t){s.error(`\u7AEF\u70B9\u4E0D\u5B58\u5728: ${e}`);return}if(t.process){s.info(`[${e}] MCP \u8FDB\u7A0B\u5DF2\u5728\u8FD0\u884C`);return}s.info(`[${e}] \u6B63\u5728\u542F\u52A8 MCP \u8FDB\u7A0B`),t.process=X("node",[this.mcpScript],{stdio:["pipe","pipe","pipe"]}),t.process.stdout?.on("data",n=>{t.stdoutBuffer+=n.toString();let o=t.stdoutBuffer.split(`
5
+ `);t.stdoutBuffer=o.pop()||"";for(let i of o)i.trim()&&this.handleMCPMessage(e,i)}),t.process.stderr?.on("data",n=>{if(l.env.XIAOZHI_DAEMON!=="true")try{l.stderr.write(n)}catch{}}),t.process.on("exit",(n,o)=>{s.warn(`[${e}] MCP \u8FDB\u7A0B\u5DF2\u9000\u51FA\uFF0C\u9000\u51FA\u7801: ${n}, \u4FE1\u53F7: ${o}`),t.process=null,this.shouldReconnect&&o!=="SIGTERM"&&o!=="SIGKILL"&&s.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",n=>{s.error(`[${e}] \u8FDB\u7A0B\u9519\u8BEF: ${n.message}`),t.process=null,this.shouldReconnect&&s.info(`[${e}] MCP \u8FDB\u7A0B\u53D1\u751F\u9519\u8BEF\uFF0C\u5C06\u5728\u4E0B\u6B21\u91CD\u8FDE\u65F6\u5C1D\u8BD5\u91CD\u542F`)})}handleMCPMessage(e,t){s.info(`>> [${e}] mcpServerProxy\u53D1\u9001\u6D88\u606F\u957F\u5EA6: ${t.length} \u5B57\u8282`),s.info(`>> [${e}] mcpServerProxy\u53D1\u9001\u6D88\u606F: ${t.substring(0,500)}...`),this.sendToEndpoint(e,t)}sendToEndpoint(e,t){let n=this.endpoints.get(e);if(!n||!n.websocket||n.websocket.readyState!==b.OPEN){s.warn(`[${e}] \u7AEF\u70B9\u4E0D\u53EF\u7528\uFF0C\u6D88\u606F\u65E0\u6CD5\u53D1\u9001`);return}try{n.websocket.send(`${t}
6
+ `),s.info(`>> [${e}] \u6210\u529F\u53D1\u9001\u6D88\u606F\u5230 WebSocket`)}catch(o){s.error(`>> [${e}] \u53D1\u9001\u6D88\u606F\u5230 WebSocket \u5931\u8D25: ${o}`)}}startHeartbeat(e){let t=this.endpoints.get(e);t&&(this.stopHeartbeat(e),t.heartbeatTimer=setInterval(()=>{t.websocket&&t.websocket.readyState===b.OPEN&&(t.websocket.ping(),t.heartbeatTimeoutTimer=setTimeout(()=>{s.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(s.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===b.OPEN&&t.websocket.close()}catch(n){s.debug(`[${e}] \u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${n}`)}t.websocket=null}if(t.process&&!t.process.killed){try{s.debug(`[${e}] \u7EC8\u6B62 MCP \u8FDB\u7A0B...`),t.process.kill("SIGTERM"),await new Promise(n=>{let o=setTimeout(()=>{t.process&&!t.process.killed&&(s.warn(`[${e}] MCP \u8FDB\u7A0B\u672A\u80FD\u6B63\u5E38\u9000\u51FA\uFF0C\u5F3A\u5236\u7EC8\u6B62`),t.process.kill("SIGKILL")),n()},2e3);t.process?.on("exit",()=>{clearTimeout(o),n()})})}catch(n){s.warn(`[${e}] \u7EC8\u6B62 MCP \u8FDB\u7A0B\u65F6\u51FA\u9519: ${n}`)}t.process=null}t.stdoutBuffer="",t.isConnected=!1,s.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){s.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(n){s.error(`[${e}] \u7EC8\u6B62\u8FDB\u7A0B\u65F6\u51FA\u9519: ${n instanceof Error?n.message:String(n)}`)}t.process=null}if(t.websocket){try{t.websocket.close()}catch(n){s.warn(`[${e}] \u5173\u95ED WebSocket \u65F6\u51FA\u9519: ${n}`)}t.websocket=null}}}shutdown(){s.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(),x()||setTimeout(()=>{l.exit(0)},100)}async reportStatusToWebUI(){if(!x())try{let e=p.getWebUIPort(),t=new b(`ws://localhost:${e}`);t.on("open",()=>{let n=[];for(let[i,g]of this.endpoints)n.push({url:i,connected:g.isConnected});let o={type:"clientStatus",data:{status:this.hasAnyConnection()?"connected":"disconnected",mcpEndpoints:n,activeMCPServers:[],lastHeartbeat:Date.now()}};t.send(JSON.stringify(o)),s.debug("\u5DF2\u5411 Web UI \u62A5\u544A\u72B6\u6001"),setTimeout(()=>{t.close()},1e3)}),t.on("error",n=>{s.debug(`Web UI \u8FDE\u63A5\u5931\u8D25\uFF08\u53EF\u80FD\u672A\u8FD0\u884C\uFF09: ${n.message}`)})}catch(e){s.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}};function R(r){let e=l.env.XIAOZHI_DAEMON==="true";l.on("SIGINT",()=>{s.info("\u6536\u5230\u4E2D\u65AD\u4FE1\u53F7\uFF0C\u6B63\u5728\u5173\u95ED..."),r.shutdown()}),l.on("SIGTERM",()=>{s.info("\u6536\u5230\u7EC8\u6B62\u4FE1\u53F7\uFF0C\u6B63\u5728\u5173\u95ED..."),r.shutdown()}),e&&(l.on("SIGHUP",()=>{s.info("\u6536\u5230 SIGHUP \u4FE1\u53F7\uFF08\u7EC8\u7AEF\u5DF2\u5173\u95ED\uFF09\uFF0C\u7EE7\u7EED\u5728\u5B88\u62A4\u8FDB\u7A0B\u6A21\u5F0F\u4E0B\u8FD0\u884C...")}),l.on("uncaughtException",t=>{t.message?.includes("EPIPE")||s.error(`\u672A\u6355\u83B7\u7684\u5F02\u5E38: ${t.message||t}
7
+ ${t.stack||""}`)}),l.on("unhandledRejection",(t,n)=>{s.error(`\u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD: ${t instanceof Error?t.message:String(t)}`)}))}f(R,"setupSignalHandlers");z();var a=u.withTag("ADAPTIVE_MCP_PIPE");c.env.XIAOZHI_DAEMON==="true"&&c.env.XIAOZHI_CONFIG_DIR&&(u.initLogFile(c.env.XIAOZHI_CONFIG_DIR),u.enableFileLogging(!0));async function B(){c.argv.length<3&&(a.error("\u7528\u6CD5: node adaptiveMCPPipe.js <mcp_script>"),c.exit(1));let r=c.argv[2],e;try{if(c.env.XIAOZHI_DAEMON!=="true")try{c.stderr.write(`[DEBUG] XIAOZHI_CONFIG_DIR: ${c.env.XIAOZHI_CONFIG_DIR}
8
+ `),c.stderr.write(`[DEBUG] process.cwd(): ${c.cwd()}
9
+ `),c.stderr.write(`[DEBUG] configManager.getConfigPath(): ${p.getConfigPath()}
10
+ `),c.stderr.write(`[DEBUG] configManager.configExists(): ${p.configExists()}
11
+ `)}catch{}if(p.configExists())e=p.getMcpEndpoints(),a.info(`\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\u4E2D\u7684 MCP \u7AEF\u70B9\uFF08${e.length} \u4E2A\uFF09`);else{let o=c.env.MCP_ENDPOINT;o||(a.error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\u4E14\u672A\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF"),a.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),c.exit(1)),e=[o],a.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\uFF08\u5EFA\u8BAE\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\uFF09")}}catch(o){a.error(`\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`);let i=c.env.MCP_ENDPOINT;i||(a.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),c.exit(1)),e=[i],a.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\u4F5C\u4E3A\u5907\u7528\u65B9\u6848")}let t=e.filter(o=>!o||o.includes("<\u8BF7\u586B\u5199")?(a.warn(`\u8DF3\u8FC7\u65E0\u6548\u7AEF\u70B9: ${o}`),!1):!0);if(t.length===0){a.warn("\u6CA1\u6709\u6709\u6548\u7684 MCP \u7AEF\u70B9\uFF0C\u5C06\u8DF3\u8FC7\u5C0F\u667A\u670D\u52A1\u7AEF\u8FDE\u63A5"),a.info("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"),a.info('\u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9'),await K(r);return}a.info(t.length===1?"\u542F\u52A8\u5355\u7AEF\u70B9\u8FDE\u63A5":`\u542F\u52A8\u591A\u7AEF\u70B9\u8FDE\u63A5\uFF08${t.length} \u4E2A\u7AEF\u70B9\uFF09`);let n=new w(r,t);R(n);try{await n.start()}catch(o){a.error(`\u7A0B\u5E8F\u6267\u884C\u9519\u8BEF: ${o instanceof Error?o.message:String(o)}`),c.exit(1)}}f(B,"main");async function K(r){a.info("\u542F\u52A8 MCP \u670D\u52A1\u5668\u4EE3\u7406\uFF08\u65E0\u5C0F\u667A\u670D\u52A1\u7AEF\u8FDE\u63A5\uFF09");let{spawn:e}=await import("child_process"),t=e("node",[r],{stdio:["pipe","inherit","inherit"],env:{...c.env,XIAOZHI_CONFIG_DIR:c.env.XIAOZHI_CONFIG_DIR||c.cwd()}}),n=f(()=>{a.info("\u6B63\u5728\u5173\u95ED MCP \u670D\u52A1\u5668\u4EE3\u7406..."),t&&!t.killed&&(t.kill("SIGTERM"),setTimeout(()=>{t.killed||t.kill("SIGKILL")},5e3)),c.exit(0)},"cleanup");return c.on("SIGINT",n),c.on("SIGTERM",n),t.on("exit",(o,i)=>{a.warn(`MCP \u670D\u52A1\u5668\u4EE3\u7406\u5DF2\u9000\u51FA\uFF0C\u9000\u51FA\u7801: ${o}, \u4FE1\u53F7: ${i}`),i!=="SIGTERM"&&i!=="SIGKILL"&&(a.error("MCP \u670D\u52A1\u5668\u4EE3\u7406\u610F\u5916\u9000\u51FA"),c.exit(1))}),t.on("error",o=>{a.error(`MCP \u670D\u52A1\u5668\u4EE3\u7406\u9519\u8BEF: ${o.message}`),c.exit(1)}),a.info("MCP \u670D\u52A1\u5668\u4EE3\u7406\u5DF2\u542F\u52A8\uFF0C\u7B49\u5F85\u8FDE\u63A5..."),new Promise(()=>{})}f(K,"startMCPServerProxyOnly");var U=import.meta.url,V=Z(U),q=c.argv[1];V===q&&B().catch(r=>{a.error(`\u672A\u5904\u7406\u7684\u9519\u8BEF: ${r instanceof Error?r.message:String(r)}`),c.exit(1)});export{B as main};
12
12
  //# sourceMappingURL=adaptiveMCPPipe.js.map