xiaozhi-client 1.4.0-beta.4 → 1.5.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -0
- package/dist/cli.js +19 -9
- package/dist/cli.js.map +1 -1
- package/dist/mcpServerProxy.js +7 -7
- package/dist/mcpServerProxy.js.map +1 -1
- package/dist/package.json +3 -1
- package/dist/services/mcpServer.d.ts +20 -0
- package/dist/services/mcpServer.js +12 -0
- package/dist/services/mcpServer.js.map +1 -0
- package/docs/images/integrate-to-cherry-studio.png +0 -0
- package/docs/images/integrate-to-cursor.png +0 -0
- package/package.json +3 -1
- package/web/dist/assets/index-FD98vGpI.js.map +1 -1
package/README.md
CHANGED
|
@@ -139,6 +139,7 @@ xiaozhi-client 现已支持接入 [ModelScope](https://www.modelscope.cn/mcp)
|
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
3. 启动服务:
|
|
142
|
+
|
|
142
143
|
```bash
|
|
143
144
|
xiaozhi start
|
|
144
145
|
```
|
|
@@ -302,3 +303,88 @@ xiaozhi-client 提供了一个现代化的 Web UI 界面,让配置 MCP 服务
|
|
|
302
303
|
```bash
|
|
303
304
|
xiaozhi ui
|
|
304
305
|
```
|
|
306
|
+
|
|
307
|
+
## 作为 MCP Server 集成到其他客户端
|
|
308
|
+
|
|
309
|
+
> 需升级至 `1.5.0` 及以上版本
|
|
310
|
+
|
|
311
|
+
xiaozhi-client 不仅可以作为小智 AI 的客户端使用,还可以作为标准的 MCP Server 被 Cursor、Cherry Studio 等支持 MCP 协议的客户端集成。
|
|
312
|
+
|
|
313
|
+
这样做的好处是你无需在多个客户端中重复配置 MCP Server,只需要在 xiaozhi.config.json 中配置一遍 MCP 服务,即可在任意客户端集成。
|
|
314
|
+
|
|
315
|
+
并且,由于 xiaozhi-client 允许你自定义暴露哪些 MCP Server tools 因此你可以选择性的定制自己的工具集。
|
|
316
|
+
|
|
317
|
+

|
|
318
|
+

|
|
319
|
+
|
|
320
|
+
### 方式一:使用 stdio 模式(推荐)
|
|
321
|
+
|
|
322
|
+
第一步:确保已全局安装 xiaozhi-client:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
npm install -g xiaozhi-client
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
第二步:在 客户端 的 MCP 配置中添加:
|
|
329
|
+
|
|
330
|
+
```json
|
|
331
|
+
{
|
|
332
|
+
"mcpServers": {
|
|
333
|
+
"xiaozhi-client": {
|
|
334
|
+
"command": "xiaozhi",
|
|
335
|
+
"args": ["start", "--stdio"]
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
提示:如果需要指定配置文件位置,可以使用环境变量
|
|
342
|
+
|
|
343
|
+
配置文件的查找顺序
|
|
344
|
+
|
|
345
|
+
1. 当前工作目录
|
|
346
|
+
2. 通过 `XIAOZHI_CONFIG_DIR` 环境变量指定的目录
|
|
347
|
+
|
|
348
|
+
```json
|
|
349
|
+
{
|
|
350
|
+
"mcpServers": {
|
|
351
|
+
"xiaozhi-client": {
|
|
352
|
+
"command": "xiaozhi",
|
|
353
|
+
"args": ["start", "--stdio"],
|
|
354
|
+
"env": {
|
|
355
|
+
"XIAOZHI_CONFIG_DIR": "/path/to/your/config/directory"
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
#### 方式二:使用 HTTP Server 模式
|
|
363
|
+
|
|
364
|
+
> 如果你将 xiaozhi-client 装在 docker 中使用,可以通过 http server 的方式暴露给外部客户端
|
|
365
|
+
|
|
366
|
+
第一步:启动 xiaozhi-client 的 HTTP Server:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
# 使用默认端口 3000
|
|
370
|
+
xiaozhi start --server
|
|
371
|
+
|
|
372
|
+
# 使用自定义端口
|
|
373
|
+
xiaozhi start --server 8080
|
|
374
|
+
|
|
375
|
+
# 后台运行
|
|
376
|
+
xiaozhi start --server --daemon
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
第二步:在 客户端 中配置 SSE 连接:
|
|
380
|
+
|
|
381
|
+
```json
|
|
382
|
+
{
|
|
383
|
+
"mcpServers": {
|
|
384
|
+
"xiaozhi-client": {
|
|
385
|
+
"type": "sse",
|
|
386
|
+
"url": "http://localhost:3000/sse"
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var to=Object.defineProperty;var g=(n,o)=>to(n,"name",{value:o,configurable:!0});import{spawn as X}from"child_process";import h from"fs";import vo from"os";import p from"path";import{fileURLToPath as j}from"url";import s from"chalk";import{Command as wo}from"commander";import C from"ora";import lo from"omelette";import{copyFileSync as no,existsSync as N,readFileSync as io,writeFileSync as ro}from"fs";import{dirname as so,resolve as R}from"path";import{fileURLToPath as co}from"url";var ao=so(co(import.meta.url)),k={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},O=class n{static{g(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=R(ao,"xiaozhi.config.default.json")}getConfigFilePath(){let o=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return R(o,"xiaozhi.config.json")}static getInstance(){return n.instance||(n.instance=new n),n.instance}configExists(){let o=this.getConfigFilePath();return N(o)}initConfig(){if(!N(this.defaultConfigPath))throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.default.json \u4E0D\u5B58\u5728");if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let o=this.getConfigFilePath();no(this.defaultConfigPath,o),this.config=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let o=this.getConfigFilePath(),e=io(o,"utf8"),t=JSON.parse(e);return this.validateConfig(t),t}catch(o){throw o instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${o.message}`):o}}validateConfig(o){if(!o||typeof o!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let e=o;if(!e.mcpEndpoint||typeof e.mcpEndpoint!="string")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(!e.mcpServers||typeof e.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[t,i]of Object.entries(e.mcpServers)){if(!i||typeof i!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t} \u65E0\u6548`);let r=i;if(r.type==="sse"){if(!r.url||typeof r.url!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.url \u65E0\u6548`)}else{if(!r.command||typeof r.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.command \u65E0\u6548`);if(!Array.isArray(r.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.args \u5FC5\u987B\u662F\u6570\u7EC4`);if(r.env&&typeof r.env!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.env \u5FC5\u987B\u662F\u5BF9\u8C61`)}}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMcpEndpoint(){return this.getConfig().mcpEndpoint}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(o){return this.getMcpServerConfig()[o]?.tools||{}}isToolEnabled(o,e){return this.getServerToolsConfig(o)[e]?.enable!==!1}updateMcpEndpoint(o){if(!o||typeof o!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t={...this.getConfig(),mcpEndpoint:o};this.saveConfig(t)}updateMcpServer(o,e){if(!o||typeof o!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if("type"in e&&e.type==="sse"){if(!e.url||typeof e.url!="string")throw new Error("SSE \u670D\u52A1\u914D\u7F6E\u7684 url \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else{let r=e;if(!r.command||typeof r.command!="string")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 command \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!Array.isArray(r.args))throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4");if(r.env&&typeof r.env!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61")}let t=this.getConfig(),i={...t,mcpServers:{...t.mcpServers,[o]:e}};this.saveConfig(i)}removeMcpServer(o){if(!o||typeof o!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let e=this.getConfig();if(!e.mcpServers[o])throw new Error(`\u670D\u52A1 ${o} \u4E0D\u5B58\u5728`);let t={...e.mcpServers};delete t[o];let i={...e,mcpServers:t};this.saveConfig(i)}updateServerToolsConfig(o,e){let i={...this.getConfig()};i.mcpServerConfig||(i.mcpServerConfig={}),i.mcpServerConfig[o]={tools:e},this.saveConfig(i)}setToolEnabled(o,e,t,i){let c={...this.getConfig()};c.mcpServerConfig||(c.mcpServerConfig={}),c.mcpServerConfig[o]||(c.mcpServerConfig[o]={tools:{}}),c.mcpServerConfig[o].tools[e]={enable:t,...i&&{description:i}},this.saveConfig(c)}saveConfig(o){try{this.validateConfig(o);let e=this.getConfigFilePath(),t=JSON.stringify(o,null,2);ro(e,t,"utf8"),this.config=o}catch(e){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}reloadConfig(){this.config=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let e=this.getConfig().connection||{};return{heartbeatInterval:e.heartbeatInterval??k.heartbeatInterval,heartbeatTimeout:e.heartbeatTimeout??k.heartbeatTimeout,reconnectInterval:e.reconnectInterval??k.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(o){let e=this.getConfig(),i={...e.connection||{},...o},r={...e,connection:i};this.saveConfig(r)}setHeartbeatInterval(o){if(o<=0)throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatInterval:o})}setHeartbeatTimeout(o){if(o<=0)throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatTimeout:o})}setReconnectInterval(o){if(o<=0)throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({reconnectInterval:o})}getModelScopeConfig(){return this.getConfig().modelscope||{}}getModelScopeApiKey(){return this.getModelScopeConfig().apiKey||process.env.MODELSCOPE_API_TOKEN}updateModelScopeConfig(o){let e=this.getConfig(),i={...e.modelscope||{},...o},r={...e,modelscope:i};this.saveConfig(r)}setModelScopeApiKey(o){if(!o||typeof o!="string")throw new Error("API Key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");this.updateModelScopeConfig({apiKey:o})}getWebUIConfig(){return this.getConfig().webUI||{}}getWebUIPort(){return this.getWebUIConfig().port??9999}updateWebUIConfig(o){let e=this.getConfig(),i={...e.webUI||{},...o},r={...e,webUI:i};this.saveConfig(r)}setWebUIPort(o){if(!Number.isInteger(o)||o<=0||o>65535)throw new Error("\u7AEF\u53E3\u53F7\u5FC5\u987B\u662F 1-65535 \u4E4B\u95F4\u7684\u6574\u6570");this.updateWebUIConfig({port:o})}},l=O.getInstance();function go(){try{if(!l.configExists())return[];let n=l.getMcpServers();return Object.keys(n)}catch{return[]}}g(go,"getMcpServerNames");function fo(n){try{if(!l.configExists())return[];let o=l.getServerToolsConfig(n);return Object.keys(o)}catch{return[]}}g(fo,"getServerToolNames");function D(){let n=lo("xiaozhi <command>");if(n.on("command",({reply:o})=>{o(["create","init","config","start","stop","status","attach","restart","mcp","completion"])}),n.on("complete",(o,{line:e,before:t,reply:i})=>{process.env.XIAOZHI_DEBUG_COMPLETION&&console.error(`Debug completion - line: "${e}", before: "${t}", fragment: "${o}"`);let r=e.trim().split(/\s+/),a=e!==e.trim()?r.length:r.length-1;if(r[1]==="mcp"){let d=r[2];if(a===2){let m=["list","server","tool"],u=r[2]||"",y=m.filter(b=>b.startsWith(u));i(y);return}if(a===3){switch(d){case"list":{let m=["--tools"],u=r[3]||"",y=m.filter(b=>b.startsWith(u));i(y);break}case"server":case"tool":{let m=go(),u=r[3]||"",y=m.filter(b=>b.startsWith(u));i(y);break}default:i([])}return}if(a===4&&d==="tool"){let m=r[3],u=fo(m),y=r[4]||"",b=u.filter(I=>I.startsWith(y));i(b);return}if(a===5&&d==="tool"){let m=["enable","disable"],u=r[5]||"",y=m.filter(b=>b.startsWith(u));i(y);return}}if(a===2){switch(r[1]){case"create":i(["--template","-t"]);break;case"start":case"restart":i(["--daemon","-d"]);break;case"completion":i(["install","uninstall"]);break;default:i([])}return}i([])}),process.argv.includes("--completion")){try{console.log(n.setupShellInitFile())}catch(o){console.error("\u751F\u6210\u81EA\u52A8\u8865\u5168\u811A\u672C\u65F6\u51FA\u9519:",o)}process.exit(0)}process.argv.includes("--completion-fish")&&(console.log(n.setupShellInitFile("fish")),process.exit(0)),process.argv.includes("--compzsh")||process.argv.includes("--compbash"),n.init()}g(D,"setupAutoCompletion");function A(){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(A,"showCompletionHelp");import M from"fs";import po from"path";import x from"chalk";import{createConsola as mo}from"consola";function uo(n){let o=n.getFullYear(),e=String(n.getMonth()+1).padStart(2,"0"),t=String(n.getDate()).padStart(2,"0"),i=String(n.getHours()).padStart(2,"0"),r=String(n.getMinutes()).padStart(2,"0"),c=String(n.getSeconds()).padStart(2,"0");return`${o}-${e}-${t} ${i}:${r}:${c}`}g(uo,"formatDateTime");var P=class{static{g(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=mo({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let o=this.isDaemonMode;this.consolaInstance.setReporters([{log:g(e=>{let t={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},i={info:x.blue,success:x.green,warn:x.yellow,error:x.red,debug:x.gray,log:g(u=>u,"log")},r=t[e.type]||e.type.toUpperCase(),c=i[e.type]||(u=>u),a=uo(new Date),d=c(`[${r}]`),m=`[${a}] ${d} ${e.args.join(" ")}`;if(!o)try{console.error(m)}catch(u){if(u instanceof Error&&u.message?.includes("EPIPE"))return;throw u}},"log")}])}initLogFile(o){this.logFilePath=po.join(o,"xiaozhi.log"),M.existsSync(this.logFilePath)||M.writeFileSync(this.logFilePath,""),this.writeStream=M.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(o,e,...t){if(this.writeStream){let r=`[${new Date().toISOString()}] [${o.toUpperCase()}] ${e}`,c=t.length>0?`${r} ${t.map(a=>typeof a=="object"?JSON.stringify(a):String(a)).join(" ")}`:r;this.writeStream.write(`${c}
|
|
3
|
-
`)}}enableFileLogging(
|
|
2
|
+
var J=Object.defineProperty;var l=(n,e)=>J(n,"name",{value:e,configurable:!0});var G=(n,e)=>()=>(n&&(e=n(n=0)),e);var fe=(n,e)=>{for(var o in e)J(n,o,{get:e[o],enumerable:!0})};import z from"fs";import we from"path";import M from"chalk";import{createConsola as Pe}from"consola";function xe(n){let e=n.getFullYear(),o=String(n.getMonth()+1).padStart(2,"0"),t=String(n.getDate()).padStart(2,"0"),r=String(n.getHours()).padStart(2,"0"),i=String(n.getMinutes()).padStart(2,"0"),c=String(n.getSeconds()).padStart(2,"0");return`${e}-${o}-${t} ${r}:${i}:${c}`}var T,w,k=G(()=>{"use strict";l(xe,"formatDateTime");T=class{static{l(this,"Logger")}logFilePath=null;writeStream=null;consolaInstance;isDaemonMode;constructor(){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.consolaInstance=Pe({formatOptions:{date:!1,colors:!0,compact:!0},fancy:!1});let e=this.isDaemonMode;this.consolaInstance.setReporters([{log:l(o=>{let t={info:"INFO",success:"SUCCESS",warn:"WARN",error:"ERROR",debug:"DEBUG",log:"LOG"},r={info:M.blue,success:M.green,warn:M.yellow,error:M.red,debug:M.gray,log:l(h=>h,"log")},i=t[o.type]||o.type.toUpperCase(),c=r[o.type]||(h=>h),a=xe(new Date),f=c(`[${i}]`),d=`[${a}] ${f} ${o.args.join(" ")}`;if(!e)try{console.error(d)}catch(h){if(h instanceof Error&&h.message?.includes("EPIPE"))return;throw h}},"log")}])}initLogFile(e){this.logFilePath=we.join(e,"xiaozhi.log"),z.existsSync(this.logFilePath)||z.writeFileSync(this.logFilePath,""),this.writeStream=z.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"})}logToFile(e,o,...t){if(this.writeStream){let i=`[${new Date().toISOString()}] [${e.toUpperCase()}] ${o}`,c=t.length>0?`${i} ${t.map(a=>typeof a=="object"?JSON.stringify(a):String(a)).join(" ")}`:i;this.writeStream.write(`${c}
|
|
3
|
+
`)}}enableFileLogging(e){e&&!this.writeStream&&this.logFilePath?this.writeStream=z.createWriteStream(this.logFilePath,{flags:"a",encoding:"utf8"}):!e&&this.writeStream&&(this.writeStream.end(),this.writeStream=null)}info(e,...o){this.consolaInstance.info(e,...o),this.logToFile("info",e,...o)}success(e,...o){this.consolaInstance.success(e,...o),this.logToFile("success",e,...o)}warn(e,...o){this.consolaInstance.warn(e,...o),this.logToFile("warn",e,...o)}error(e,...o){this.consolaInstance.error(e,...o),this.logToFile("error",e,...o)}debug(e,...o){this.consolaInstance.debug(e,...o),this.logToFile("debug",e,...o)}log(e,...o){this.consolaInstance.log(e,...o),this.logToFile("log",e,...o)}withTag(e){return this}close(){this.writeStream&&(this.writeStream.end(),this.writeStream=null)}},w=new T});var re={};fe(re,{MCPServer:()=>D});import{spawn as je}from"child_process";import{EventEmitter as Oe}from"events";import j from"path";import{fileURLToPath as ne}from"url";import{randomUUID as ze}from"crypto";import A from"express";var ke,Ho,y,D,ie=G(()=>{"use strict";k();ke=ne(import.meta.url),Ho=j.dirname(ke),y=w.withTag("mcp-server"),D=class extends Oe{static{l(this,"MCPServer")}app;server=null;clients=new Map;mcpProxy=null;port;constructor(e=3e3){super(),this.port=e,this.app=A(),this.setupMiddleware(),this.setupRoutes()}setupMiddleware(){this.app.use(A.json()),this.app.use(A.urlencoded({extended:!0})),this.app.use((e,o,t)=>{o.header("Access-Control-Allow-Origin","*"),o.header("Access-Control-Allow-Methods","GET, POST, OPTIONS"),o.header("Access-Control-Allow-Headers","Content-Type, Accept"),o.header("Cache-Control","no-cache"),t()})}setupRoutes(){this.app.get("/sse",(e,o)=>{let t=Date.now().toString(),r=ze();o.setHeader("Content-Type","text/event-stream"),o.setHeader("Cache-Control","no-cache, no-transform"),o.setHeader("Connection","keep-alive"),o.setHeader("X-Accel-Buffering","no"),this.clients.set(r,{id:t,sessionId:r,response:o}),y.info(`MCP client connected: ${t} (session: ${r})`),o.write(`event: endpoint
|
|
4
|
+
data: /messages?sessionId=${r}
|
|
5
|
+
|
|
6
|
+
`),e.on("close",()=>{this.clients.delete(r),y.info(`MCP client disconnected: ${t} (session: ${r})`)})}),this.app.post("/messages",async(e,o)=>{try{let t=e.query.sessionId,r=e.body;if(y.info(`Received message via SSE transport (session: ${t}):`,JSON.stringify(r)),!t||!this.clients.has(t)){o.status(400).json({jsonrpc:"2.0",error:{code:-32600,message:"Invalid or missing sessionId"},id:r.id});return}if(!this.mcpProxy){o.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP proxy not running"},id:r.id});return}if(r.id===void 0)y.info(`Forwarding notification: ${r.method}`),this.mcpProxy.stdin.write(`${JSON.stringify(r)}
|
|
7
|
+
`),o.status(202).send();else{let i=await this.forwardToProxy(r),c=this.clients.get(t);c&&this.sendToClient(c,i),o.status(202).send()}}catch(t){y.error("SSE message error:",t),o.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:t instanceof Error?t.message:"Internal error"},id:e.body.id})}}),this.app.post("/rpc",async(e,o)=>{try{let t=e.body;if(y.debug("Received RPC message:",t),!this.mcpProxy){o.status(503).json({jsonrpc:"2.0",error:{code:-32603,message:"MCP proxy not running"},id:t.id});return}let r=await this.forwardToProxy(t);o.json(r)}catch(t){y.error("RPC error:",t),o.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:t instanceof Error?t.message:"Internal error"},id:e.body.id})}}),this.app.get("/health",(e,o)=>{o.json({status:"ok",mode:"mcp-server",proxy:this.mcpProxy?"running":"stopped",clients:this.clients.size})})}async forwardToProxy(e){return new Promise((o,t)=>{if(!this.mcpProxy||!this.mcpProxy.stdin||!this.mcpProxy.stdout){t(new Error("MCP proxy not available"));return}let r,i=l(c=>{try{let a=c.toString().split(`
|
|
8
|
+
`).filter(f=>f.trim());for(let f of a)try{let d=JSON.parse(f);if(y.debug(`Received response from proxy: ${f}`),d.id===e.id||e.method==="notifications/initialized"&&!d.id){clearTimeout(r),this.mcpProxy?.stdout?.removeListener("data",i),o(d);return}}catch{y.debug(`Non-JSON line from proxy: ${f}`)}}catch(a){clearTimeout(r),t(a)}},"messageHandler");this.mcpProxy.stdout.on("data",i),y.info(`Forwarding message to proxy: ${JSON.stringify(e)}`),this.mcpProxy.stdin.write(`${JSON.stringify(e)}
|
|
9
|
+
`),r=setTimeout(()=>{this.mcpProxy?.stdout?.removeListener("data",i),y.warn(`Request timeout for message id: ${e.id}, method: ${e.method} - This may be normal if the response was already sent via SSE`),o({jsonrpc:"2.0",id:e.id,result:{_timeout:!0,message:"Response may have been sent via SSE"}})},3e4)})}sendToClient(e,o){try{let t=`event: message
|
|
10
|
+
data: ${JSON.stringify(o)}
|
|
11
|
+
|
|
12
|
+
`;e.response.write(t)}catch(t){y.error(`Failed to send to client ${e.id}:`,t),this.clients.delete(e.sessionId)}}broadcastToClients(e){for(let o of this.clients.values())this.sendToClient(o,e)}async start(){try{await this.startMCPProxy(),this.server=this.app.listen(this.port,()=>{y.info(`MCP Server listening on port ${this.port}`),y.info(`SSE endpoint: http://localhost:${this.port}/sse`),y.info(`Messages endpoint: http://localhost:${this.port}/messages`),y.info(`RPC endpoint: http://localhost:${this.port}/rpc`)}),this.emit("started")}catch(e){throw y.error("Failed to start MCP server:",e),e}}async startMCPProxy(){let e=ne(import.meta.url),o=j.dirname(e),t=null;for(let r=0;r<5;r++){let i=j.join(o,"mcpServerProxy.js"),c=await import("fs");if(c.existsSync(i)){t=i;break}let a=j.join(o,"dist","mcpServerProxy.js");if(c.existsSync(a)){t=a;break}o=j.dirname(o)}if(!t)throw new Error("Could not find mcpServerProxy.js in the project structure");y.info(`Starting MCP proxy from: ${t}`),this.mcpProxy=je("node",[t],{stdio:["pipe","pipe","pipe"],env:{...process.env,MCP_SERVER_MODE:"true",XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}}),this.mcpProxy.on("error",r=>{y.error("MCP proxy error:",r)}),this.mcpProxy.on("exit",(r,i)=>{y.warn(`MCP proxy exited with code ${r}, signal ${i}`),this.mcpProxy=null}),this.mcpProxy.stderr&&this.mcpProxy.stderr.on("data",r=>{let i=r.toString().trim();i.includes("[ERROR]")||i.includes("Error:")||i.includes("Failed")?y.error("MCP proxy stderr:",i):y.info("MCP proxy output:",i)}),await new Promise((r,i)=>{let c=setTimeout(()=>{i(new Error("MCP proxy startup timeout"))},1e4),a=l(f=>{let d=f.toString();(d.includes("MCP proxy ready")||d.includes("started"))&&(clearTimeout(c),this.mcpProxy?.stdout?.removeListener("data",a),r())},"dataHandler");this.mcpProxy?.stdout?.on("data",a)}),y.info("MCP proxy started successfully")}async stop(){y.info("Stopping MCP server...");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.emit("stopped"),y.info("MCP server stopped")}}});import{spawn as H}from"child_process";import u from"fs";import Ne from"os";import m from"path";import{fileURLToPath as I}from"url";import s from"chalk";import{Command as Re}from"commander";import b from"ora";import ve from"omelette";import{copyFileSync as de,existsSync as X,readFileSync as me,writeFileSync as he}from"fs";import{dirname as ue,resolve as Z}from"path";import{fileURLToPath as ye}from"url";var Se=ue(ye(import.meta.url)),R={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},F=class n{static{l(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=Z(Se,"xiaozhi.config.default.json")}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return Z(e,"xiaozhi.config.json")}static getInstance(){return n.instance||(n.instance=new n),n.instance}configExists(){let e=this.getConfigFilePath();return X(e)}initConfig(){if(!X(this.defaultConfigPath))throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.default.json \u4E0D\u5B58\u5728");if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let e=this.getConfigFilePath();de(this.defaultConfigPath,e),this.config=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let e=this.getConfigFilePath(),o=me(e,"utf8"),t=JSON.parse(o);return this.validateConfig(t),t}catch(e){throw e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let o=e;if(!o.mcpEndpoint||typeof o.mcpEndpoint!="string")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(!o.mcpServers||typeof o.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[t,r]of Object.entries(o.mcpServers)){if(!r||typeof r!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t} \u65E0\u6548`);let i=r;if(i.type==="sse"){if(!i.url||typeof i.url!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.url \u65E0\u6548`)}else{if(!i.command||typeof i.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.command \u65E0\u6548`);if(!Array.isArray(i.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.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.${t}.env \u5FC5\u987B\u662F\u5BF9\u8C61`)}}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMcpEndpoint(){return this.getConfig().mcpEndpoint}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,o){return this.getServerToolsConfig(e)[o]?.enable!==!1}updateMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t={...this.getConfig(),mcpEndpoint:e};this.saveConfig(t)}updateMcpServer(e,o){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if("type"in o&&o.type==="sse"){if(!o.url||typeof o.url!="string")throw new Error("SSE \u670D\u52A1\u914D\u7F6E\u7684 url \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else{let i=o;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 t=this.getConfig(),r={...t,mcpServers:{...t.mcpServers,[e]:o}};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 o=this.getConfig();if(!o.mcpServers[e])throw new Error(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728`);let t={...o.mcpServers};delete t[e];let r={...o,mcpServers:t};this.saveConfig(r)}updateServerToolsConfig(e,o){let r={...this.getConfig()};r.mcpServerConfig||(r.mcpServerConfig={}),r.mcpServerConfig[e]={tools:o},this.saveConfig(r)}setToolEnabled(e,o,t,r){let c={...this.getConfig()};c.mcpServerConfig||(c.mcpServerConfig={}),c.mcpServerConfig[e]||(c.mcpServerConfig[e]={tools:{}}),c.mcpServerConfig[e].tools[o]={enable:t,...r&&{description:r}},this.saveConfig(c)}saveConfig(e){try{this.validateConfig(e);let o=this.getConfigFilePath(),t=JSON.stringify(e,null,2);he(o,t,"utf8"),this.config=e}catch(o){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}reloadConfig(){this.config=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let o=this.getConfig().connection||{};return{heartbeatInterval:o.heartbeatInterval??R.heartbeatInterval,heartbeatTimeout:o.heartbeatTimeout??R.heartbeatTimeout,reconnectInterval:o.reconnectInterval??R.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let o=this.getConfig(),r={...o.connection||{},...e},i={...o,connection:r};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 o=this.getConfig(),r={...o.modelscope||{},...e},i={...o,modelscope:r};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 o=this.getConfig(),r={...o.webUI||{},...e},i={...o,webUI:r};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})}},g=F.getInstance();function Ce(){try{if(!g.configExists())return[];let n=g.getMcpServers();return Object.keys(n)}catch{return[]}}l(Ce,"getMcpServerNames");function be(n){try{if(!g.configExists())return[];let e=g.getServerToolsConfig(n);return Object.keys(e)}catch{return[]}}l(be,"getServerToolNames");function B(){let n=ve("xiaozhi <command>");if(n.on("command",({reply:e})=>{e(["create","init","config","start","stop","status","attach","restart","mcp","completion"])}),n.on("complete",(e,{line:o,before:t,reply:r})=>{process.env.XIAOZHI_DEBUG_COMPLETION&&console.error(`Debug completion - line: "${o}", before: "${t}", fragment: "${e}"`);let i=o.trim().split(/\s+/),a=o!==o.trim()?i.length:i.length-1;if(i[1]==="mcp"){let f=i[2];if(a===2){let d=["list","server","tool"],h=i[2]||"",S=d.filter(v=>v.startsWith(h));r(S);return}if(a===3){switch(f){case"list":{let d=["--tools"],h=i[3]||"",S=d.filter(v=>v.startsWith(h));r(S);break}case"server":case"tool":{let d=Ce(),h=i[3]||"",S=d.filter(v=>v.startsWith(h));r(S);break}default:r([])}return}if(a===4&&f==="tool"){let d=i[3],h=be(d),S=i[4]||"",v=h.filter($=>$.startsWith(S));r(v);return}if(a===5&&f==="tool"){let d=["enable","disable"],h=i[5]||"",S=d.filter(v=>v.startsWith(h));r(S);return}}if(a===2){switch(i[1]){case"create":r(["--template","-t"]);break;case"start":case"restart":r(["--daemon","-d"]);break;case"completion":r(["install","uninstall"]);break;default:r([])}return}r([])}),process.argv.includes("--completion")){try{console.log(n.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(n.setupShellInitFile("fish")),process.exit(0)),process.argv.includes("--compzsh")||process.argv.includes("--compbash"),n.init()}l(B,"setupAutoCompletion");function V(){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")}l(V,"showCompletionHelp");k();import p from"chalk";import K from"cli-table3";import U from"ora";function Y(n){let e=0;for(let o of n)/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(o)?e+=2:e+=1;return e}l(Y,"getDisplayWidth");function Q(n,e){if(Y(n)<=e)return n;if(e<=3)return"";let o="",t=0,r=!1;for(let i of n){let c=/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(i)?2:1;if(t+c>e-3){if(!r)return"";o+="...";break}o+=i,t+=c,r=!0}return o}l(Q,"truncateToWidth");async function q(n={}){let e=U("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868...").start();try{let o=g.getMcpServers(),t=Object.keys(o);if(t.length===0){e.warn("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1"),console.log(p.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi config' \u547D\u4EE4\u914D\u7F6E MCP \u670D\u52A1"));return}if(e.succeed(`\u627E\u5230 ${t.length} \u4E2A MCP \u670D\u52A1`),n.tools){console.log(),console.log(p.bold("MCP \u670D\u52A1\u5DE5\u5177\u5217\u8868:")),console.log();let r=8,i=[];for(let a of t){let f=g.getServerToolsConfig(a),d=Object.keys(f);i.push(...d)}for(let a of i){let f=Y(a);f>r&&(r=f)}r=Math.max(10,Math.min(r+2,30));let c=new K({head:[p.bold("MCP"),p.bold("\u5DE5\u5177\u540D\u79F0"),p.bold("\u72B6\u6001"),p.bold("\u63CF\u8FF0")],colWidths:[15,r,8,40],wordWrap:!0,style:{head:[],border:[]}});for(let a of t){let f=g.getServerToolsConfig(a),d=Object.keys(f);if(d.length===0)c.push([p.gray(a),p.gray("(\u65E0\u5DE5\u5177)"),p.gray("-"),p.gray("\u8BF7\u5148\u542F\u52A8\u670D\u52A1\u626B\u63CF\u5DE5\u5177")]);else{c.length>0&&c.push([{colSpan:4,content:""}]);for(let h of d){let S=f[h],v=S.enable?p.green("\u542F\u7528"):p.red("\u7981\u7528"),$=Q(S.description||"",32);c.push([a,h,v,$])}}}console.log(c.toString())}else{console.log(),console.log(p.bold("MCP \u670D\u52A1\u5217\u8868:")),console.log();for(let r of t){let i=o[r],c=g.getServerToolsConfig(r),a=Object.keys(c).length,f=Object.values(c).filter(d=>d.enable!==!1).length;console.log(`${p.cyan("\u2022")} ${p.bold(r)}`),"type"in i&&i.type==="sse"?(console.log(` \u7C7B\u578B: ${p.gray("SSE")}`),console.log(` URL: ${p.gray(i.url)}`)):console.log(` \u547D\u4EE4: ${p.gray(i.command)} ${p.gray(i.args.join(" "))}`),a>0?console.log(` \u5DE5\u5177: ${p.green(f)} \u542F\u7528 / ${p.yellow(a)} \u603B\u8BA1`):console.log(` \u5DE5\u5177: ${p.gray("\u672A\u626B\u63CF (\u8BF7\u5148\u542F\u52A8\u670D\u52A1)")}`),console.log()}}console.log(p.gray("\u{1F4A1} \u63D0\u793A:")),console.log(p.gray(" - \u4F7F\u7528 'xiaozhi mcp list --tools' \u67E5\u770B\u6240\u6709\u5DE5\u5177")),console.log(p.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> list' \u67E5\u770B\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177")),console.log(p.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> <\u5DE5\u5177\u540D> enable/disable' \u542F\u7528/\u7981\u7528\u5DE5\u5177"))}catch(o){e.fail("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868\u5931\u8D25"),console.error(p.red(`\u9519\u8BEF: ${o instanceof Error?o.message:String(o)}`)),process.exit(1)}}l(q,"listMcpServers");async function ee(n){let e=U(`\u83B7\u53D6 ${n} \u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868...`).start();try{if(!g.getMcpServers()[n]){e.fail(`\u670D\u52A1 '${n}' \u4E0D\u5B58\u5728`),console.log(p.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let t=g.getServerToolsConfig(n),r=Object.keys(t);if(r.length===0){e.warn(`\u670D\u52A1 '${n}' \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 '${n}' \u5171\u6709 ${r.length} \u4E2A\u5DE5\u5177`),console.log(),console.log(p.bold(`${n} \u670D\u52A1\u5DE5\u5177\u5217\u8868:`)),console.log();let i=new K({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 r){let a=t[c],f=a.enable?p.green("\u542F\u7528"):p.red("\u7981\u7528"),d=Q(a.description||"",40);i.push([c,f,d])}console.log(i.toString()),console.log(),console.log(p.gray("\u{1F4A1} \u63D0\u793A:")),console.log(p.gray(` - \u4F7F\u7528 'xiaozhi mcp ${n} <\u5DE5\u5177\u540D> enable' \u542F\u7528\u5DE5\u5177`)),console.log(p.gray(` - \u4F7F\u7528 'xiaozhi mcp ${n} <\u5DE5\u5177\u540D> disable' \u7981\u7528\u5DE5\u5177`))}catch(o){e.fail("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25"),console.error(p.red(`\u9519\u8BEF: ${o instanceof Error?o.message:String(o)}`)),process.exit(1)}}l(ee,"listServerTools");async function oe(n,e,o){let t=o?"\u542F\u7528":"\u7981\u7528",r=U(`${t}\u5DE5\u5177 ${n}/${e}...`).start();try{if(!g.getMcpServers()[n]){r.fail(`\u670D\u52A1 '${n}' \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=g.getServerToolsConfig(n);if(!c[e]){r.fail(`\u5DE5\u5177 '${e}' \u5728\u670D\u52A1 '${n}' \u4E2D\u4E0D\u5B58\u5728`),console.log(p.yellow(`\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp ${n} list' \u67E5\u770B\u8BE5\u670D\u52A1\u7684\u6240\u6709\u5DE5\u5177`));return}g.setToolEnabled(n,e,o,c[e].description),r.succeed(`\u6210\u529F${t}\u5DE5\u5177 ${p.cyan(n)}/${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(i){r.fail(`${t}\u5DE5\u5177\u5931\u8D25`),console.error(p.red(`\u9519\u8BEF: ${i instanceof Error?i.message:String(i)}`)),process.exit(1)}}l(oe,"setToolEnabled");import{existsSync as W}from"fs";import{readFile as te}from"fs/promises";import{createServer as Ie}from"http";import{dirname as $e,join as x}from"path";import{parse as Me}from"url";import{fileURLToPath as Te}from"url";import{WebSocketServer as Ee}from"ws";k();var E=class{static{l(this,"WebServer")}httpServer;wss;logger;port;clientInfo={status:"disconnected",mcpEndpoint:"",activeMCPServers:[]};heartbeatTimeout;HEARTBEAT_TIMEOUT=35e3;constructor(e){if(e===void 0)try{this.port=g.getWebUIPort()}catch{this.port=9999}else this.port=e;this.logger=new T,this.httpServer=Ie((o,t)=>{this.handleHttpRequest(o,t)}),this.wss=new Ee({server:this.httpServer}),this.setupWebSocket()}async handleHttpRequest(e,o){let{pathname:t}=Me(e.url||"",!0);if(o.setHeader("Access-Control-Allow-Origin","*"),o.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, OPTIONS"),o.setHeader("Access-Control-Allow-Headers","Content-Type"),e.method==="OPTIONS"){o.writeHead(200),o.end();return}try{if(e.method==="GET"&&!t?.startsWith("/api/")){await this.serveStaticFile(t||"/",o);return}if(t==="/api/config"&&e.method==="GET"){let r=g.getConfig();o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify(r))}else if(t==="/api/config"&&e.method==="PUT"){let r="";e.on("data",i=>{r+=i.toString()}),e.on("end",async()=>{try{let i=JSON.parse(r);this.updateConfig(i),o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify({success:!0})),this.broadcastConfigUpdate(i)}catch(i){o.writeHead(400,{"Content-Type":"application/json"}),o.end(JSON.stringify({error:i instanceof Error?i.message:String(i)}))}})}else t==="/api/status"&&e.method==="GET"?(o.writeHead(200,{"Content-Type":"application/json"}),o.end(JSON.stringify(this.clientInfo))):(o.writeHead(404),o.end("Not Found"))}catch(r){this.logger.error("HTTP request error:",r),o.writeHead(500,{"Content-Type":"application/json"}),o.end(JSON.stringify({error:"Internal Server Error"}))}}async serveStaticFile(e,o){try{let t=$e(Te(import.meta.url)),i=[x(t,"..","web","dist"),x(t,"..","web"),x(process.cwd(),"web","dist"),x(process.cwd(),"web")].find(v=>W(v));if(!i){o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(`
|
|
4
13
|
<!DOCTYPE html>
|
|
5
14
|
<html>
|
|
6
15
|
<head>
|
|
@@ -20,12 +29,13 @@ var to=Object.defineProperty;var g=(n,o)=>to(n,"name",{value:o,configurable:!0})
|
|
|
20
29
|
</div>
|
|
21
30
|
</body>
|
|
22
31
|
</html>
|
|
23
|
-
`);return}let c=
|
|
24
|
-
\u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${
|
|
25
|
-
\u670D\u52A1\u5DF2\u505C\u6B62`))}),
|
|
26
|
-
\u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),a.kill("SIGTERM"),global.__webServer)try{await global.__webServer.stop(),console.log(s.green("Web UI \u5DF2\u505C\u6B62"))}catch{}}),process.on("SIGTERM",async()=>{if(a.kill("SIGTERM"),global.__webServer)try{await global.__webServer.stop()}catch{}})}}catch(t){
|
|
27
|
-
\u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),
|
|
28
|
-
\u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),
|
|
32
|
+
`);return}let c=e;if(c==="/"&&(c="/index.html"),c.includes("..")){o.writeHead(403),o.end("Forbidden");return}let a=x(i,c);if(!W(a)){let v=x(i,"index.html");if(W(v)){let $=await te(v);o.writeHead(200,{"Content-Type":"text/html"}),o.end($)}else o.writeHead(404),o.end("Not Found");return}let f=await te(a),d=a.split(".").pop()?.toLowerCase(),S={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"}[d||""]||"application/octet-stream";o.writeHead(200,{"Content-Type":S}),o.end(f)}catch(t){this.logger.error("Serve static file error:",t),o.writeHead(500),o.end("Internal Server Error")}}setupWebSocket(){this.wss.on("connection",e=>{this.logger.debug("WebSocket client connected"),e.on("message",async o=>{try{let t=JSON.parse(o.toString());await this.handleWebSocketMessage(e,t)}catch(t){this.logger.error("WebSocket message error:",t),e.send(JSON.stringify({type:"error",error:t instanceof Error?t.message:String(t)}))}}),e.on("close",()=>{this.logger.debug("WebSocket client disconnected")}),this.sendInitialData(e)})}async handleWebSocketMessage(e,o){switch(o.type){case"getConfig":{let t=g.getConfig();e.send(JSON.stringify({type:"config",data:t}));break}case"updateConfig":this.updateConfig(o.config),this.broadcastConfigUpdate(o.config);break;case"getStatus":e.send(JSON.stringify({type:"status",data:this.clientInfo}));break;case"clientStatus":this.updateClientInfo(o.data),this.broadcastStatusUpdate();break}}async sendInitialData(e){let o=g.getConfig();e.send(JSON.stringify({type:"config",data:o})),e.send(JSON.stringify({type:"status",data:this.clientInfo}))}broadcastConfigUpdate(e){let o=JSON.stringify({type:"configUpdate",data:e});for(let t of this.wss.clients)t.readyState===1&&t.send(o)}broadcastStatusUpdate(){let e=JSON.stringify({type:"statusUpdate",data:this.clientInfo});for(let o of this.wss.clients)o.readyState===1&&o.send(e)}updateClientInfo(e){this.clientInfo={...this.clientInfo,...e},e.lastHeartbeat&&(this.clientInfo.lastHeartbeat=Date.now()),e.status==="connected"&&this.resetHeartbeatTimeout()}resetHeartbeatTimeout(){this.heartbeatTimeout&&clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=setTimeout(()=>{this.logger.warn("\u5BA2\u6237\u7AEF\u5FC3\u8DF3\u8D85\u65F6\uFF0C\u6807\u8BB0\u4E3A\u65AD\u5F00\u8FDE\u63A5"),this.updateClientInfo({status:"disconnected"}),this.broadcastStatusUpdate()},this.HEARTBEAT_TIMEOUT)}updateConfig(e){e.mcpEndpoint!==g.getMcpEndpoint()&&g.updateMcpEndpoint(e.mcpEndpoint);let o=g.getMcpServers();for(let[t,r]of Object.entries(e.mcpServers))JSON.stringify(o[t])!==JSON.stringify(r)&&g.updateMcpServer(t,r);for(let t of Object.keys(o))t in e.mcpServers||g.removeMcpServer(t);if(e.connection&&g.updateConnectionConfig(e.connection),e.modelscope&&g.updateModelScopeConfig(e.modelscope),e.webUI&&g.updateWebUIConfig(e.webUI),e.mcpServerConfig)for(let[t,r]of Object.entries(e.mcpServerConfig))for(let[i,c]of Object.entries(r.tools))g.setToolEnabled(t,i,c.enable)}updateStatus(e){this.updateClientInfo(e),this.broadcastStatusUpdate()}start(){return new Promise((e,o)=>{this.httpServer.listen(this.port,()=>{this.logger.info(`Web server listening on http://localhost:${this.port}`),e()}).on("error",o)})}stop(){return new Promise(e=>{this.heartbeatTimeout&&(clearTimeout(this.heartbeatTimeout),this.heartbeatTimeout=void 0);for(let o of this.wss.clients)o.terminate();this.wss.close(()=>{this.httpServer.close(()=>{this.logger.info("Web server stopped"),e()}),setTimeout(()=>{this.logger.info("Web server force stopped"),e()},2e3)})})}};var C=new Re,Fe="xiaozhi-mcp-service";function ae(){try{let n=I(import.meta.url),e=m.dirname(n),o=[m.join(e,"..","package.json"),m.join(e,"..","package.json"),m.join(e,"..","..","package.json"),m.join(e,"package.json")];for(let t of o)if(u.existsSync(t)){let r=JSON.parse(u.readFileSync(t,"utf8"));if(r.version)return r.version}return"unknown"}catch(n){return console.warn("\u65E0\u6CD5\u4ECE package.json \u8BFB\u53D6\u7248\u672C\u4FE1\u606F:",n),"unknown"}}l(ae,"getVersion");var P=m.join(Ne.tmpdir(),`${Fe}.pid`);function N(){try{if(!u.existsSync(P))return{running:!1};let n=u.readFileSync(P,"utf8").trim(),[e,o,t]=n.split("|"),r=Number.parseInt(e);if(Number.isNaN(r))return u.unlinkSync(P),{running:!1};try{process.kill(r,0);let i=Number.parseInt(o),c=Ue(Date.now()-i);return{running:!0,pid:r,uptime:c,mode:t||"foreground"}}catch{return u.unlinkSync(P),{running:!1}}}catch{return{running:!1}}}l(N,"getServiceStatus");function Ue(n){let e=Math.floor(n/1e3),o=Math.floor(e/60),t=Math.floor(o/60),r=Math.floor(t/24);return r>0?`${r}\u5929 ${t%24}\u5C0F\u65F6 ${o%60}\u5206\u949F`:t>0?`${t}\u5C0F\u65F6 ${o%60}\u5206\u949F`:o>0?`${o}\u5206\u949F ${e%60}\u79D2`:`${e}\u79D2`}l(Ue,"formatUptime");function _(n,e){let o=`${n}|${Date.now()}|${e}`;u.writeFileSync(P,o)}l(_,"savePidInfo");function O(){try{u.existsSync(P)&&u.unlinkSync(P)}catch{}}l(O,"cleanupPidFile");function We(){if(!g.configExists())return console.error(s.red("\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728")),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E')),!1;try{let n=g.getMcpEndpoint();return!n||n.includes("<\u8BF7\u586B\u5199")?(console.error(s.red("\u274C \u9519\u8BEF: MCP \u7AEF\u70B9\u672A\u914D\u7F6E")),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9')),!1):!0}catch(n){return console.error(s.red(`\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u65E0\u6548 - ${n instanceof Error?n.message:String(n)}`)),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u91CD\u65B0\u521D\u59CB\u5316\u914D\u7F6E')),!1}}l(We,"checkEnvironment");function Ae(){let n=m.dirname(I(import.meta.url)),e;return n.includes("js-demo/dist")?e=n:e=[m.join(n,"..","js-demo","dist"),m.join(n,"..","..","js-demo","dist"),m.join(n,"..","..","..","js-demo","dist"),m.join(process.cwd(),"js-demo","dist"),m.join(process.cwd(),"dist")].find(t=>u.existsSync(m.join(t,"mcpPipe.js"))&&u.existsSync(m.join(t,"mcpServerProxy.js")))||n,{command:"node",args:["mcpPipe.js","mcpServerProxy.js"],cwd:e}}l(Ae,"getServiceCommand");async function se(){try{if(!g.configExists()){console.log(s.yellow("\u{1F4A1} \u63D0\u793A: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7 Web UI \u542F\u52A8"));return}let n=new E;await n.start();let e=g.getWebUIPort();console.log(s.green(`\u2705 Web UI \u5DF2\u542F\u52A8: http://localhost:${e}`));let{spawn:o}=await import("child_process"),t=`http://localhost:${e}`,r=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";try{o(r,[t],{detached:!0,stdio:"ignore"}).unref()}catch{}global.__webServer=n}catch(n){console.log(s.yellow(`\u26A0\uFE0F Web UI \u542F\u52A8\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`))}}l(se,"startWebUIInBackground");async function le(n=!1,e=!1){let o=b("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let t=N();if(t.running){o.fail(`\u670D\u52A1\u5DF2\u7ECF\u5728\u8FD0\u884C (PID: ${t.pid})`);return}if(o.text="\u68C0\u67E5\u73AF\u5883\u914D\u7F6E...",!We()){o.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}let{command:r,args:i,cwd:c}=Ae();if(o.text=`\u542F\u52A8\u670D\u52A1 (${n?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,n){let a=H(r,i,{cwd:c,detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true"}});_(a.pid,"daemon");let f=process.cwd();w.initLogFile(f),w.enableFileLogging(!0);let d=m.join(f,"xiaozhi.log"),h=u.createWriteStream(d,{flags:"a"});a.stdout?.pipe(h),a.stderr?.pipe(h),a.on("exit",(S,v)=>{S!==0&&S!==null&&w.error(`\u540E\u53F0\u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${S}, \u4FE1\u53F7: ${v})`),O()}),a.on("error",S=>{w.error(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u9519\u8BEF: ${S.message}`),O(),o.fail(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u5931\u8D25: ${S.message}`)}),a.unref(),o.succeed(`\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${a.pid})`),console.log(s.gray(`\u65E5\u5FD7\u6587\u4EF6: ${d}`)),console.log(s.gray("\u4F7F\u7528 'xiaozhi attach' \u53EF\u4EE5\u67E5\u770B\u5B9E\u65F6\u65E5\u5FD7")),e&&await se()}else{o.succeed("\u670D\u52A1\u542F\u52A8\u4E2D...");let a=H(r,i,{cwd:c,stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});_(a.pid,"foreground"),a.on("exit",(f,d)=>{O(),console.log(f!==0?s.red(`
|
|
33
|
+
\u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${f}, \u4FE1\u53F7: ${d})`):s.green(`
|
|
34
|
+
\u670D\u52A1\u5DF2\u505C\u6B62`))}),e&&setTimeout(()=>{se()},1e3),process.on("SIGINT",async()=>{if(console.log(s.yellow(`
|
|
35
|
+
\u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),a.kill("SIGTERM"),global.__webServer)try{await global.__webServer.stop(),console.log(s.green("Web UI \u5DF2\u505C\u6B62"))}catch{}}),process.on("SIGTERM",async()=>{if(a.kill("SIGTERM"),global.__webServer)try{await global.__webServer.stop()}catch{}})}}catch(t){o.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}l(le,"startService");async function ge(){let n=b("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=N();if(!e.running){n.warn("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}n.text=`\u505C\u6B62\u670D\u52A1 (PID: ${e.pid})...`;try{process.kill(e.pid,"SIGTERM");let o=0,t=30;for(;o<t;){await new Promise(r=>setTimeout(r,100));try{process.kill(e.pid,0),o++}catch{break}}try{process.kill(e.pid,0),n.text="\u5F3A\u5236\u505C\u6B62\u670D\u52A1...",process.kill(e.pid,"SIGKILL"),await new Promise(r=>setTimeout(r,500))}catch{}O(),n.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(o){O(),n.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}catch(e){n.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(ge,"stopService");async function De(){let n=b("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=N();if(e.running){if(n.succeed("\u670D\u52A1\u72B6\u6001"),console.log(s.green("\u2705 \u670D\u52A1\u6B63\u5728\u8FD0\u884C")),console.log(s.gray(` PID: ${e.pid}`)),console.log(s.gray(` \u8FD0\u884C\u65F6\u95F4: ${e.uptime}`)),console.log(s.gray(` \u8FD0\u884C\u6A21\u5F0F: ${e.mode==="daemon"?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"}`)),e.mode==="daemon"){let o=m.join(process.cwd(),"xiaozhi.log");console.log(s.gray(` \u65E5\u5FD7\u6587\u4EF6: ${o}`))}}else n.succeed("\u670D\u52A1\u72B6\u6001"),console.log(s.red("\u274C \u670D\u52A1\u672A\u8FD0\u884C"))}catch(e){n.fail(`\u68C0\u67E5\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(De,"checkStatus");async function He(){let n=b("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let e=N();if(!e.running){n.fail("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}if(e.mode!=="daemon"){n.fail("\u670D\u52A1\u4E0D\u662F\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C");return}n.succeed("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1..."),console.log(s.green(`\u5DF2\u8FDE\u63A5\u5230\u670D\u52A1 (PID: ${e.pid})`)),console.log(s.gray("\u6309 Ctrl+C \u53EF\u4EE5\u65AD\u5F00\u8FDE\u63A5\uFF08\u4E0D\u4F1A\u505C\u6B62\u670D\u52A1\uFF09")),console.log(s.gray("=".repeat(50)));let o=m.join(process.cwd(),"xiaozhi.log");if(u.existsSync(o))if(process.platform==="win32"){let{spawn:t}=await import("child_process"),r=t("powershell",["-Command",`Get-Content -Path "${o}" -Wait`],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(s.yellow(`
|
|
36
|
+
\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:t}=await import("child_process"),r=t("tail",["-f",o],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(s.yellow(`
|
|
37
|
+
\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(s.yellow("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728"))}catch(e){n.fail(`\u8FDE\u63A5\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(He,"attachService");async function _e(n=!1,e=!1){console.log(s.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await ge(),await new Promise(o=>setTimeout(o,1e3)),await le(n,e)}l(_e,"restartService");async function Le(n,e=!1){let o=b("\u542F\u52A8 MCP Server \u6A21\u5F0F...").start();try{if(!g.configExists()){o.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}let{MCPServer:t}=await Promise.resolve().then(()=>(ie(),re));if(e){let r=I(import.meta.url),i=m.dirname(r),c=H("node",[m.join(i,"cli.js"),"start","--server",n.toString()],{detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true",MCP_SERVER_MODE:"true"}});_(c.pid,"daemon");let a=m.join(process.cwd(),"xiaozhi-mcp-server.log"),f=u.createWriteStream(a,{flags:"a"});c.stdout?.pipe(f),c.stderr?.pipe(f),c.unref(),o.succeed(`MCP Server \u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${c.pid}, Port: ${n})`),console.log(s.gray(`\u65E5\u5FD7\u6587\u4EF6: ${a}`))}else{let r=new t(n),i=l(async()=>{console.log(s.yellow(`
|
|
38
|
+
\u6B63\u5728\u505C\u6B62 MCP Server...`)),await r.stop(),process.exit(0)},"cleanup");process.on("SIGINT",i),process.on("SIGTERM",i),await r.start(),o.succeed("MCP Server \u5DF2\u542F\u52A8"),console.log(s.green(`\u2705 SSE endpoint: http://localhost:${n}/sse`)),console.log(s.green(`\u2705 Messages endpoint: http://localhost:${n}/messages`)),console.log(s.green(`\u2705 RPC endpoint: http://localhost:${n}/rpc`)),console.log(s.yellow("\u{1F4A1} \u63D0\u793A: \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1"))}}catch(t){o.fail(`\u542F\u52A8 MCP Server \u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}l(Le,"startMCPServerMode");function Je(){let n=ae();console.log(s.blue(`xiaozhi v${n}`)),console.log(s.gray("MCP Calculator Service CLI Tool")),console.log(s.gray("Built with Node.js and TypeScript")),console.log(s.gray(`Node.js: ${process.version}`)),console.log(s.gray(`Platform: ${process.platform} ${process.arch}`))}l(Je,"showDetailedInfo");async function Ge(){let n=b("\u521D\u59CB\u5316\u914D\u7F6E...").start();try{if(g.configExists()){n.warn("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728"),console.log(s.yellow("\u5982\u9700\u91CD\u65B0\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u5220\u9664\u73B0\u6709\u7684 xiaozhi.config.json \u6587\u4EF6"));return}g.initConfig(),n.succeed("\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u6210\u529F"),console.log(s.green("\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u521B\u5EFA: xiaozhi.config.json")),console.log(s.yellow("\u{1F4DD} \u8BF7\u7F16\u8F91\u914D\u7F6E\u6587\u4EF6\u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9:")),console.log(s.gray(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${g.getConfigPath()}`)),console.log(s.yellow("\u{1F4A1} \u6216\u8005\u4F7F\u7528\u547D\u4EE4\u8BBE\u7F6E:")),console.log(s.gray(" xiaozhi config mcpEndpoint <your-endpoint-url>"))}catch(e){n.fail(`\u521D\u59CB\u5316\u914D\u7F6E\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(Ge,"initConfig");function Xe(){let n=m.dirname(I(import.meta.url)),o=[m.join(n,"..","templates"),m.join(n,"templates"),m.join(n,"..","..","templates")].find(t=>u.existsSync(t));return o?u.readdirSync(o).filter(t=>{let r=m.join(o,t);return u.statSync(r).isDirectory()}):[]}l(Xe,"getAvailableTemplates");function ce(n,e){let o=n.length,t=e.length,r=Array(o+1).fill(null).map(()=>Array(t+1).fill(0));for(let c=0;c<=o;c++)r[c][0]=c;for(let c=0;c<=t;c++)r[0][c]=c;for(let c=1;c<=o;c++)for(let a=1;a<=t;a++)n[c-1]===e[a-1]?r[c][a]=r[c-1][a-1]:r[c][a]=Math.min(r[c-1][a]+1,r[c][a-1]+1,r[c-1][a-1]+1);let i=Math.max(o,t);return i===0?1:(i-r[o][t])/i}l(ce,"calculateSimilarity");function Ze(n,e){if(e.length===0)return null;let o=e[0],t=ce(n.toLowerCase(),o.toLowerCase());for(let r of e.slice(1)){let i=ce(n.toLowerCase(),r.toLowerCase());i>t&&(t=i,o=r)}return t>.5?o:null}l(Ze,"findSimilarTemplate");async function Be(n){if(!process.stdin.isTTY)return console.log("n (\u975E\u4EA4\u4E92\u5F0F\u73AF\u5883)"),!1;let e=await import("readline");return new Promise(o=>{process.stdout.write(n);let t=e.createInterface({input:process.stdin,output:process.stdout}),r=l(i=>{let c=i.trim().toLowerCase();c==="y"||c==="yes"?(t.close(),o(!0)):c==="n"||c==="no"||c===""?(t.close(),o(!1)):process.stdout.write("\u8BF7\u8F93\u5165 y \u6216 n: ")},"handleInput");t.on("line",r),t.on("SIGINT",()=>{t.close(),o(!1)})})}l(Be,"askUserConfirmation");function Ve(n){let e={mcpEndpoint:"<\u8BF7\u586B\u5199\u4F60\u7684\u63A5\u5165\u70B9\u5730\u5740\uFF08\u83B7\u53D6\u5730\u5740\u5728 xiaozhi.me\uFF09>",mcpServers:{}},o=m.join(n,"xiaozhi.config.json");u.writeFileSync(o,JSON.stringify(e,null,2),"utf8")}l(Ve,"createBasicConfig");async function Ke(n,e){let o=b("\u521D\u59CB\u5316\u9879\u76EE...").start();try{let t=m.join(process.cwd(),n);if(u.existsSync(t)){o.fail(`\u76EE\u5F55 "${n}" \u5DF2\u5B58\u5728`),console.log(s.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u9009\u62E9\u4E0D\u540C\u7684\u9879\u76EE\u540D\u79F0\u6216\u5220\u9664\u73B0\u6709\u76EE\u5F55"));return}if(e.template){o.text="\u68C0\u67E5\u6A21\u677F...";let r=Xe();if(r.length===0){o.fail("\u627E\u4E0D\u5230 templates \u76EE\u5F55"),console.log(s.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u786E\u4FDD xiaozhi-client \u6B63\u786E\u5B89\u88C5"));return}if(!r.includes(e.template)){o.fail(`\u6A21\u677F "${e.template}" \u4E0D\u5B58\u5728`);let h=Ze(e.template,r);if(h)if(console.log(s.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${h}" \u5417\uFF1F`)),await Be(s.cyan("\u786E\u8BA4\u4F7F\u7528\u6B64\u6A21\u677F\uFF1F(y/n): ")))e.template=h;else{console.log(s.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let v of r)console.log(s.gray(` - ${v}`));return}else{console.log(s.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let S of r)console.log(s.gray(` - ${S}`));return}}let i=m.dirname(I(import.meta.url)),a=[m.join(i,"..","templates"),m.join(i,"templates"),m.join(i,"..","..","templates")].find(h=>u.existsSync(h)),f=m.join(a,e.template);o.text=`\u4ECE\u6A21\u677F "${e.template}" \u521B\u5EFA\u9879\u76EE "${n}"...`,pe(f,t,["node_modules",".pnpm-debug.log","pnpm-lock.yaml"]);let d=m.join(t,"xiaozhi.log");u.existsSync(d)||u.writeFileSync(d,"","utf8"),o.succeed(`\u9879\u76EE "${n}" \u521B\u5EFA\u6210\u529F`),console.log(s.green("\u2705 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(s.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(s.gray(` cd ${n}`)),console.log(s.gray(" pnpm install # \u5B89\u88C5\u4F9D\u8D56")),console.log(s.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9")),console.log(s.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1"))}else{o.text=`\u521B\u5EFA\u57FA\u672C\u9879\u76EE "${n}"...`,u.mkdirSync(t,{recursive:!0}),Ve(t);let r=m.join(t,"xiaozhi.log");u.writeFileSync(r,"","utf8"),o.succeed(`\u9879\u76EE "${n}" \u521B\u5EFA\u6210\u529F`),console.log(s.green("\u2705 \u57FA\u672C\u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(s.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(s.gray(` cd ${n}`)),console.log(s.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9\u548C\u670D\u52A1")),console.log(s.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1")),console.log(s.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 --template \u9009\u9879\u53EF\u4EE5\u4ECE\u6A21\u677F\u521B\u5EFA\u9879\u76EE"))}}catch(t){o.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}l(Ke,"createProject");function pe(n,e,o=[]){u.existsSync(e)||u.mkdirSync(e,{recursive:!0});let t=u.readdirSync(n);for(let r of t){if(o.some(f=>r.includes(f)))continue;let i=m.join(n,r),c=m.join(e,r);u.statSync(i).isDirectory()?pe(i,c,o):u.copyFileSync(i,c)}}l(pe,"copyDirectory");async function Ye(){let n=b("\u542F\u52A8 UI \u670D\u52A1...").start();try{if(!g.configExists()){n.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}let e=new E;await e.start(),n.succeed("UI \u670D\u52A1\u5DF2\u542F\u52A8");let o=g.getWebUIPort();console.log(s.green(`\u2705 \u914D\u7F6E\u7BA1\u7406\u7F51\u9875\u5DF2\u542F\u52A8: http://localhost:${o}`)),console.log(s.yellow("\u{1F4A1} \u63D0\u793A: \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1"));let{spawn:t}=await import("child_process"),r=`http://localhost:${o}`,i=process.platform==="darwin"?"open":process.platform==="win32"?"start":"xdg-open";try{t(i,[r],{detached:!0,stdio:"ignore"}).unref()}catch{}let c=!1;process.on("SIGINT",async()=>{c&&(console.log(s.red(`
|
|
29
39
|
\u5F3A\u5236\u9000\u51FA...`)),process.exit(1)),c=!0,console.log(s.yellow(`
|
|
30
|
-
\u6B63\u5728\u505C\u6B62 UI \u670D\u52A1...`));try{await o.stop(),console.log(s.green("UI \u670D\u52A1\u5DF2\u505C\u6B62"))}catch{console.log(s.red("\u505C\u6B62\u670D\u52A1\u65F6\u51FA\u9519\uFF0C\u5F3A\u5236\u9000\u51FA"))}process.exit(0)}),process.on("SIGTERM",async()=>{c=!0,await o.stop(),process.exit(0)})}catch(o){n.fail(`\u542F\u52A8 UI \u670D\u52A1\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(No,"startUIService");async function Ro(n,o){let e=C("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!l.configExists()){e.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}if(o)switch(n){case"mcpEndpoint":l.updateMcpEndpoint(o),e.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${o}`);break;case"heartbeatInterval":{let t=Number.parseInt(o,10);if(Number.isNaN(t)||t<=0){e.fail("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}l.setHeartbeatInterval(t),e.succeed(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}case"heartbeatTimeout":{let t=Number.parseInt(o,10);if(Number.isNaN(t)||t<=0){e.fail("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}l.setHeartbeatTimeout(t),e.succeed(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}case"reconnectInterval":{let t=Number.parseInt(o,10);if(Number.isNaN(t)||t<=0){e.fail("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}l.setReconnectInterval(t),e.succeed(`\u91CD\u8FDE\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}default:e.fail(`\u914D\u7F6E\u9879 ${n} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(s.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}else{e.text="\u8BFB\u53D6\u914D\u7F6E...";let t=l.getConfig();switch(n){case"mcpEndpoint":e.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`MCP \u7AEF\u70B9: ${t.mcpEndpoint}`));break;case"mcpServers":e.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green("MCP \u670D\u52A1:"));for(let[i,r]of Object.entries(t.mcpServers))"type"in r&&r.type==="sse"?console.log(s.gray(` ${i}: [SSE] ${r.url}`)):console.log(s.gray(` ${i}: ${r.command} ${r.args.join(" ")}`));break;case"connection":{e.succeed("\u914D\u7F6E\u4FE1\u606F");let i=l.getConnectionConfig();console.log(s.green("\u8FDE\u63A5\u914D\u7F6E:")),console.log(s.gray(` \u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${i.heartbeatInterval}ms`)),console.log(s.gray(` \u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${i.heartbeatTimeout}ms`)),console.log(s.gray(` \u91CD\u8FDE\u95F4\u9694: ${i.reconnectInterval}ms`));break}case"heartbeatInterval":e.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${l.getHeartbeatInterval()}ms`));break;case"heartbeatTimeout":e.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${l.getHeartbeatTimeout()}ms`));break;case"reconnectInterval":e.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`\u91CD\u8FDE\u95F4\u9694: ${l.getReconnectInterval()}ms`));break;default:e.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${n}`),console.log(s.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers, connection, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}}}catch(t){e.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(Ro,"configCommand");function Do(){console.log(s.blue.bold("xiaozhi - MCP Calculator Service CLI")),console.log(),console.log(s.yellow("\u4F7F\u7528\u65B9\u6CD5:")),console.log(" xiaozhi <command> [options]"),console.log(),console.log(s.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] \u542F\u52A8\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C, --ui \u540C\u65F6\u542F\u52A8 Web UI)"),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(s.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(s.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(s.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(s.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 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(s.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(s.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(Do,"showHelp");S.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(Q(),"-v, --version","\u663E\u793A\u7248\u672C\u4FE1\u606F").helpOption("-h, --help","\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");S.command("create <projectName>").description("\u521B\u5EFA\u9879\u76EE").option("-t, --template <templateName>","\u4F7F\u7528\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u9879\u76EE").action(async(n,o)=>{await Fo(n,o)});S.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").action(async()=>{await zo()});S.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(n,o)=>{await Ro(n,o)});S.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").action(async n=>{await q(n.daemon,n.ui)});S.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await oo()});S.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await To()});S.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await Eo()});S.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 n=>{await Mo(n.daemon,n.ui)});var F=S.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");F.command("list").description("\u5217\u51FA MCP \u670D\u52A1").option("--tools","\u663E\u793A\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868").action(async n=>{await J(n)});F.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async n=>{await G(n)});F.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(n,o,e)=>{e!=="enable"&&e!=="disable"&&(console.error(s.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await B(n,o,e==="enable")});S.command("ui").description("\u542F\u52A8\u914D\u7F6E\u7BA1\u7406\u7F51\u9875").action(async()=>{await No()});S.command("completion").description("\u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E").action(async()=>{A()});S.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(n=>{n.V&&(jo(),process.exit(0))});D();process.argv.length<=2&&(Do(),process.exit(0));S.parse(process.argv);export{Y as calculateSimilarity,Po as checkEnvironment,xo as formatUptime,z as getServiceStatus,Q as getVersion};
|
|
40
|
+
\u6B63\u5728\u505C\u6B62 UI \u670D\u52A1...`));try{await e.stop(),console.log(s.green("UI \u670D\u52A1\u5DF2\u505C\u6B62"))}catch{console.log(s.red("\u505C\u6B62\u670D\u52A1\u65F6\u51FA\u9519\uFF0C\u5F3A\u5236\u9000\u51FA"))}process.exit(0)}),process.on("SIGTERM",async()=>{c=!0,await e.stop(),process.exit(0)})}catch(e){n.fail(`\u542F\u52A8 UI \u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(Ye,"startUIService");async function Qe(n,e){let o=b("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!g.configExists()){o.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}if(e)switch(n){case"mcpEndpoint":g.updateMcpEndpoint(e),o.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${e}`);break;case"heartbeatInterval":{let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0){o.fail("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}g.setHeartbeatInterval(t),o.succeed(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}case"heartbeatTimeout":{let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0){o.fail("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}g.setHeartbeatTimeout(t),o.succeed(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}case"reconnectInterval":{let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<=0){o.fail("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6570\u5B57\uFF08\u6BEB\u79D2\uFF09");return}g.setReconnectInterval(t),o.succeed(`\u91CD\u8FDE\u95F4\u9694\u5DF2\u66F4\u65B0\u4E3A: ${t}ms`);break}default:o.fail(`\u914D\u7F6E\u9879 ${n} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(s.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}else{o.text="\u8BFB\u53D6\u914D\u7F6E...";let t=g.getConfig();switch(n){case"mcpEndpoint":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`MCP \u7AEF\u70B9: ${t.mcpEndpoint}`));break;case"mcpServers":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green("MCP \u670D\u52A1:"));for(let[r,i]of Object.entries(t.mcpServers))"type"in i&&i.type==="sse"?console.log(s.gray(` ${r}: [SSE] ${i.url}`)):console.log(s.gray(` ${r}: ${i.command} ${i.args.join(" ")}`));break;case"connection":{o.succeed("\u914D\u7F6E\u4FE1\u606F");let r=g.getConnectionConfig();console.log(s.green("\u8FDE\u63A5\u914D\u7F6E:")),console.log(s.gray(` \u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${r.heartbeatInterval}ms`)),console.log(s.gray(` \u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${r.heartbeatTimeout}ms`)),console.log(s.gray(` \u91CD\u8FDE\u95F4\u9694: ${r.reconnectInterval}ms`));break}case"heartbeatInterval":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${g.getHeartbeatInterval()}ms`));break;case"heartbeatTimeout":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${g.getHeartbeatTimeout()}ms`));break;case"reconnectInterval":o.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`\u91CD\u8FDE\u95F4\u9694: ${g.getReconnectInterval()}ms`));break;default:o.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${n}`),console.log(s.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers, connection, heartbeatInterval, heartbeatTimeout, reconnectInterval"));return}}}catch(t){o.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}l(Qe,"configCommand");function qe(){console.log(s.blue.bold("xiaozhi - MCP Calculator Service CLI")),console.log(),console.log(s.yellow("\u4F7F\u7528\u65B9\u6CD5:")),console.log(" xiaozhi <command> [options]"),console.log(),console.log(s.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(s.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(s.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(s.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(s.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(s.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(s.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")}l(qe,"showHelp");C.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(ae(),"-v, --version","\u663E\u793A\u7248\u672C\u4FE1\u606F").helpOption("-h, --help","\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");C.command("create <projectName>").description("\u521B\u5EFA\u9879\u76EE").option("-t, --template <templateName>","\u4F7F\u7528\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u9879\u76EE").action(async(n,e)=>{await Ke(n,e)});C.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").action(async()=>{await Ge()});C.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(n,e)=>{await Qe(n,e)});C.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 n=>{if(n.stdio){let{spawn:e}=await import("child_process"),o=I(import.meta.url),t=m.dirname(o),r=m.join(t,"mcpServerProxy.js");e("node",[r],{stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.env.XIAOZHI_CONFIG_DIR||process.cwd()}})}else if(n.server){let e=typeof n.server=="string"?Number.parseInt(n.server):3e3;await Le(e,n.daemon)}else await le(n.daemon,n.ui)});C.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await ge()});C.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await De()});C.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await He()});C.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 n=>{await _e(n.daemon,n.ui)});var L=C.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");L.command("list").description("\u5217\u51FA MCP \u670D\u52A1").option("--tools","\u663E\u793A\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868").action(async n=>{await q(n)});L.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async n=>{await ee(n)});L.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(n,e,o)=>{o!=="enable"&&o!=="disable"&&(console.error(s.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await oe(n,e,o==="enable")});C.command("ui").description("\u542F\u52A8\u914D\u7F6E\u7BA1\u7406\u7F51\u9875").action(async()=>{await Ye()});C.command("completion").description("\u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E").action(async()=>{V()});C.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(n=>{n.V&&(Je(),process.exit(0))});B();process.argv.length<=2&&(qe(),process.exit(0));C.parse(process.argv);export{ce as calculateSimilarity,We as checkEnvironment,Ue as formatUptime,N as getServiceStatus,ae as getVersion};
|
|
31
41
|
//# sourceMappingURL=cli.js.map
|