xiaozhi-client 1.0.6 → 1.0.7-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/dist/cli.js CHANGED
@@ -1,8 +1,12 @@
1
1
  #!/usr/bin/env node
2
- var X=Object.defineProperty;var g=(e,o)=>X(e,"name",{value:o,configurable:!0});import{spawn as G}from"child_process";import p from"fs";import J from"os";import f from"path";import{fileURLToPath as x}from"url";import s from"chalk";import{Command as so}from"commander";import v from"ora";import no from"omelette";import{copyFileSync as K,existsSync as T,readFileSync as Y,writeFileSync as q}from"fs";import{dirname as Q,resolve as I}from"path";import{fileURLToPath as oo}from"url";var eo=Q(oo(import.meta.url)),E=class e{static{g(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=I(eo,"xiaozhi.config.default.json")}getConfigFilePath(){let o=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return I(o,"xiaozhi.config.json")}static getInstance(){return e.instance||(e.instance=new e),e.instance}configExists(){let o=this.getConfigFilePath();return T(o)}initConfig(){if(!T(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();K(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(),n=Y(o,"utf8"),t=JSON.parse(n);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 n=o;if(!n.mcpEndpoint||typeof n.mcpEndpoint!="string")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(!n.mcpServers||typeof n.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(n.mcpServers)){if(!i||typeof i!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t} \u65E0\u6548`);let c=i;if(!c.command||typeof c.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.command \u65E0\u6548`);if(!Array.isArray(c.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.args \u5FC5\u987B\u662F\u6570\u7EC4`);if(c.env&&typeof c.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,n){return this.getServerToolsConfig(o)[n]?.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,n){if(!o||typeof o!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!n.command||typeof n.command!="string")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 command \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!Array.isArray(n.args))throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4");if(n.env&&typeof n.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]:n}};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 n=this.getConfig();if(!n.mcpServers[o])throw new Error(`\u670D\u52A1 ${o} \u4E0D\u5B58\u5728`);let t={...n.mcpServers};delete t[o];let i={...n,mcpServers:t};this.saveConfig(i)}updateServerToolsConfig(o,n){let i={...this.getConfig()};i.mcpServerConfig||(i.mcpServerConfig={}),i.mcpServerConfig[o]={tools:n},this.saveConfig(i)}setToolEnabled(o,n,t,i){let r={...this.getConfig()};r.mcpServerConfig||(r.mcpServerConfig={}),r.mcpServerConfig[o]||(r.mcpServerConfig[o]={tools:{}}),r.mcpServerConfig[o].tools[n]={enable:t,...i&&{description:i}},this.saveConfig(r)}saveConfig(o){try{this.validateConfig(o);let n=this.getConfigFilePath(),t=JSON.stringify(o,null,2);q(n,t,"utf8"),this.config=o}catch(n){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}reloadConfig(){this.config=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}},d=E.getInstance();function to(){try{if(!d.configExists())return[];let e=d.getMcpServers();return Object.keys(e)}catch{return[]}}g(to,"getMcpServerNames");function io(e){try{if(!d.configExists())return[];let o=d.getServerToolsConfig(e);return Object.keys(o)}catch{return[]}}g(io,"getServerToolNames");function k(){let e=no("xiaozhi <command>");if(e.on("command",({reply:o})=>{o(["create","init","config","start","stop","status","attach","restart","mcp","completion"])}),e.on("complete",(o,{line:n,before:t,reply:i})=>{process.env.XIAOZHI_DEBUG_COMPLETION&&console.error(`Debug completion - line: "${n}", before: "${t}", fragment: "${o}"`);let c=n.trim().split(/\s+/),a=n!==n.trim()?c.length:c.length-1;if(c[1]==="mcp"){let u=c[2];if(a===2){let m=["list","server","tool"],h=c[2]||"",y=m.filter(w=>w.startsWith(h));i(y);return}if(a===3){switch(u){case"list":{let m=["--tools"],h=c[3]||"",y=m.filter(w=>w.startsWith(h));i(y);break}case"server":case"tool":{let m=to(),h=c[3]||"",y=m.filter(w=>w.startsWith(h));i(y);break}default:i([])}return}if(a===4&&u==="tool"){let m=c[3],h=io(m),y=c[4]||"",w=h.filter($=>$.startsWith(y));i(w);return}if(a===5&&u==="tool"){let m=["enable","disable"],h=c[5]||"",y=m.filter(w=>w.startsWith(h));i(y);return}}if(a===2){switch(c[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(e.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(e.setupShellInitFile("fish")),process.exit(0)),process.argv.includes("--compzsh")||process.argv.includes("--compbash"),e.init()}g(k,"setupAutoCompletion");function D(){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(D,"showCompletionHelp");import l from"chalk";import O from"cli-table3";import M from"ora";function R(e){let o=0;for(let n of e)/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(n)?o+=2:o+=1;return o}g(R,"getDisplayWidth");function F(e,o){if(R(e)<=o)return e;if(o<=3)return"";let n="",t=0,i=!1;for(let c of e){let r=/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(c)?2:1;if(t+r>o-3){if(!i)return"";n+="...";break}n+=c,t+=r,i=!0}return n}g(F,"truncateToWidth");async function A(e={}){let o=M("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868...").start();try{let n=d.getMcpServers(),t=Object.keys(n);if(t.length===0){o.warn("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1"),console.log(l.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi config' \u547D\u4EE4\u914D\u7F6E MCP \u670D\u52A1"));return}if(o.succeed(`\u627E\u5230 ${t.length} \u4E2A MCP \u670D\u52A1`),e.tools){console.log(),console.log(l.bold("MCP \u670D\u52A1\u5DE5\u5177\u5217\u8868:")),console.log();let i=8,c=[];for(let a of t){let u=d.getServerToolsConfig(a),m=Object.keys(u);c.push(...m)}for(let a of c){let u=R(a);u>i&&(i=u)}i=Math.max(10,Math.min(i+2,30));let r=new O({head:[l.bold("MCP"),l.bold("\u5DE5\u5177\u540D\u79F0"),l.bold("\u72B6\u6001"),l.bold("\u63CF\u8FF0")],colWidths:[15,i,8,40],wordWrap:!0,style:{head:[],border:[]}});for(let a of t){let u=d.getServerToolsConfig(a),m=Object.keys(u);if(m.length===0)r.push([l.gray(a),l.gray("(\u65E0\u5DE5\u5177)"),l.gray("-"),l.gray("\u8BF7\u5148\u542F\u52A8\u670D\u52A1\u626B\u63CF\u5DE5\u5177")]);else{r.length>0&&r.push([{colSpan:4,content:""}]);for(let h of m){let y=u[h],w=y.enable?l.green("\u542F\u7528"):l.red("\u7981\u7528"),$=F(y.description||"",32);r.push([a,h,w,$])}}}console.log(r.toString())}else{console.log(),console.log(l.bold("MCP \u670D\u52A1\u5217\u8868:")),console.log();for(let i of t){let c=n[i],r=d.getServerToolsConfig(i),a=Object.keys(r).length,u=Object.values(r).filter(m=>m.enable!==!1).length;console.log(`${l.cyan("\u2022")} ${l.bold(i)}`),console.log(` \u547D\u4EE4: ${l.gray(c.command)} ${l.gray(c.args.join(" "))}`),a>0?console.log(` \u5DE5\u5177: ${l.green(u)} \u542F\u7528 / ${l.yellow(a)} \u603B\u8BA1`):console.log(` \u5DE5\u5177: ${l.gray("\u672A\u626B\u63CF (\u8BF7\u5148\u542F\u52A8\u670D\u52A1)")}`),console.log()}}console.log(l.gray("\u{1F4A1} \u63D0\u793A:")),console.log(l.gray(" - \u4F7F\u7528 'xiaozhi mcp list --tools' \u67E5\u770B\u6240\u6709\u5DE5\u5177")),console.log(l.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> list' \u67E5\u770B\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177")),console.log(l.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> <\u5DE5\u5177\u540D> enable/disable' \u542F\u7528/\u7981\u7528\u5DE5\u5177"))}catch(n){o.fail("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868\u5931\u8D25"),console.error(l.red(`\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`)),process.exit(1)}}g(A,"listMcpServers");async function L(e){let o=M(`\u83B7\u53D6 ${e} \u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868...`).start();try{if(!d.getMcpServers()[e]){o.fail(`\u670D\u52A1 '${e}' \u4E0D\u5B58\u5728`),console.log(l.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let t=d.getServerToolsConfig(e),i=Object.keys(t);if(i.length===0){o.warn(`\u670D\u52A1 '${e}' \u6682\u65E0\u5DE5\u5177\u4FE1\u606F`),console.log(l.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u542F\u52A8\u670D\u52A1\u4EE5\u626B\u63CF\u5DE5\u5177\u5217\u8868"));return}o.succeed(`\u670D\u52A1 '${e}' \u5171\u6709 ${i.length} \u4E2A\u5DE5\u5177`),console.log(),console.log(l.bold(`${e} \u670D\u52A1\u5DE5\u5177\u5217\u8868:`)),console.log();let c=new O({head:[l.bold("\u5DE5\u5177\u540D\u79F0"),l.bold("\u72B6\u6001"),l.bold("\u63CF\u8FF0")],colWidths:[30,8,50],wordWrap:!0,style:{head:[],border:[]}});for(let r of i){let a=t[r],u=a.enable?l.green("\u542F\u7528"):l.red("\u7981\u7528"),m=F(a.description||"",40);c.push([r,u,m])}console.log(c.toString()),console.log(),console.log(l.gray("\u{1F4A1} \u63D0\u793A:")),console.log(l.gray(` - \u4F7F\u7528 'xiaozhi mcp ${e} <\u5DE5\u5177\u540D> enable' \u542F\u7528\u5DE5\u5177`)),console.log(l.gray(` - \u4F7F\u7528 'xiaozhi mcp ${e} <\u5DE5\u5177\u540D> disable' \u7981\u7528\u5DE5\u5177`))}catch(n){o.fail("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25"),console.error(l.red(`\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`)),process.exit(1)}}g(L,"listServerTools");async function W(e,o,n){let t=n?"\u542F\u7528":"\u7981\u7528",i=M(`${t}\u5DE5\u5177 ${e}/${o}...`).start();try{if(!d.getMcpServers()[e]){i.fail(`\u670D\u52A1 '${e}' \u4E0D\u5B58\u5728`),console.log(l.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let r=d.getServerToolsConfig(e);if(!r[o]){i.fail(`\u5DE5\u5177 '${o}' \u5728\u670D\u52A1 '${e}' \u4E2D\u4E0D\u5B58\u5728`),console.log(l.yellow(`\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp ${e} list' \u67E5\u770B\u8BE5\u670D\u52A1\u7684\u6240\u6709\u5DE5\u5177`));return}d.setToolEnabled(e,o,n,r[o].description),i.succeed(`\u6210\u529F${t}\u5DE5\u5177 ${l.cyan(e)}/${l.cyan(o)}`),console.log(),console.log(l.gray("\u{1F4A1} \u63D0\u793A: \u5DE5\u5177\u72B6\u6001\u66F4\u6539\u5C06\u5728\u4E0B\u6B21\u542F\u52A8\u670D\u52A1\u65F6\u751F\u6548"))}catch(c){i.fail(`${t}\u5DE5\u5177\u5931\u8D25`),console.error(l.red(`\u9519\u8BEF: ${c instanceof Error?c.message:String(c)}`)),process.exit(1)}}g(W,"setToolEnabled");var C=new so,H="xiaozhi-mcp-service";function U(){try{let e=x(import.meta.url),o=f.dirname(e),n=[f.join(o,"..","package.json"),f.join(o,"..","package.json"),f.join(o,"..","..","package.json"),f.join(o,"package.json")];for(let t of n)if(p.existsSync(t)){let i=JSON.parse(p.readFileSync(t,"utf8"));if(i.version)return i.version}return"unknown"}catch(e){return console.warn("Warning: Could not read version from package.json:",e),"unknown"}}g(U,"getVersion");var S=f.join(J.tmpdir(),`${H}.pid`),b=f.join(J.tmpdir(),`${H}.log`);function P(){try{if(!p.existsSync(S))return{running:!1};let e=p.readFileSync(S,"utf8").trim(),[o,n,t]=e.split("|"),i=Number.parseInt(o);if(Number.isNaN(i))return p.unlinkSync(S),{running:!1};try{process.kill(i,0);let c=Number.parseInt(n),r=ro(Date.now()-c);return{running:!0,pid:i,uptime:r,mode:t||"foreground"}}catch{return p.unlinkSync(S),{running:!1}}}catch{return{running:!1}}}g(P,"getServiceStatus");function ro(e){let o=Math.floor(e/1e3),n=Math.floor(o/60),t=Math.floor(n/60),i=Math.floor(t/24);return i>0?`${i}\u5929 ${t%24}\u5C0F\u65F6 ${n%60}\u5206\u949F`:t>0?`${t}\u5C0F\u65F6 ${n%60}\u5206\u949F`:n>0?`${n}\u5206\u949F ${o%60}\u79D2`:`${o}\u79D2`}g(ro,"formatUptime");function _(e,o){let n=`${e}|${Date.now()}|${o}`;p.writeFileSync(S,n)}g(_,"savePidInfo");function z(){try{p.existsSync(S)&&p.unlinkSync(S)}catch{}}g(z,"cleanupPidFile");function co(){if(!d.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 e=d.getMcpEndpoint();return!e||e.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(e){return console.error(s.red(`\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u65E0\u6548 - ${e instanceof Error?e.message:String(e)}`)),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u91CD\u65B0\u521D\u59CB\u5316\u914D\u7F6E')),!1}}g(co,"checkEnvironment");function lo(){let e=f.dirname(x(import.meta.url)),o;return e.includes("js-demo/dist")?o=e:o=[f.join(e,"..","js-demo","dist"),f.join(e,"..","..","js-demo","dist"),f.join(e,"..","..","..","js-demo","dist"),f.join(process.cwd(),"js-demo","dist"),f.join(process.cwd(),"dist")].find(t=>p.existsSync(f.join(t,"mcpPipe.js"))&&p.existsSync(f.join(t,"mcpServerProxy.js")))||e,{command:"node",args:["mcpPipe.js","mcpServerProxy.js"],cwd:o}}g(lo,"getServiceCommand");async function V(e=!1){let o=v("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let n=P();if(n.running){o.fail(`\u670D\u52A1\u5DF2\u7ECF\u5728\u8FD0\u884C (PID: ${n.pid})`);return}if(o.text="\u68C0\u67E5\u73AF\u5883\u914D\u7F6E...",!co()){o.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}let{command:t,args:i,cwd:c}=lo();if(o.text=`\u542F\u52A8\u670D\u52A1 (${e?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,e){let r=G(t,i,{cwd:c,detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});_(r.pid,"daemon");let a=p.createWriteStream(b,{flags:"a"});r.stdout?.pipe(a),r.stderr?.pipe(a),r.unref(),o.succeed(`\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${r.pid})`),console.log(s.gray(`\u65E5\u5FD7\u6587\u4EF6: ${b}`)),console.log(s.gray("\u4F7F\u7528 'xiaozhi attach' \u53EF\u4EE5\u67E5\u770B\u5B9E\u65F6\u65E5\u5FD7"))}else{o.succeed("\u670D\u52A1\u542F\u52A8\u4E2D...");let r=G(t,i,{cwd:c,stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});_(r.pid,"foreground"),r.on("exit",(a,u)=>{z(),console.log(a!==0?s.red(`
3
- \u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${a}, \u4FE1\u53F7: ${u})`):s.green(`
2
+ var B=Object.defineProperty;var g=(e,o)=>B(e,"name",{value:o,configurable:!0});import{spawn as G}from"child_process";import d from"fs";import H from"os";import p from"path";import{fileURLToPath as $}from"url";import s from"chalk";import{Command as so}from"commander";import b from"ora";import no from"omelette";import{copyFileSync as K,existsSync as I,readFileSync as Y,writeFileSync as q}from"fs";import{dirname as Q,resolve as T}from"path";import{fileURLToPath as oo}from"url";var eo=Q(oo(import.meta.url)),M=class e{static{g(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=T(eo,"xiaozhi.config.default.json")}getConfigFilePath(){let o=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return T(o,"xiaozhi.config.json")}static getInstance(){return e.instance||(e.instance=new e),e.instance}configExists(){let o=this.getConfigFilePath();return I(o)}initConfig(){if(!I(this.defaultConfigPath))throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.default.json \u4E0D\u5B58\u5728");if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let o=this.getConfigFilePath();K(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(),n=Y(o,"utf8"),t=JSON.parse(n);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 n=o;if(!n.mcpEndpoint||typeof n.mcpEndpoint!="string")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(!n.mcpServers||typeof n.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(n.mcpServers)){if(!i||typeof i!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t} \u65E0\u6548`);let c=i;if(!c.command||typeof c.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.command \u65E0\u6548`);if(!Array.isArray(c.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${t}.args \u5FC5\u987B\u662F\u6570\u7EC4`);if(c.env&&typeof c.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,n){return this.getServerToolsConfig(o)[n]?.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,n){if(!o||typeof o!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!n.command||typeof n.command!="string")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 command \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!Array.isArray(n.args))throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4");if(n.env&&typeof n.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]:n}};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 n=this.getConfig();if(!n.mcpServers[o])throw new Error(`\u670D\u52A1 ${o} \u4E0D\u5B58\u5728`);let t={...n.mcpServers};delete t[o];let i={...n,mcpServers:t};this.saveConfig(i)}updateServerToolsConfig(o,n){let i={...this.getConfig()};i.mcpServerConfig||(i.mcpServerConfig={}),i.mcpServerConfig[o]={tools:n},this.saveConfig(i)}setToolEnabled(o,n,t,i){let r={...this.getConfig()};r.mcpServerConfig||(r.mcpServerConfig={}),r.mcpServerConfig[o]||(r.mcpServerConfig[o]={tools:{}}),r.mcpServerConfig[o].tools[n]={enable:t,...i&&{description:i}},this.saveConfig(r)}saveConfig(o){try{this.validateConfig(o);let n=this.getConfigFilePath(),t=JSON.stringify(o,null,2);q(n,t,"utf8"),this.config=o}catch(n){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}reloadConfig(){this.config=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}},u=M.getInstance();function to(){try{if(!u.configExists())return[];let e=u.getMcpServers();return Object.keys(e)}catch{return[]}}g(to,"getMcpServerNames");function io(e){try{if(!u.configExists())return[];let o=u.getServerToolsConfig(e);return Object.keys(o)}catch{return[]}}g(io,"getServerToolNames");function k(){let e=no("xiaozhi <command>");if(e.on("command",({reply:o})=>{o(["create","init","config","start","stop","status","attach","restart","mcp","completion"])}),e.on("complete",(o,{line:n,before:t,reply:i})=>{process.env.XIAOZHI_DEBUG_COMPLETION&&console.error(`Debug completion - line: "${n}", before: "${t}", fragment: "${o}"`);let c=n.trim().split(/\s+/),a=n!==n.trim()?c.length:c.length-1;if(c[1]==="mcp"){let f=c[2];if(a===2){let m=["list","server","tool"],h=c[2]||"",y=m.filter(w=>w.startsWith(h));i(y);return}if(a===3){switch(f){case"list":{let m=["--tools"],h=c[3]||"",y=m.filter(w=>w.startsWith(h));i(y);break}case"server":case"tool":{let m=to(),h=c[3]||"",y=m.filter(w=>w.startsWith(h));i(y);break}default:i([])}return}if(a===4&&f==="tool"){let m=c[3],h=io(m),y=c[4]||"",w=h.filter(E=>E.startsWith(y));i(w);return}if(a===5&&f==="tool"){let m=["enable","disable"],h=c[5]||"",y=m.filter(w=>w.startsWith(h));i(y);return}}if(a===2){switch(c[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(e.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(e.setupShellInitFile("fish")),process.exit(0)),process.argv.includes("--compzsh")||process.argv.includes("--compbash"),e.init()}g(k,"setupAutoCompletion");function O(){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(O,"showCompletionHelp");import l from"chalk";import D from"cli-table3";import z from"ora";function F(e){let o=0;for(let n of e)/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(n)?o+=2:o+=1;return o}g(F,"getDisplayWidth");function R(e,o){if(F(e)<=o)return e;if(o<=3)return"";let n="",t=0,i=!1;for(let c of e){let r=/[\u4e00-\u9fff\u3400-\u4dbf\uff00-\uffef]/.test(c)?2:1;if(t+r>o-3){if(!i)return"";n+="...";break}n+=c,t+=r,i=!0}return n}g(R,"truncateToWidth");async function A(e={}){let o=z("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868...").start();try{let n=u.getMcpServers(),t=Object.keys(n);if(t.length===0){o.warn("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u670D\u52A1"),console.log(l.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi config' \u547D\u4EE4\u914D\u7F6E MCP \u670D\u52A1"));return}if(o.succeed(`\u627E\u5230 ${t.length} \u4E2A MCP \u670D\u52A1`),e.tools){console.log(),console.log(l.bold("MCP \u670D\u52A1\u5DE5\u5177\u5217\u8868:")),console.log();let i=8,c=[];for(let a of t){let f=u.getServerToolsConfig(a),m=Object.keys(f);c.push(...m)}for(let a of c){let f=F(a);f>i&&(i=f)}i=Math.max(10,Math.min(i+2,30));let r=new D({head:[l.bold("MCP"),l.bold("\u5DE5\u5177\u540D\u79F0"),l.bold("\u72B6\u6001"),l.bold("\u63CF\u8FF0")],colWidths:[15,i,8,40],wordWrap:!0,style:{head:[],border:[]}});for(let a of t){let f=u.getServerToolsConfig(a),m=Object.keys(f);if(m.length===0)r.push([l.gray(a),l.gray("(\u65E0\u5DE5\u5177)"),l.gray("-"),l.gray("\u8BF7\u5148\u542F\u52A8\u670D\u52A1\u626B\u63CF\u5DE5\u5177")]);else{r.length>0&&r.push([{colSpan:4,content:""}]);for(let h of m){let y=f[h],w=y.enable?l.green("\u542F\u7528"):l.red("\u7981\u7528"),E=R(y.description||"",32);r.push([a,h,w,E])}}}console.log(r.toString())}else{console.log(),console.log(l.bold("MCP \u670D\u52A1\u5217\u8868:")),console.log();for(let i of t){let c=n[i],r=u.getServerToolsConfig(i),a=Object.keys(r).length,f=Object.values(r).filter(m=>m.enable!==!1).length;console.log(`${l.cyan("\u2022")} ${l.bold(i)}`),console.log(` \u547D\u4EE4: ${l.gray(c.command)} ${l.gray(c.args.join(" "))}`),a>0?console.log(` \u5DE5\u5177: ${l.green(f)} \u542F\u7528 / ${l.yellow(a)} \u603B\u8BA1`):console.log(` \u5DE5\u5177: ${l.gray("\u672A\u626B\u63CF (\u8BF7\u5148\u542F\u52A8\u670D\u52A1)")}`),console.log()}}console.log(l.gray("\u{1F4A1} \u63D0\u793A:")),console.log(l.gray(" - \u4F7F\u7528 'xiaozhi mcp list --tools' \u67E5\u770B\u6240\u6709\u5DE5\u5177")),console.log(l.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> list' \u67E5\u770B\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177")),console.log(l.gray(" - \u4F7F\u7528 'xiaozhi mcp <\u670D\u52A1\u540D> <\u5DE5\u5177\u540D> enable/disable' \u542F\u7528/\u7981\u7528\u5DE5\u5177"))}catch(n){o.fail("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868\u5931\u8D25"),console.error(l.red(`\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`)),process.exit(1)}}g(A,"listMcpServers");async function L(e){let o=z(`\u83B7\u53D6 ${e} \u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868...`).start();try{if(!u.getMcpServers()[e]){o.fail(`\u670D\u52A1 '${e}' \u4E0D\u5B58\u5728`),console.log(l.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let t=u.getServerToolsConfig(e),i=Object.keys(t);if(i.length===0){o.warn(`\u670D\u52A1 '${e}' \u6682\u65E0\u5DE5\u5177\u4FE1\u606F`),console.log(l.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u542F\u52A8\u670D\u52A1\u4EE5\u626B\u63CF\u5DE5\u5177\u5217\u8868"));return}o.succeed(`\u670D\u52A1 '${e}' \u5171\u6709 ${i.length} \u4E2A\u5DE5\u5177`),console.log(),console.log(l.bold(`${e} \u670D\u52A1\u5DE5\u5177\u5217\u8868:`)),console.log();let c=new D({head:[l.bold("\u5DE5\u5177\u540D\u79F0"),l.bold("\u72B6\u6001"),l.bold("\u63CF\u8FF0")],colWidths:[30,8,50],wordWrap:!0,style:{head:[],border:[]}});for(let r of i){let a=t[r],f=a.enable?l.green("\u542F\u7528"):l.red("\u7981\u7528"),m=R(a.description||"",40);c.push([r,f,m])}console.log(c.toString()),console.log(),console.log(l.gray("\u{1F4A1} \u63D0\u793A:")),console.log(l.gray(` - \u4F7F\u7528 'xiaozhi mcp ${e} <\u5DE5\u5177\u540D> enable' \u542F\u7528\u5DE5\u5177`)),console.log(l.gray(` - \u4F7F\u7528 'xiaozhi mcp ${e} <\u5DE5\u5177\u540D> disable' \u7981\u7528\u5DE5\u5177`))}catch(n){o.fail("\u83B7\u53D6\u5DE5\u5177\u5217\u8868\u5931\u8D25"),console.error(l.red(`\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`)),process.exit(1)}}g(L,"listServerTools");async function W(e,o,n){let t=n?"\u542F\u7528":"\u7981\u7528",i=z(`${t}\u5DE5\u5177 ${e}/${o}...`).start();try{if(!u.getMcpServers()[e]){i.fail(`\u670D\u52A1 '${e}' \u4E0D\u5B58\u5728`),console.log(l.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp list' \u67E5\u770B\u6240\u6709\u53EF\u7528\u670D\u52A1"));return}let r=u.getServerToolsConfig(e);if(!r[o]){i.fail(`\u5DE5\u5177 '${o}' \u5728\u670D\u52A1 '${e}' \u4E2D\u4E0D\u5B58\u5728`),console.log(l.yellow(`\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 'xiaozhi mcp ${e} list' \u67E5\u770B\u8BE5\u670D\u52A1\u7684\u6240\u6709\u5DE5\u5177`));return}u.setToolEnabled(e,o,n,r[o].description),i.succeed(`\u6210\u529F${t}\u5DE5\u5177 ${l.cyan(e)}/${l.cyan(o)}`),console.log(),console.log(l.gray("\u{1F4A1} \u63D0\u793A: \u5DE5\u5177\u72B6\u6001\u66F4\u6539\u5C06\u5728\u4E0B\u6B21\u542F\u52A8\u670D\u52A1\u65F6\u751F\u6548"))}catch(c){i.fail(`${t}\u5DE5\u5177\u5931\u8D25`),console.error(l.red(`\u9519\u8BEF: ${c instanceof Error?c.message:String(c)}`)),process.exit(1)}}g(W,"setToolEnabled");var C=new so,J="xiaozhi-mcp-service";function Z(){try{let e=$(import.meta.url),o=p.dirname(e),n=[p.join(o,"..","package.json"),p.join(o,"..","package.json"),p.join(o,"..","..","package.json"),p.join(o,"package.json")];for(let t of n)if(d.existsSync(t)){let i=JSON.parse(d.readFileSync(t,"utf8"));if(i.version)return i.version}return"unknown"}catch(e){return console.warn("Warning: Could not read version from package.json:",e),"unknown"}}g(Z,"getVersion");var v=p.join(H.tmpdir(),`${J}.pid`),S=p.join(H.tmpdir(),`${J}.log`);function P(){try{if(!d.existsSync(v))return{running:!1};let e=d.readFileSync(v,"utf8").trim(),[o,n,t]=e.split("|"),i=Number.parseInt(o);if(Number.isNaN(i))return d.unlinkSync(v),{running:!1};try{process.kill(i,0);let c=Number.parseInt(n),r=ro(Date.now()-c);return{running:!0,pid:i,uptime:r,mode:t||"foreground"}}catch{return d.unlinkSync(v),{running:!1}}}catch{return{running:!1}}}g(P,"getServiceStatus");function ro(e){let o=Math.floor(e/1e3),n=Math.floor(o/60),t=Math.floor(n/60),i=Math.floor(t/24);return i>0?`${i}\u5929 ${t%24}\u5C0F\u65F6 ${n%60}\u5206\u949F`:t>0?`${t}\u5C0F\u65F6 ${n%60}\u5206\u949F`:n>0?`${n}\u5206\u949F ${o%60}\u79D2`:`${o}\u79D2`}g(ro,"formatUptime");function _(e,o){let n=`${e}|${Date.now()}|${o}`;d.writeFileSync(v,n)}g(_,"savePidInfo");function x(){try{d.existsSync(v)&&d.unlinkSync(v)}catch{}}g(x,"cleanupPidFile");function co(){if(!u.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 e=u.getMcpEndpoint();return!e||e.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(e){return console.error(s.red(`\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u65E0\u6548 - ${e instanceof Error?e.message:String(e)}`)),console.log(s.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u91CD\u65B0\u521D\u59CB\u5316\u914D\u7F6E')),!1}}g(co,"checkEnvironment");function lo(){let e=p.dirname($(import.meta.url)),o;return e.includes("js-demo/dist")?o=e:o=[p.join(e,"..","js-demo","dist"),p.join(e,"..","..","js-demo","dist"),p.join(e,"..","..","..","js-demo","dist"),p.join(process.cwd(),"js-demo","dist"),p.join(process.cwd(),"dist")].find(t=>d.existsSync(p.join(t,"mcpPipe.js"))&&d.existsSync(p.join(t,"mcpServerProxy.js")))||e,{command:"node",args:["mcpPipe.js","mcpServerProxy.js"],cwd:o}}g(lo,"getServiceCommand");async function U(e=!1){let o=b("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let n=P();if(n.running){o.fail(`\u670D\u52A1\u5DF2\u7ECF\u5728\u8FD0\u884C (PID: ${n.pid})`);return}if(o.text="\u68C0\u67E5\u73AF\u5883\u914D\u7F6E...",!co()){o.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}let{command:t,args:i,cwd:c}=lo();if(o.text=`\u542F\u52A8\u670D\u52A1 (${e?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,e){let r=G(t,i,{cwd:c,detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd(),XIAOZHI_DAEMON:"true"}});_(r.pid,"daemon");let a=d.createWriteStream(S,{flags:"a"});r.stdout?.pipe(a),r.stderr?.pipe(a),r.on("exit",(f,m)=>{if(f!==0&&f!==null){let h=`
3
+ [${new Date().toISOString()}] \u540E\u53F0\u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${f}, \u4FE1\u53F7: ${m})
4
+ `;d.appendFileSync(S,h)}x()}),r.on("error",f=>{let m=`
5
+ [${new Date().toISOString()}] \u540E\u53F0\u670D\u52A1\u542F\u52A8\u9519\u8BEF: ${f.message}
6
+ `;d.appendFileSync(S,m),x(),o.fail(`\u540E\u53F0\u670D\u52A1\u542F\u52A8\u5931\u8D25: ${f.message}`)}),r.unref(),o.succeed(`\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${r.pid})`),console.log(s.gray(`\u65E5\u5FD7\u6587\u4EF6: ${S}`)),console.log(s.gray("\u4F7F\u7528 'xiaozhi attach' \u53EF\u4EE5\u67E5\u770B\u5B9E\u65F6\u65E5\u5FD7"))}else{o.succeed("\u670D\u52A1\u542F\u52A8\u4E2D...");let r=G(t,i,{cwd:c,stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});_(r.pid,"foreground"),r.on("exit",(a,f)=>{x(),console.log(a!==0?s.red(`
7
+ \u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${a}, \u4FE1\u53F7: ${f})`):s.green(`
4
8
  \u670D\u52A1\u5DF2\u505C\u6B62`))}),process.on("SIGINT",()=>{console.log(s.yellow(`
5
- \u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),r.kill("SIGTERM")}),process.on("SIGTERM",()=>{r.kill("SIGTERM")})}}catch(n){o.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}g(V,"startService");async function Z(){let e=v("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let o=P();if(!o.running){e.warn("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}e.text=`\u505C\u6B62\u670D\u52A1 (PID: ${o.pid})...`;try{process.kill(o.pid,"SIGTERM");let n=0,t=30;for(;n<t;){await new Promise(i=>setTimeout(i,100));try{process.kill(o.pid,0),n++}catch{break}}try{process.kill(o.pid,0),e.text="\u5F3A\u5236\u505C\u6B62\u670D\u52A1...",process.kill(o.pid,"SIGKILL"),await new Promise(i=>setTimeout(i,500))}catch{}z(),e.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(n){z(),e.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}catch(o){e.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(Z,"stopService");async function ao(){let e=v("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let o=P();o.running?(e.succeed("\u670D\u52A1\u72B6\u6001"),console.log(s.green("\u2705 \u670D\u52A1\u6B63\u5728\u8FD0\u884C")),console.log(s.gray(` PID: ${o.pid}`)),console.log(s.gray(` \u8FD0\u884C\u65F6\u95F4: ${o.uptime}`)),console.log(s.gray(` \u8FD0\u884C\u6A21\u5F0F: ${o.mode==="daemon"?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"}`)),o.mode==="daemon"&&console.log(s.gray(` \u65E5\u5FD7\u6587\u4EF6: ${b}`))):(e.succeed("\u670D\u52A1\u72B6\u6001"),console.log(s.red("\u274C \u670D\u52A1\u672A\u8FD0\u884C")))}catch(o){e.fail(`\u68C0\u67E5\u72B6\u6001\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(ao,"checkStatus");async function go(){let e=v("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let o=P();if(!o.running){e.fail("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}if(o.mode!=="daemon"){e.fail("\u670D\u52A1\u4E0D\u662F\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C");return}if(e.succeed("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1..."),console.log(s.green(`\u5DF2\u8FDE\u63A5\u5230\u670D\u52A1 (PID: ${o.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))),p.existsSync(b))if(process.platform==="win32"){let{spawn:n}=await import("child_process"),t=n("powershell",["-Command",`Get-Content -Path "${b}" -Wait`],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(s.yellow(`
6
- \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),t.kill(),process.exit(0)}),t.on("exit",()=>{process.exit(0)})}else{let{spawn:n}=await import("child_process"),t=n("tail",["-f",b],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(s.yellow(`
7
- \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),t.kill(),process.exit(0)}),t.on("exit",()=>{process.exit(0)})}else console.log(s.yellow("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728"))}catch(o){e.fail(`\u8FDE\u63A5\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(go,"attachService");async function fo(e=!1){console.log(s.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await Z(),await new Promise(o=>setTimeout(o,1e3)),await V(e)}g(fo,"restartService");function po(){let e=U();console.log(s.blue(`xiaozhi v${e}`)),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}`))}g(po,"showDetailedInfo");async function mo(){let e=v("\u521D\u59CB\u5316\u914D\u7F6E...").start();try{if(d.configExists()){e.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}d.initConfig(),e.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: ${d.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(o){e.fail(`\u521D\u59CB\u5316\u914D\u7F6E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(mo,"initConfig");function uo(){let e=f.dirname(x(import.meta.url)),n=[f.join(e,"..","templates"),f.join(e,"templates"),f.join(e,"..","..","templates")].find(t=>p.existsSync(t));return n?p.readdirSync(n).filter(t=>{let i=f.join(n,t);return p.statSync(i).isDirectory()}):[]}g(uo,"getAvailableTemplates");function N(e,o){let n=e.length,t=o.length,i=Array(n+1).fill(null).map(()=>Array(t+1).fill(0));for(let r=0;r<=n;r++)i[r][0]=r;for(let r=0;r<=t;r++)i[0][r]=r;for(let r=1;r<=n;r++)for(let a=1;a<=t;a++)e[r-1]===o[a-1]?i[r][a]=i[r-1][a-1]:i[r][a]=Math.min(i[r-1][a]+1,i[r][a-1]+1,i[r-1][a-1]+1);let c=Math.max(n,t);return c===0?1:(c-i[n][t])/c}g(N,"calculateSimilarity");function ho(e,o){if(o.length===0)return null;let n=o[0],t=N(e.toLowerCase(),n.toLowerCase());for(let i of o.slice(1)){let c=N(e.toLowerCase(),i.toLowerCase());c>t&&(t=c,n=i)}return t>.5?n:null}g(ho,"findSimilarTemplate");async function yo(e){if(!process.stdin.isTTY)return console.log("n (\u975E\u4EA4\u4E92\u5F0F\u73AF\u5883)"),!1;let o=await import("readline");return new Promise(n=>{process.stdout.write(e);let t=o.createInterface({input:process.stdin,output:process.stdout}),i=g(c=>{let r=c.trim().toLowerCase();r==="y"||r==="yes"?(t.close(),n(!0)):r==="n"||r==="no"||r===""?(t.close(),n(!1)):process.stdout.write("\u8BF7\u8F93\u5165 y \u6216 n: ")},"handleInput");t.on("line",i),t.on("SIGINT",()=>{t.close(),n(!1)})})}g(yo,"askUserConfirmation");function Co(e){let o={mcpEndpoint:"<\u8BF7\u586B\u5199\u4F60\u7684\u63A5\u5165\u70B9\u5730\u5740\uFF08\u83B7\u53D6\u5730\u5740\u5728 xiaozhi.me\uFF09>",mcpServers:{}},n=f.join(e,"xiaozhi.config.json");p.writeFileSync(n,JSON.stringify(o,null,2),"utf8")}g(Co,"createBasicConfig");async function wo(e,o){let n=v("\u521D\u59CB\u5316\u9879\u76EE...").start();try{let t=f.join(process.cwd(),e);if(p.existsSync(t)){n.fail(`\u76EE\u5F55 "${e}" \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(o.template){n.text="\u68C0\u67E5\u6A21\u677F...";let i=uo();if(i.length===0){n.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(!i.includes(o.template)){n.fail(`\u6A21\u677F "${o.template}" \u4E0D\u5B58\u5728`);let m=ho(o.template,i);if(m)if(console.log(s.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${m}" \u5417\uFF1F`)),await yo(s.cyan("\u786E\u8BA4\u4F7F\u7528\u6B64\u6A21\u677F\uFF1F(y/n): ")))o.template=m;else{console.log(s.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let y of i)console.log(s.gray(` - ${y}`));return}else{console.log(s.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let h of i)console.log(s.gray(` - ${h}`));return}}let c=f.dirname(x(import.meta.url)),a=[f.join(c,"..","templates"),f.join(c,"templates"),f.join(c,"..","..","templates")].find(m=>p.existsSync(m)),u=f.join(a,o.template);n.text=`\u4ECE\u6A21\u677F "${o.template}" \u521B\u5EFA\u9879\u76EE "${e}"...`,B(u,t,["node_modules",".pnpm-debug.log","pnpm-lock.yaml"]),n.succeed(`\u9879\u76EE "${e}" \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 ${e}`)),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 n.text=`\u521B\u5EFA\u57FA\u672C\u9879\u76EE "${e}"...`,p.mkdirSync(t,{recursive:!0}),Co(t),n.succeed(`\u9879\u76EE "${e}" \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 ${e}`)),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){n.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(wo,"createProject");function B(e,o,n=[]){p.existsSync(o)||p.mkdirSync(o,{recursive:!0});let t=p.readdirSync(e);for(let i of t){if(n.some(u=>i.includes(u)))continue;let c=f.join(e,i),r=f.join(o,i);p.statSync(c).isDirectory()?B(c,r,n):p.copyFileSync(c,r)}}g(B,"copyDirectory");async function So(e,o){let n=v("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!d.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}if(o)switch(e){case"mcpEndpoint":d.updateMcpEndpoint(o),n.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${o}`);break;default:n.fail(`\u914D\u7F6E\u9879 ${e} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(s.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint"));return}else{n.text="\u8BFB\u53D6\u914D\u7F6E...";let t=d.getConfig();switch(e){case"mcpEndpoint":n.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`MCP \u7AEF\u70B9: ${t.mcpEndpoint}`));break;case"mcpServers":n.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green("MCP \u670D\u52A1:"));for(let[i,c]of Object.entries(t.mcpServers))console.log(s.gray(` ${i}: ${c.command} ${c.args.join(" ")}`));break;default:n.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${e}`),console.log(s.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers"));return}}}catch(t){n.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(So,"configCommand");function vo(){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] \u542F\u52A8\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C)"),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] \u91CD\u542F\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C)"),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 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(vo,"showHelp");C.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(U(),"-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(e,o)=>{await wo(e,o)});C.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").action(async()=>{await mo()});C.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(e,o)=>{await So(e,o)});C.command("start").description("\u542F\u52A8\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").action(async e=>{await V(e.daemon)});C.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await Z()});C.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await ao()});C.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await go()});C.command("restart").description("\u91CD\u542F\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").action(async e=>{await fo(e.daemon)});var j=C.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");j.command("list").description("\u5217\u51FA MCP \u670D\u52A1").option("--tools","\u663E\u793A\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868").action(async e=>{await A(e)});j.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async e=>{await L(e)});j.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(e,o,n)=>{n!=="enable"&&n!=="disable"&&(console.error(s.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await W(e,o,n==="enable")});C.command("completion").description("\u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E").action(async()=>{D()});C.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(e=>{e.V&&(po(),process.exit(0))});k();process.argv.length<=2&&(vo(),process.exit(0));C.parse(process.argv);export{N as calculateSimilarity,co as checkEnvironment,ro as formatUptime,P as getServiceStatus,U as getVersion};
9
+ \u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),r.kill("SIGTERM")}),process.on("SIGTERM",()=>{r.kill("SIGTERM")})}}catch(n){o.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}g(U,"startService");async function V(){let e=b("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let o=P();if(!o.running){e.warn("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}e.text=`\u505C\u6B62\u670D\u52A1 (PID: ${o.pid})...`;try{process.kill(o.pid,"SIGTERM");let n=0,t=30;for(;n<t;){await new Promise(i=>setTimeout(i,100));try{process.kill(o.pid,0),n++}catch{break}}try{process.kill(o.pid,0),e.text="\u5F3A\u5236\u505C\u6B62\u670D\u52A1...",process.kill(o.pid,"SIGKILL"),await new Promise(i=>setTimeout(i,500))}catch{}x(),e.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(n){x(),e.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}catch(o){e.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(V,"stopService");async function ao(){let e=b("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let o=P();o.running?(e.succeed("\u670D\u52A1\u72B6\u6001"),console.log(s.green("\u2705 \u670D\u52A1\u6B63\u5728\u8FD0\u884C")),console.log(s.gray(` PID: ${o.pid}`)),console.log(s.gray(` \u8FD0\u884C\u65F6\u95F4: ${o.uptime}`)),console.log(s.gray(` \u8FD0\u884C\u6A21\u5F0F: ${o.mode==="daemon"?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"}`)),o.mode==="daemon"&&console.log(s.gray(` \u65E5\u5FD7\u6587\u4EF6: ${S}`))):(e.succeed("\u670D\u52A1\u72B6\u6001"),console.log(s.red("\u274C \u670D\u52A1\u672A\u8FD0\u884C")))}catch(o){e.fail(`\u68C0\u67E5\u72B6\u6001\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(ao,"checkStatus");async function go(){let e=b("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{let o=P();if(!o.running){e.fail("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}if(o.mode!=="daemon"){e.fail("\u670D\u52A1\u4E0D\u662F\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C");return}if(e.succeed("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1..."),console.log(s.green(`\u5DF2\u8FDE\u63A5\u5230\u670D\u52A1 (PID: ${o.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))),d.existsSync(S))if(process.platform==="win32"){let{spawn:n}=await import("child_process"),t=n("powershell",["-Command",`Get-Content -Path "${S}" -Wait`],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(s.yellow(`
10
+ \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),t.kill(),process.exit(0)}),t.on("exit",()=>{process.exit(0)})}else{let{spawn:n}=await import("child_process"),t=n("tail",["-f",S],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(s.yellow(`
11
+ \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),t.kill(),process.exit(0)}),t.on("exit",()=>{process.exit(0)})}else console.log(s.yellow("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728"))}catch(o){e.fail(`\u8FDE\u63A5\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(go,"attachService");async function fo(e=!1){console.log(s.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await V(),await new Promise(o=>setTimeout(o,1e3)),await U(e)}g(fo,"restartService");function po(){let e=Z();console.log(s.blue(`xiaozhi v${e}`)),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}`))}g(po,"showDetailedInfo");async function mo(){let e=b("\u521D\u59CB\u5316\u914D\u7F6E...").start();try{if(u.configExists()){e.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}u.initConfig(),e.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: ${u.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(o){e.fail(`\u521D\u59CB\u5316\u914D\u7F6E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}}g(mo,"initConfig");function uo(){let e=p.dirname($(import.meta.url)),n=[p.join(e,"..","templates"),p.join(e,"templates"),p.join(e,"..","..","templates")].find(t=>d.existsSync(t));return n?d.readdirSync(n).filter(t=>{let i=p.join(n,t);return d.statSync(i).isDirectory()}):[]}g(uo,"getAvailableTemplates");function N(e,o){let n=e.length,t=o.length,i=Array(n+1).fill(null).map(()=>Array(t+1).fill(0));for(let r=0;r<=n;r++)i[r][0]=r;for(let r=0;r<=t;r++)i[0][r]=r;for(let r=1;r<=n;r++)for(let a=1;a<=t;a++)e[r-1]===o[a-1]?i[r][a]=i[r-1][a-1]:i[r][a]=Math.min(i[r-1][a]+1,i[r][a-1]+1,i[r-1][a-1]+1);let c=Math.max(n,t);return c===0?1:(c-i[n][t])/c}g(N,"calculateSimilarity");function ho(e,o){if(o.length===0)return null;let n=o[0],t=N(e.toLowerCase(),n.toLowerCase());for(let i of o.slice(1)){let c=N(e.toLowerCase(),i.toLowerCase());c>t&&(t=c,n=i)}return t>.5?n:null}g(ho,"findSimilarTemplate");async function yo(e){if(!process.stdin.isTTY)return console.log("n (\u975E\u4EA4\u4E92\u5F0F\u73AF\u5883)"),!1;let o=await import("readline");return new Promise(n=>{process.stdout.write(e);let t=o.createInterface({input:process.stdin,output:process.stdout}),i=g(c=>{let r=c.trim().toLowerCase();r==="y"||r==="yes"?(t.close(),n(!0)):r==="n"||r==="no"||r===""?(t.close(),n(!1)):process.stdout.write("\u8BF7\u8F93\u5165 y \u6216 n: ")},"handleInput");t.on("line",i),t.on("SIGINT",()=>{t.close(),n(!1)})})}g(yo,"askUserConfirmation");function Co(e){let o={mcpEndpoint:"<\u8BF7\u586B\u5199\u4F60\u7684\u63A5\u5165\u70B9\u5730\u5740\uFF08\u83B7\u53D6\u5730\u5740\u5728 xiaozhi.me\uFF09>",mcpServers:{}},n=p.join(e,"xiaozhi.config.json");d.writeFileSync(n,JSON.stringify(o,null,2),"utf8")}g(Co,"createBasicConfig");async function wo(e,o){let n=b("\u521D\u59CB\u5316\u9879\u76EE...").start();try{let t=p.join(process.cwd(),e);if(d.existsSync(t)){n.fail(`\u76EE\u5F55 "${e}" \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(o.template){n.text="\u68C0\u67E5\u6A21\u677F...";let i=uo();if(i.length===0){n.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(!i.includes(o.template)){n.fail(`\u6A21\u677F "${o.template}" \u4E0D\u5B58\u5728`);let m=ho(o.template,i);if(m)if(console.log(s.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${m}" \u5417\uFF1F`)),await yo(s.cyan("\u786E\u8BA4\u4F7F\u7528\u6B64\u6A21\u677F\uFF1F(y/n): ")))o.template=m;else{console.log(s.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let y of i)console.log(s.gray(` - ${y}`));return}else{console.log(s.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(let h of i)console.log(s.gray(` - ${h}`));return}}let c=p.dirname($(import.meta.url)),a=[p.join(c,"..","templates"),p.join(c,"templates"),p.join(c,"..","..","templates")].find(m=>d.existsSync(m)),f=p.join(a,o.template);n.text=`\u4ECE\u6A21\u677F "${o.template}" \u521B\u5EFA\u9879\u76EE "${e}"...`,X(f,t,["node_modules",".pnpm-debug.log","pnpm-lock.yaml"]),n.succeed(`\u9879\u76EE "${e}" \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 ${e}`)),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 n.text=`\u521B\u5EFA\u57FA\u672C\u9879\u76EE "${e}"...`,d.mkdirSync(t,{recursive:!0}),Co(t),n.succeed(`\u9879\u76EE "${e}" \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 ${e}`)),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){n.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(wo,"createProject");function X(e,o,n=[]){d.existsSync(o)||d.mkdirSync(o,{recursive:!0});let t=d.readdirSync(e);for(let i of t){if(n.some(f=>i.includes(f)))continue;let c=p.join(e,i),r=p.join(o,i);d.statSync(c).isDirectory()?X(c,r,n):d.copyFileSync(c,r)}}g(X,"copyDirectory");async function So(e,o){let n=b("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!u.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}if(o)switch(e){case"mcpEndpoint":u.updateMcpEndpoint(o),n.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${o}`);break;default:n.fail(`\u914D\u7F6E\u9879 ${e} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(s.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint"));return}else{n.text="\u8BFB\u53D6\u914D\u7F6E...";let t=u.getConfig();switch(e){case"mcpEndpoint":n.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green(`MCP \u7AEF\u70B9: ${t.mcpEndpoint}`));break;case"mcpServers":n.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(s.green("MCP \u670D\u52A1:"));for(let[i,c]of Object.entries(t.mcpServers))console.log(s.gray(` ${i}: ${c.command} ${c.args.join(" ")}`));break;default:n.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${e}`),console.log(s.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers"));return}}}catch(t){n.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}g(So,"configCommand");function vo(){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] \u542F\u52A8\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C)"),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] \u91CD\u542F\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C)"),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 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(vo,"showHelp");C.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(Z(),"-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(e,o)=>{await wo(e,o)});C.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").action(async()=>{await mo()});C.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(e,o)=>{await So(e,o)});C.command("start").description("\u542F\u52A8\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").action(async e=>{await U(e.daemon)});C.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await V()});C.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await ao()});C.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await go()});C.command("restart").description("\u91CD\u542F\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").action(async e=>{await fo(e.daemon)});var j=C.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");j.command("list").description("\u5217\u51FA MCP \u670D\u52A1").option("--tools","\u663E\u793A\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868").action(async e=>{await A(e)});j.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async e=>{await L(e)});j.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(e,o,n)=>{n!=="enable"&&n!=="disable"&&(console.error(s.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await W(e,o,n==="enable")});C.command("completion").description("\u663E\u793A\u81EA\u52A8\u8865\u5168\u8BBE\u7F6E\u8BF4\u660E").action(async()=>{O()});C.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(e=>{e.V&&(po(),process.exit(0))});k();process.argv.length<=2&&(vo(),process.exit(0));C.parse(process.argv);export{N as calculateSimilarity,co as checkEnvironment,ro as formatUptime,P as getServiceStatus,Z as getVersion};
8
12
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/autoCompletion.ts","../src/configManager.ts","../src/mcpCommands.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\nimport { setupAutoCompletion, showCompletionHelp } from \"./autoCompletion\";\nimport { configManager } from \"./configManager\";\nimport { listMcpServers, listServerTools, setToolEnabled } from \"./mcpCommands\";\n\nconst program = new Command();\nconst SERVICE_NAME = \"xiaozhi-mcp-service\";\n\n/**\n * 获取版本号\n */\nexport function getVersion(): string {\n try {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n // 尝试多个可能的 package.json 路径\n const possiblePaths = [\n // 开发环境:src/cli.ts -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 构建后环境:dist/cli.js -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"package.json\"),\n // 如果 package.json 被复制到 dist 目录\n path.join(currentDir, \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n if (packageJson.version) {\n return packageJson.version;\n }\n }\n }\n\n // 如果都找不到,返回默认版本\n return \"unknown\";\n } catch (error) {\n console.warn(\"Warning: Could not read version from package.json:\", error);\n return \"unknown\";\n }\n}\n\n// PID 文件路径\nconst PID_FILE = path.join(os.tmpdir(), `${SERVICE_NAME}.pid`);\nconst LOG_FILE = path.join(os.tmpdir(), `${SERVICE_NAME}.log`);\n\ninterface ServiceStatus {\n running: boolean;\n pid?: number;\n uptime?: string;\n mode?: \"foreground\" | \"daemon\";\n}\n\n/**\n * 获取服务状态\n */\nexport function getServiceStatus(): ServiceStatus {\n try {\n if (!fs.existsSync(PID_FILE)) {\n return { running: false };\n }\n\n const pidContent = fs.readFileSync(PID_FILE, \"utf8\").trim();\n const [pidStr, startTime, mode] = pidContent.split(\"|\");\n const pid = Number.parseInt(pidStr);\n\n if (Number.isNaN(pid)) {\n // PID 文件损坏,删除它\n fs.unlinkSync(PID_FILE);\n return { running: false };\n }\n\n // 检查进程是否还在运行\n try {\n process.kill(pid, 0); // 发送信号 0 来检查进程是否存在\n\n // 计算运行时间\n const start = Number.parseInt(startTime);\n const uptime = formatUptime(Date.now() - start);\n\n return {\n running: true,\n pid,\n uptime,\n mode: (mode as \"foreground\" | \"daemon\") || \"foreground\",\n };\n } catch (error) {\n // 进程不存在,删除 PID 文件\n fs.unlinkSync(PID_FILE);\n return { running: false };\n }\n } catch (error) {\n return { running: false };\n }\n}\n\n/**\n * 格式化运行时间\n */\nexport function formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}天 ${hours % 24}小时 ${minutes % 60}分钟`;\n }\n if (hours > 0) {\n return `${hours}小时 ${minutes % 60}分钟`;\n }\n if (minutes > 0) {\n return `${minutes}分钟 ${seconds % 60}秒`;\n }\n return `${seconds}秒`;\n}\n\n/**\n * 保存 PID 信息\n */\nfunction savePidInfo(pid: number, mode: \"foreground\" | \"daemon\") {\n const pidInfo = `${pid}|${Date.now()}|${mode}`;\n fs.writeFileSync(PID_FILE, pidInfo);\n}\n\n/**\n * 清理 PID 文件\n */\nfunction cleanupPidFile() {\n try {\n if (fs.existsSync(PID_FILE)) {\n fs.unlinkSync(PID_FILE);\n }\n } catch (error) {\n // 忽略清理错误\n }\n}\n\n/**\n * 检查配置文件和环境\n */\nexport function checkEnvironment(): boolean {\n // 首先检查配置文件是否存在\n if (!configManager.configExists()) {\n console.error(chalk.red(\"❌ 错误: 配置文件不存在\"));\n console.log(chalk.yellow('💡 提示: 请运行 \"xiaozhi init\" 初始化配置'));\n return false;\n }\n\n try {\n // 检查配置是否有效\n const endpoint = configManager.getMcpEndpoint();\n if (!endpoint || endpoint.includes(\"<请填写\")) {\n console.error(chalk.red(\"❌ 错误: MCP 端点未配置\"));\n console.log(\n chalk.yellow(\n '💡 提示: 请运行 \"xiaozhi config mcpEndpoint <your-endpoint-url>\" 设置端点'\n )\n );\n return false;\n }\n return true;\n } catch (error) {\n console.error(\n chalk.red(\n `❌ 错误: 配置文件无效 - ${\n error instanceof Error ? error.message : String(error)\n }`\n )\n );\n console.log(chalk.yellow('💡 提示: 请运行 \"xiaozhi init\" 重新初始化配置'));\n return false;\n }\n}\n\n/**\n * 获取服务启动命令和参数\n */\nfunction getServiceCommand(): { command: string; args: string[]; cwd: string } {\n // 获取当前脚本所在目录\n const scriptDir = path.dirname(fileURLToPath(import.meta.url));\n\n // 检查是否在开发环境(js-demo/dist)还是全局安装环境\n let distDir: string;\n if (scriptDir.includes(\"js-demo/dist\")) {\n // 开发环境\n distDir = scriptDir;\n } else {\n // 全局安装环境,需要找到实际的项目目录\n // 通常全局安装后,脚本在 node_modules/.bin 或类似位置\n // 我们需要找到实际的 dist 目录\n const possiblePaths = [\n path.join(scriptDir, \"..\", \"js-demo\", \"dist\"),\n path.join(scriptDir, \"..\", \"..\", \"js-demo\", \"dist\"),\n path.join(scriptDir, \"..\", \"..\", \"..\", \"js-demo\", \"dist\"),\n path.join(process.cwd(), \"js-demo\", \"dist\"),\n path.join(process.cwd(), \"dist\"),\n ];\n\n distDir =\n possiblePaths.find(\n (p) =>\n fs.existsSync(path.join(p, \"mcpPipe.js\")) &&\n fs.existsSync(path.join(p, \"mcpServerProxy.js\"))\n ) || scriptDir;\n }\n\n return {\n command: \"node\",\n args: [\"mcpPipe.js\", \"mcpServerProxy.js\"],\n cwd: distDir,\n };\n}\n\n/**\n * 启动服务\n */\nasync function startService(daemon = false): Promise<void> {\n const spinner = ora(\"检查服务状态...\").start();\n\n try {\n // 检查服务是否已经在运行\n const status = getServiceStatus();\n if (status.running) {\n spinner.fail(`服务已经在运行 (PID: ${status.pid})`);\n return;\n }\n\n // 检查环境变量\n spinner.text = \"检查环境配置...\";\n if (!checkEnvironment()) {\n spinner.fail(\"环境配置检查失败\");\n return;\n }\n\n // 获取启动命令\n const { command, args, cwd } = getServiceCommand();\n\n spinner.text = `启动服务 (${daemon ? \"后台模式\" : \"前台模式\"})...`;\n\n if (daemon) {\n // 后台模式\n const child = spawn(command, args, {\n cwd,\n detached: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.cwd(), // 传递用户的当前工作目录\n },\n });\n\n // 保存 PID 信息\n savePidInfo(child.pid!, \"daemon\");\n\n // 设置日志输出\n const logStream = fs.createWriteStream(LOG_FILE, { flags: \"a\" });\n child.stdout?.pipe(logStream);\n child.stderr?.pipe(logStream);\n\n // 分离进程\n child.unref();\n\n spinner.succeed(`服务已在后台启动 (PID: ${child.pid})`);\n console.log(chalk.gray(`日志文件: ${LOG_FILE}`));\n console.log(chalk.gray(`使用 'xiaozhi attach' 可以查看实时日志`));\n } else {\n // 前台模式\n spinner.succeed(\"服务启动中...\");\n\n const child = spawn(command, args, {\n cwd,\n stdio: \"inherit\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.cwd(), // 传递用户的当前工作目录\n },\n });\n\n // 保存 PID 信息\n savePidInfo(child.pid!, \"foreground\");\n\n // 处理进程退出\n child.on(\"exit\", (code, signal) => {\n cleanupPidFile();\n if (code !== 0) {\n console.log(\n chalk.red(`\\n服务异常退出 (代码: ${code}, 信号: ${signal})`)\n );\n } else {\n console.log(chalk.green(\"\\n服务已停止\"));\n }\n });\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(chalk.yellow(\"\\n正在停止服务...\"));\n child.kill(\"SIGTERM\");\n });\n\n process.on(\"SIGTERM\", () => {\n child.kill(\"SIGTERM\");\n });\n }\n } catch (error) {\n spinner.fail(\n `启动服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 停止服务\n */\nasync function stopService(): Promise<void> {\n const spinner = ora(\"检查服务状态...\").start();\n\n try {\n const status = getServiceStatus();\n\n if (!status.running) {\n spinner.warn(\"服务未在运行\");\n return;\n }\n\n spinner.text = `停止服务 (PID: ${status.pid})...`;\n\n try {\n // 尝试优雅停止\n process.kill(status.pid!, \"SIGTERM\");\n\n // 等待进程停止\n let attempts = 0;\n const maxAttempts = 30; // 3秒超时\n\n while (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n try {\n process.kill(status.pid!, 0);\n attempts++;\n } catch {\n // 进程已停止\n break;\n }\n }\n\n // 检查是否还在运行\n try {\n process.kill(status.pid!, 0);\n // 如果还在运行,强制停止\n spinner.text = \"强制停止服务...\";\n process.kill(status.pid!, \"SIGKILL\");\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n // 进程已停止\n }\n\n cleanupPidFile();\n spinner.succeed(\"服务已停止\");\n } catch (error) {\n cleanupPidFile();\n spinner.fail(\n `停止服务失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n } catch (error) {\n spinner.fail(\n `停止服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 检查服务状态\n */\nasync function checkStatus(): Promise<void> {\n const spinner = ora(\"检查服务状态...\").start();\n\n try {\n const status = getServiceStatus();\n\n if (status.running) {\n spinner.succeed(\"服务状态\");\n console.log(chalk.green(\"✅ 服务正在运行\"));\n console.log(chalk.gray(` PID: ${status.pid}`));\n console.log(chalk.gray(` 运行时间: ${status.uptime}`));\n console.log(\n chalk.gray(\n ` 运行模式: ${status.mode === \"daemon\" ? \"后台模式\" : \"前台模式\"}`\n )\n );\n\n if (status.mode === \"daemon\") {\n console.log(chalk.gray(` 日志文件: ${LOG_FILE}`));\n }\n } else {\n spinner.succeed(\"服务状态\");\n console.log(chalk.red(\"❌ 服务未运行\"));\n }\n } catch (error) {\n spinner.fail(\n `检查状态失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 附加到后台服务\n */\nasync function attachService(): Promise<void> {\n const spinner = ora(\"检查服务状态...\").start();\n\n try {\n const status = getServiceStatus();\n\n if (!status.running) {\n spinner.fail(\"服务未在运行\");\n return;\n }\n\n if (status.mode !== \"daemon\") {\n spinner.fail(\"服务不是在后台模式运行\");\n return;\n }\n\n spinner.succeed(\"连接到后台服务...\");\n console.log(chalk.green(`已连接到服务 (PID: ${status.pid})`));\n console.log(chalk.gray(\"按 Ctrl+C 可以断开连接(不会停止服务)\"));\n console.log(chalk.gray(\"=\".repeat(50)));\n\n // 显示日志文件内容\n if (fs.existsSync(LOG_FILE)) {\n // 跨平台的日志查看实现\n if (process.platform === \"win32\") {\n // Windows 使用 PowerShell 的 Get-Content -Wait\n const { spawn } = await import(\"node:child_process\");\n const tail = spawn(\n \"powershell\",\n [\"-Command\", `Get-Content -Path \"${LOG_FILE}\" -Wait`],\n { stdio: \"inherit\" }\n );\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(chalk.yellow(\"\\n断开连接,服务继续在后台运行\"));\n tail.kill();\n process.exit(0);\n });\n\n tail.on(\"exit\", () => {\n process.exit(0);\n });\n } else {\n // Unix/Linux/macOS 使用 tail -f\n const { spawn } = await import(\"node:child_process\");\n const tail = spawn(\"tail\", [\"-f\", LOG_FILE], { stdio: \"inherit\" });\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(chalk.yellow(\"\\n断开连接,服务继续在后台运行\"));\n tail.kill();\n process.exit(0);\n });\n\n tail.on(\"exit\", () => {\n process.exit(0);\n });\n }\n } else {\n console.log(chalk.yellow(\"日志文件不存在\"));\n }\n } catch (error) {\n spinner.fail(\n `连接失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 重启服务\n */\nasync function restartService(daemon = false): Promise<void> {\n console.log(chalk.blue(\"🔄 重启服务...\"));\n\n // 先停止服务\n await stopService();\n\n // 等待一下确保完全停止\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n // 重新启动服务\n await startService(daemon);\n}\n\n/**\n * 显示详细信息\n */\nfunction showDetailedInfo(): void {\n const version = getVersion();\n console.log(chalk.blue(`xiaozhi v${version}`));\n console.log(chalk.gray(\"MCP Calculator Service CLI Tool\"));\n console.log(chalk.gray(\"Built with Node.js and TypeScript\"));\n console.log(chalk.gray(`Node.js: ${process.version}`));\n console.log(chalk.gray(`Platform: ${process.platform} ${process.arch}`));\n}\n\n/**\n * 初始化配置\n */\nasync function initConfig(): Promise<void> {\n const spinner = ora(\"初始化配置...\").start();\n\n try {\n if (configManager.configExists()) {\n spinner.warn(\"配置文件已存在\");\n console.log(\n chalk.yellow(\"如需重新初始化,请先删除现有的 xiaozhi.config.json 文件\")\n );\n return;\n }\n\n configManager.initConfig();\n spinner.succeed(\"配置文件初始化成功\");\n\n console.log(chalk.green(\"✅ 配置文件已创建: xiaozhi.config.json\"));\n console.log(chalk.yellow(\"📝 请编辑配置文件设置你的 MCP 端点:\"));\n console.log(\n chalk.gray(` 配置文件路径: ${configManager.getConfigPath()}`)\n );\n console.log(chalk.yellow(\"💡 或者使用命令设置:\"));\n console.log(\n chalk.gray(\" xiaozhi config mcpEndpoint <your-endpoint-url>\")\n );\n } catch (error) {\n spinner.fail(\n `初始化配置失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n}\n\n/**\n * 获取可用模板列表\n */\nfunction getAvailableTemplates(): string[] {\n const scriptDir = path.dirname(fileURLToPath(import.meta.url));\n const possiblePaths = [\n path.join(scriptDir, \"..\", \"templates\"), // 开发环境\n path.join(scriptDir, \"templates\"), // 打包后的环境\n path.join(scriptDir, \"..\", \"..\", \"templates\"), // npm 全局安装\n ];\n\n const templatesDir = possiblePaths.find((p) => fs.existsSync(p));\n if (!templatesDir) {\n return [];\n }\n\n return fs.readdirSync(templatesDir).filter((item) => {\n const itemPath = path.join(templatesDir, item);\n return fs.statSync(itemPath).isDirectory();\n });\n}\n\n/**\n * 计算字符串相似度(简单的编辑距离算法)\n */\nexport function calculateSimilarity(str1: string, str2: string): number {\n const len1 = str1.length;\n const len2 = str2.length;\n const matrix = Array(len1 + 1)\n .fill(null)\n .map(() => Array(len2 + 1).fill(0));\n\n for (let i = 0; i <= len1; i++) matrix[i][0] = i;\n for (let j = 0; j <= len2; j++) matrix[0][j] = j;\n\n for (let i = 1; i <= len1; i++) {\n for (let j = 1; j <= len2; j++) {\n if (str1[i - 1] === str2[j - 1]) {\n matrix[i][j] = matrix[i - 1][j - 1];\n } else {\n matrix[i][j] = Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + 1\n );\n }\n }\n }\n\n const maxLen = Math.max(len1, len2);\n return maxLen === 0 ? 1 : (maxLen - matrix[len1][len2]) / maxLen;\n}\n\n/**\n * 查找最相似的模板\n */\nfunction findSimilarTemplate(\n input: string,\n templates: string[]\n): string | null {\n if (templates.length === 0) return null;\n\n let bestMatch = templates[0];\n let bestSimilarity = calculateSimilarity(\n input.toLowerCase(),\n bestMatch.toLowerCase()\n );\n\n for (const template of templates.slice(1)) {\n const similarity = calculateSimilarity(\n input.toLowerCase(),\n template.toLowerCase()\n );\n if (similarity > bestSimilarity) {\n bestSimilarity = similarity;\n bestMatch = template;\n }\n }\n\n // 只有相似度超过 0.5 才认为是可能的匹配\n return bestSimilarity > 0.5 ? bestMatch : null;\n}\n\n/**\n * 询问用户确认\n */\nasync function askUserConfirmation(question: string): Promise<boolean> {\n // 检查是否在交互式终端中\n if (!process.stdin.isTTY) {\n // 非交互式环境,默认返回 false\n console.log(\"n (非交互式环境)\");\n return false;\n }\n\n // 使用 readline 接口处理用户输入\n const readline = await import(\"node:readline\");\n\n return new Promise((resolve) => {\n process.stdout.write(question);\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const handleInput = (input: string) => {\n const char = input.trim().toLowerCase();\n if (char === \"y\" || char === \"yes\") {\n rl.close();\n resolve(true);\n } else if (char === \"n\" || char === \"no\" || char === \"\") {\n rl.close();\n resolve(false);\n } else {\n // 无效输入,重新询问\n process.stdout.write(\"请输入 y 或 n: \");\n }\n };\n\n rl.on(\"line\", handleInput);\n rl.on(\"SIGINT\", () => {\n rl.close();\n resolve(false);\n });\n });\n}\n\n/**\n * 创建基本的 xiaozhi.config.json 文件\n */\nfunction createBasicConfig(projectPath: string): void {\n const configContent = {\n mcpEndpoint: \"<请填写你的接入点地址(获取地址在 xiaozhi.me)>\",\n mcpServers: {},\n };\n\n const configPath = path.join(projectPath, \"xiaozhi.config.json\");\n fs.writeFileSync(configPath, JSON.stringify(configContent, null, 2), \"utf8\");\n}\n\n/**\n * 创建项目命令\n */\nasync function createProject(\n projectName: string,\n options: { template?: string }\n): Promise<void> {\n const spinner = ora(\"初始化项目...\").start();\n\n try {\n // 确定目标目录\n const targetPath = path.join(process.cwd(), projectName);\n\n // 检查目标目录是否已存在\n if (fs.existsSync(targetPath)) {\n spinner.fail(`目录 \"${projectName}\" 已存在`);\n console.log(chalk.yellow(\"💡 提示: 请选择不同的项目名称或删除现有目录\"));\n return;\n }\n\n if (options.template) {\n // 使用模板创建项目\n spinner.text = \"检查模板...\";\n\n // 获取可用模板列表\n const availableTemplates = getAvailableTemplates();\n\n if (availableTemplates.length === 0) {\n spinner.fail(\"找不到 templates 目录\");\n console.log(chalk.yellow(\"💡 提示: 请确保 xiaozhi-client 正确安装\"));\n return;\n }\n\n // 检查模板是否存在\n if (!availableTemplates.includes(options.template)) {\n spinner.fail(`模板 \"${options.template}\" 不存在`);\n\n // 尝试找到相似的模板\n const similarTemplate = findSimilarTemplate(\n options.template,\n availableTemplates\n );\n\n if (similarTemplate) {\n console.log(\n chalk.yellow(`💡 你是想使用模板 \"${similarTemplate}\" 吗?`)\n );\n const confirmed = await askUserConfirmation(\n chalk.cyan(\"确认使用此模板?(y/n): \")\n );\n\n if (confirmed) {\n options.template = similarTemplate;\n } else {\n console.log(chalk.yellow(\"可用的模板:\"));\n for (const template of availableTemplates) {\n console.log(chalk.gray(` - ${template}`));\n }\n return;\n }\n } else {\n console.log(chalk.yellow(\"可用的模板:\"));\n for (const template of availableTemplates) {\n console.log(chalk.gray(` - ${template}`));\n }\n return;\n }\n }\n\n // 获取模板路径 (ESM 环境)\n const scriptDir = path.dirname(fileURLToPath(import.meta.url));\n const possiblePaths = [\n path.join(scriptDir, \"..\", \"templates\"), // 开发环境\n path.join(scriptDir, \"templates\"), // 打包后的环境\n path.join(scriptDir, \"..\", \"..\", \"templates\"), // npm 全局安装\n ];\n const templatesDir = possiblePaths.find((p) => fs.existsSync(p))!;\n const templatePath = path.join(templatesDir, options.template);\n\n spinner.text = `从模板 \"${options.template}\" 创建项目 \"${projectName}\"...`;\n\n // 复制模板到目标目录\n copyDirectory(templatePath, targetPath, [\n \"node_modules\",\n \".pnpm-debug.log\",\n \"pnpm-lock.yaml\",\n ]);\n\n spinner.succeed(`项目 \"${projectName}\" 创建成功`);\n\n console.log(chalk.green(\"✅ 项目创建完成!\"));\n console.log(chalk.yellow(\"📝 接下来的步骤:\"));\n console.log(chalk.gray(` cd ${projectName}`));\n console.log(chalk.gray(\" pnpm install # 安装依赖\"));\n console.log(\n chalk.gray(\" # 编辑 xiaozhi.config.json 设置你的 MCP 端点\")\n );\n console.log(chalk.gray(\" xiaozhi start # 启动服务\"));\n } else {\n // 创建基本项目(只有配置文件)\n spinner.text = `创建基本项目 \"${projectName}\"...`;\n\n // 创建项目目录\n fs.mkdirSync(targetPath, { recursive: true });\n\n // 创建基本的 xiaozhi.config.json\n createBasicConfig(targetPath);\n\n spinner.succeed(`项目 \"${projectName}\" 创建成功`);\n\n console.log(chalk.green(\"✅ 基本项目创建完成!\"));\n console.log(chalk.yellow(\"📝 接下来的步骤:\"));\n console.log(chalk.gray(` cd ${projectName}`));\n console.log(\n chalk.gray(\" # 编辑 xiaozhi.config.json 设置你的 MCP 端点和服务\")\n );\n console.log(chalk.gray(\" xiaozhi start # 启动服务\"));\n console.log(\n chalk.yellow(\"💡 提示: 使用 --template 选项可以从模板创建项目\")\n );\n }\n } catch (error) {\n spinner.fail(\n `创建项目失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 递归复制目录\n */\nfunction copyDirectory(\n src: string,\n dest: string,\n excludePatterns: string[] = []\n): void {\n // 创建目标目录\n if (!fs.existsSync(dest)) {\n fs.mkdirSync(dest, { recursive: true });\n }\n\n const items = fs.readdirSync(src);\n\n for (const item of items) {\n // 检查是否应该排除此项\n if (excludePatterns.some((pattern) => item.includes(pattern))) {\n continue;\n }\n\n const srcPath = path.join(src, item);\n const destPath = path.join(dest, item);\n const stat = fs.statSync(srcPath);\n\n if (stat.isDirectory()) {\n copyDirectory(srcPath, destPath, excludePatterns);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/**\n * 配置管理命令\n */\nasync function configCommand(key: string, value?: string): Promise<void> {\n const spinner = ora(\"更新配置...\").start();\n\n try {\n if (!configManager.configExists()) {\n spinner.fail(\"配置文件不存在\");\n console.log(chalk.yellow('💡 提示: 请先运行 \"xiaozhi init\" 初始化配置'));\n return;\n }\n\n if (!value) {\n // 显示配置值\n spinner.text = \"读取配置...\";\n const config = configManager.getConfig();\n\n switch (key) {\n case \"mcpEndpoint\":\n spinner.succeed(\"配置信息\");\n console.log(chalk.green(`MCP 端点: ${config.mcpEndpoint}`));\n break;\n case \"mcpServers\":\n spinner.succeed(\"配置信息\");\n console.log(chalk.green(\"MCP 服务:\"));\n for (const [name, serverConfig] of Object.entries(\n config.mcpServers\n )) {\n console.log(\n chalk.gray(\n ` ${name}: ${serverConfig.command} ${serverConfig.args.join(\n \" \"\n )}`\n )\n );\n }\n break;\n default:\n spinner.fail(`未知的配置项: ${key}`);\n console.log(chalk.yellow(\"支持的配置项: mcpEndpoint, mcpServers\"));\n return;\n }\n } else {\n // 设置配置值\n switch (key) {\n case \"mcpEndpoint\":\n configManager.updateMcpEndpoint(value);\n spinner.succeed(`MCP 端点已更新为: ${value}`);\n break;\n default:\n spinner.fail(`配置项 ${key} 不支持通过命令行设置`);\n console.log(chalk.yellow(\"支持设置的配置项: mcpEndpoint\"));\n return;\n }\n }\n } catch (error) {\n spinner.fail(\n `配置操作失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 显示帮助信息\n */\nfunction showHelp(): void {\n console.log(chalk.blue.bold(\"xiaozhi - MCP Calculator Service CLI\"));\n console.log();\n console.log(chalk.yellow(\"使用方法:\"));\n console.log(\" xiaozhi <command> [options]\");\n console.log();\n console.log(chalk.yellow(\"命令:\"));\n console.log(\" create <projectName> 创建项目\");\n console.log(\" init 初始化配置文件\");\n console.log(\" config <key> [value] 查看或设置配置\");\n console.log(\" start [--daemon] 启动服务 (--daemon 后台运行)\");\n console.log(\" stop 停止服务\");\n console.log(\" status 检查服务状态\");\n console.log(\" attach 连接到后台服务查看日志\");\n console.log(\" restart [--daemon] 重启服务 (--daemon 后台运行)\");\n console.log(\" completion 显示自动补全设置说明\");\n console.log();\n console.log(chalk.yellow(\"选项:\"));\n console.log(\" -v, --version 显示版本信息\");\n console.log(\" -V 显示详细信息\");\n console.log(\" -h, --help 显示帮助信息\");\n console.log(\" -t, --template <name> 指定模板名称(用于 create 命令)\");\n console.log();\n console.log(chalk.yellow(\"项目示例:\"));\n console.log(\" xiaozhi create my-app # 创建基本项目\");\n console.log(\n \" xiaozhi create my-app -t hello-world # 使用 hello-world 模板\"\n );\n console.log(\n \" xiaozhi create my-app --template hello-world # 同上,完整选项名\"\n );\n console.log();\n console.log(chalk.yellow(\"配置示例:\"));\n console.log(\" xiaozhi init # 初始化配置\");\n console.log(\" xiaozhi config mcpEndpoint # 查看 MCP 端点\");\n console.log(\" xiaozhi config mcpEndpoint wss://... # 设置 MCP 端点\");\n console.log();\n console.log(chalk.yellow(\"服务示例:\"));\n console.log(\" xiaozhi start # 前台启动服务\");\n console.log(\" xiaozhi start --daemon # 后台启动服务\");\n console.log(\" xiaozhi status # 检查服务状态\");\n console.log(\" xiaozhi attach # 查看后台服务日志\");\n console.log(\" xiaozhi stop # 停止服务\");\n console.log();\n console.log(chalk.yellow(\"MCP 管理示例:\"));\n console.log(\" xiaozhi mcp list # 列出所有 MCP 服务\");\n console.log(\" xiaozhi mcp list --tools # 列出所有服务的工具\");\n console.log(\" xiaozhi mcp server <name> # 列出指定服务的工具\");\n console.log(\" xiaozhi mcp tool <server> <tool> enable # 启用工具\");\n console.log(\" xiaozhi mcp tool <server> <tool> disable # 禁用工具\");\n console.log();\n console.log(chalk.yellow(\"自动补全:\"));\n console.log(\" xiaozhi completion # 显示自动补全设置说明\");\n console.log(\" # 设置后可使用 Tab 键进行命令、参数自动补全\");\n}\n\n// 配置 Commander 程序\nprogram\n .name(\"xiaozhi\")\n .description(\"MCP Calculator Service CLI Tool\")\n .version(getVersion(), \"-v, --version\", \"显示版本信息\")\n .helpOption(\"-h, --help\", \"显示帮助信息\");\n\n// create 命令\nprogram\n .command(\"create <projectName>\")\n .description(\"创建项目\")\n .option(\"-t, --template <templateName>\", \"使用指定模板创建项目\")\n .action(async (projectName, options) => {\n await createProject(projectName, options);\n });\n\n// init 命令\nprogram\n .command(\"init\")\n .description(\"初始化配置文件\")\n .action(async () => {\n await initConfig();\n });\n\n// config 命令\nprogram\n .command(\"config <key> [value]\")\n .description(\"查看或设置配置\")\n .action(async (key, value) => {\n await configCommand(key, value);\n });\n\n// start 命令\nprogram\n .command(\"start\")\n .description(\"启动服务\")\n .option(\"-d, --daemon\", \"在后台运行服务\")\n .action(async (options) => {\n await startService(options.daemon);\n });\n\n// stop 命令\nprogram\n .command(\"stop\")\n .description(\"停止服务\")\n .action(async () => {\n await stopService();\n });\n\n// status 命令\nprogram\n .command(\"status\")\n .description(\"检查服务状态\")\n .action(async () => {\n await checkStatus();\n });\n\n// attach 命令\nprogram\n .command(\"attach\")\n .description(\"连接到后台服务查看日志\")\n .action(async () => {\n await attachService();\n });\n\n// restart 命令\nprogram\n .command(\"restart\")\n .description(\"重启服务\")\n .option(\"-d, --daemon\", \"在后台运行服务\")\n .action(async (options) => {\n await restartService(options.daemon);\n });\n\n// mcp 命令组\nconst mcpCommand = program.command(\"mcp\").description(\"MCP 服务和工具管理\");\n\n// mcp list 命令\nmcpCommand\n .command(\"list\")\n .description(\"列出 MCP 服务\")\n .option(\"--tools\", \"显示所有服务的工具列表\")\n .action(async (options) => {\n await listMcpServers(options);\n });\n\n// mcp <server> list 命令\nmcpCommand\n .command(\"server <serverName>\")\n .description(\"管理指定的 MCP 服务\")\n .action(async (serverName) => {\n await listServerTools(serverName);\n });\n\n// mcp <server> <tool> enable/disable 命令\nmcpCommand\n .command(\"tool <serverName> <toolName> <action>\")\n .description(\"启用或禁用指定服务的工具\")\n .action(async (serverName, toolName, action) => {\n if (action !== \"enable\" && action !== \"disable\") {\n console.error(chalk.red(\"错误: 操作必须是 'enable' 或 'disable'\"));\n process.exit(1);\n }\n\n const enabled = action === \"enable\";\n await setToolEnabled(serverName, toolName, enabled);\n });\n\n// completion 命令\nprogram\n .command(\"completion\")\n .description(\"显示自动补全设置说明\")\n .action(async () => {\n showCompletionHelp();\n });\n\n// -V 选项 (详细信息)\nprogram.option(\"-V\", \"显示详细信息\").action((options) => {\n if (options.V) {\n showDetailedInfo();\n process.exit(0);\n }\n});\n\n// 设置自动补全\nsetupAutoCompletion();\n\n// 处理无参数情况,显示帮助\nif (process.argv.length <= 2) {\n showHelp();\n process.exit(0);\n}\n\n// 解析命令行参数\nprogram.parse(process.argv);\n","import omelette from \"omelette\";\nimport { configManager } from \"./configManager\";\n\n/**\n * 自动补全功能模块\n */\n\n/**\n * 获取所有可用的MCP服务器名称\n */\nfunction getMcpServerNames(): string[] {\n try {\n if (!configManager.configExists()) {\n return [];\n }\n const mcpServers = configManager.getMcpServers();\n return Object.keys(mcpServers);\n } catch (error) {\n return [];\n }\n}\n\n/**\n * 获取指定服务器的工具名称\n */\nfunction getServerToolNames(serverName: string): string[] {\n try {\n if (!configManager.configExists()) {\n return [];\n }\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n return Object.keys(toolsConfig);\n } catch (error) {\n return [];\n }\n}\n\n/**\n * 设置自动补全功能\n */\nexport function setupAutoCompletion(): void {\n // 创建 omelette 实例,使用简单的模板\n const completion = omelette(\"xiaozhi <command>\");\n\n // 处理主命令补全\n completion.on(\"command\", ({ reply }) => {\n reply([\n \"create\",\n \"init\",\n \"config\",\n \"start\",\n \"stop\",\n \"status\",\n \"attach\",\n \"restart\",\n \"mcp\",\n \"completion\",\n ]);\n });\n\n // 处理复杂的多级命令补全\n completion.on(\"complete\", (fragment, { line, before, reply }) => {\n // 调试信息\n if (process.env.XIAOZHI_DEBUG_COMPLETION) {\n console.error(\n `Debug completion - line: \"${line}\", before: \"${before}\", fragment: \"${fragment}\"`\n );\n }\n\n const parts = line.trim().split(/\\s+/);\n const endsWithSpace = line !== line.trim();\n const currentIndex = endsWithSpace ? parts.length : parts.length - 1;\n\n // MCP 相关的补全\n if (parts[1] === \"mcp\") {\n const subcommand = parts[2];\n\n if (currentIndex === 2) {\n // mcp 子命令\n const subcommands = [\"list\", \"server\", \"tool\"];\n const current = parts[2] || \"\";\n const matches = subcommands.filter((cmd) => cmd.startsWith(current));\n reply(matches);\n return;\n }\n\n if (currentIndex === 3) {\n switch (subcommand) {\n case \"list\": {\n const options = [\"--tools\"];\n const current = parts[3] || \"\";\n const matches = options.filter((opt) => opt.startsWith(current));\n reply(matches);\n break;\n }\n case \"server\":\n case \"tool\": {\n const serverNames = getMcpServerNames();\n const current = parts[3] || \"\";\n const matches = serverNames.filter((name) =>\n name.startsWith(current)\n );\n reply(matches);\n break;\n }\n default:\n reply([]);\n }\n return;\n }\n\n if (currentIndex === 4 && subcommand === \"tool\") {\n const serverName = parts[3];\n const toolNames = getServerToolNames(serverName);\n const current = parts[4] || \"\";\n const matches = toolNames.filter((name) => name.startsWith(current));\n reply(matches);\n return;\n }\n\n if (currentIndex === 5 && subcommand === \"tool\") {\n const actions = [\"enable\", \"disable\"];\n const current = parts[5] || \"\";\n const matches = actions.filter((action) => action.startsWith(current));\n reply(matches);\n return;\n }\n }\n\n // 其他命令的子参数补全\n if (currentIndex === 2) {\n const command = parts[1];\n switch (command) {\n case \"create\":\n reply([\"--template\", \"-t\"]);\n break;\n case \"start\":\n case \"restart\":\n reply([\"--daemon\", \"-d\"]);\n break;\n case \"completion\":\n reply([\"install\", \"uninstall\"]);\n break;\n default:\n reply([]);\n }\n return;\n }\n\n // 默认情况\n reply([]);\n });\n\n // 处理补全相关的命令行参数\n if (process.argv.includes(\"--completion\")) {\n // 输出补全脚本供shell使用\n try {\n console.log(completion.setupShellInitFile());\n } catch (error) {\n console.error(\"生成自动补全脚本时出错:\", error);\n }\n process.exit(0);\n }\n\n if (process.argv.includes(\"--completion-fish\")) {\n // Fish shell 补全\n console.log(completion.setupShellInitFile(\"fish\"));\n process.exit(0);\n }\n\n if (\n process.argv.includes(\"--compzsh\") ||\n process.argv.includes(\"--compbash\")\n ) {\n // 处理实际的补全请求 - 这些是omelette内部使用的参数\n // 不需要手动处理,让omelette自己处理\n }\n\n // 初始化补全\n completion.init();\n}\n\n/**\n * 显示自动补全安装说明\n */\nexport function showCompletionHelp(): void {\n console.log(\"🚀 xiaozhi 自动补全设置\");\n console.log();\n console.log(\"要启用自动补全,请根据你的shell执行以下命令:\");\n console.log();\n console.log(\"📝 Zsh (推荐):\");\n console.log(\" xiaozhi --completion >> ~/.xiaozhi-completion.zsh\");\n console.log(\" echo 'source ~/.xiaozhi-completion.zsh' >> ~/.zshrc\");\n console.log(\" source ~/.zshrc\");\n console.log();\n console.log(\"📝 Bash:\");\n console.log(\" xiaozhi --completion >> ~/.xiaozhi-completion.bash\");\n console.log(\" echo 'source ~/.xiaozhi-completion.bash' >> ~/.bash_profile\");\n console.log(\" source ~/.bash_profile\");\n console.log();\n console.log(\"📝 Fish:\");\n console.log(\n \" xiaozhi --completion-fish >> ~/.config/fish/completions/xiaozhi.fish\"\n );\n console.log();\n console.log(\"✨ 设置完成后,你就可以使用 Tab 键进行自动补全了!\");\n console.log();\n console.log(\"💡 示例:\");\n console.log(\" xiaozhi m<Tab> # → mcp\");\n console.log(\" xiaozhi mcp l<Tab> # → list\");\n console.log(\" xiaozhi mcp tool <Tab> # → 显示所有服务器名称\");\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 配置文件接口定义\nexport interface MCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface AppConfig {\n mcpEndpoint: string;\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n\n private constructor() {\n this.defaultConfigPath = resolve(__dirname, \"xiaozhi.config.default.json\");\n }\n\n /**\n * 获取配置文件路径(动态计算)\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n const configPath = this.getConfigFilePath();\n return existsSync(configPath);\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n */\n public initConfig(): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(\"默认配置文件 xiaozhi.config.default.json 不存在\");\n }\n\n if (this.configExists()) {\n throw new Error(\"配置文件 xiaozhi.config.json 已存在,无需重复初始化\");\n }\n\n const configPath = this.getConfigFilePath();\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\n \"配置文件 xiaozhi.config.json 不存在,请先运行 xiaozhi init 初始化配置\"\n );\n }\n\n try {\n const configPath = this.getConfigFilePath();\n const configData = readFileSync(configPath, \"utf8\");\n const config = JSON.parse(configData) as AppConfig;\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (!configObj.mcpEndpoint || typeof configObj.mcpEndpoint !== \"string\") {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n const sc = serverConfig as Record<string, unknown>;\n if (!sc.command || typeof sc.command !== \"string\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.command 无效`\n );\n }\n\n if (!Array.isArray(sc.args)) {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.args 必须是数组`\n );\n }\n\n if (sc.env && typeof sc.env !== \"object\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.env 必须是对象`\n );\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取 MCP 端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n return config.mcpEndpoint;\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点\n */\n public updateMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getConfig();\n const newConfig = { ...config, mcpEndpoint: endpoint };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 验证服务配置\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n throw new Error(\"服务配置的 command 字段必须是非空字符串\");\n }\n\n if (!Array.isArray(serverConfig.args)) {\n throw new Error(\"服务配置的 args 字段必须是数组\");\n }\n\n if (serverConfig.env && typeof serverConfig.env !== \"object\") {\n throw new Error(\"服务配置的 env 字段必须是对象\");\n }\n\n const config = this.getConfig();\n const newConfig = {\n ...config,\n mcpServers: {\n ...config.mcpServers,\n [serverName]: serverConfig,\n },\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getConfig();\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n const newMcpServers = { ...config.mcpServers };\n delete newMcpServers[serverName];\n\n const newConfig = {\n ...config,\n mcpServers: newMcpServers,\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 更新指定服务的工具配置\n newConfig.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!newConfig.mcpServerConfig[serverName]) {\n newConfig.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n newConfig.mcpServerConfig[serverName].tools[toolName] = {\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 保存配置到文件\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 格式化 JSON 并保存\n const configPath = this.getConfigFilePath();\n const configJson = JSON.stringify(config, null, 2);\n writeFileSync(configPath, configJson, \"utf8\");\n\n // 更新缓存\n this.config = config;\n } catch (error) {\n throw new Error(\n `保存配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n","import chalk from \"chalk\";\nimport Table from \"cli-table3\";\nimport ora from \"ora\";\nimport { configManager } from \"./configManager\";\n\n/**\n * MCP 相关的命令行功能\n */\n\n/**\n * 计算字符串的显示宽度(中文字符占2个宽度,英文字符占1个宽度)\n */\nexport function getDisplayWidth(str: string): number {\n let width = 0;\n for (const char of str) {\n // 判断是否为中文字符(包括中文标点符号)\n if (/[\\u4e00-\\u9fff\\u3400-\\u4dbf\\uff00-\\uffef]/.test(char)) {\n width += 2;\n } else {\n width += 1;\n }\n }\n return width;\n}\n\n/**\n * 截断字符串到指定的显示宽度\n */\nexport function truncateToWidth(str: string, maxWidth: number): string {\n if (getDisplayWidth(str) <= maxWidth) {\n return str;\n }\n\n // 如果最大宽度小于等于省略号的宽度,返回空字符串\n if (maxWidth <= 3) {\n return \"\";\n }\n\n let result = \"\";\n let currentWidth = 0;\n let hasAddedChar = false;\n\n for (const char of str) {\n const charWidth = /[\\u4e00-\\u9fff\\u3400-\\u4dbf\\uff00-\\uffef]/.test(char)\n ? 2\n : 1;\n\n // 如果加上当前字符会超出限制\n if (currentWidth + charWidth > maxWidth - 3) {\n // 如果还没有添加任何字符,说明连一个字符都放不下,返回空字符串\n if (!hasAddedChar) {\n return \"\";\n }\n // 否则添加省略号并退出\n result += \"...\";\n break;\n }\n\n result += char;\n currentWidth += charWidth;\n hasAddedChar = true;\n }\n\n return result;\n}\n\n/**\n * 列出所有 MCP 服务\n */\nexport async function listMcpServers(\n options: { tools?: boolean } = {}\n): Promise<void> {\n const spinner = ora(\"获取 MCP 服务列表...\").start();\n\n try {\n const mcpServers = configManager.getMcpServers();\n const serverNames = Object.keys(mcpServers);\n\n if (serverNames.length === 0) {\n spinner.warn(\"未配置任何 MCP 服务\");\n console.log(\n chalk.yellow(\"💡 提示: 使用 'xiaozhi config' 命令配置 MCP 服务\")\n );\n return;\n }\n\n spinner.succeed(`找到 ${serverNames.length} 个 MCP 服务`);\n\n if (options.tools) {\n // 显示所有服务的工具列表\n console.log();\n console.log(chalk.bold(\"MCP 服务工具列表:\"));\n console.log();\n\n // 计算所有工具名称的最大长度,用于动态设置列宽\n let maxToolNameWidth = 8; // 默认最小宽度\n const allToolNames: string[] = [];\n\n for (const serverName of serverNames) {\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n allToolNames.push(...toolNames);\n }\n\n // 计算最长工具名称的显示宽度\n for (const toolName of allToolNames) {\n const width = getDisplayWidth(toolName);\n if (width > maxToolNameWidth) {\n maxToolNameWidth = width;\n }\n }\n\n // 确保工具名称列宽度至少为10,最多为30\n maxToolNameWidth = Math.max(10, Math.min(maxToolNameWidth + 2, 30));\n\n // 使用 cli-table3 创建表格\n const table = new Table({\n head: [\n chalk.bold(\"MCP\"),\n chalk.bold(\"工具名称\"),\n chalk.bold(\"状态\"),\n chalk.bold(\"描述\"),\n ],\n colWidths: [15, maxToolNameWidth, 8, 40], // MCP | 工具名称 | 状态 | 描述\n wordWrap: true,\n style: {\n head: [],\n border: [],\n },\n });\n\n for (const serverName of serverNames) {\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n\n if (toolNames.length === 0) {\n // 服务没有工具时显示提示信息\n table.push([\n chalk.gray(serverName),\n chalk.gray(\"(无工具)\"),\n chalk.gray(\"-\"),\n chalk.gray(\"请先启动服务扫描工具\"),\n ]);\n } else {\n // 添加服务分隔行\n if (table.length > 0) {\n table.push([{ colSpan: 4, content: \"\" }]);\n }\n\n for (const toolName of toolNames) {\n const toolConfig = toolsConfig[toolName];\n const status = toolConfig.enable\n ? chalk.green(\"启用\")\n : chalk.red(\"禁用\");\n\n // 截断描述到最大32个字符宽度(约16个中文字符)\n const description = truncateToWidth(\n toolConfig.description || \"\",\n 32\n );\n\n // 只显示工具名称,不包含服务名前缀\n table.push([serverName, toolName, status, description]);\n }\n }\n }\n\n console.log(table.toString());\n } else {\n // 只显示服务列表\n console.log();\n console.log(chalk.bold(\"MCP 服务列表:\"));\n console.log();\n\n for (const serverName of serverNames) {\n const serverConfig = mcpServers[serverName];\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolCount = Object.keys(toolsConfig).length;\n const enabledCount = Object.values(toolsConfig).filter(\n (t) => t.enable !== false\n ).length;\n\n console.log(`${chalk.cyan(\"•\")} ${chalk.bold(serverName)}`);\n console.log(\n ` 命令: ${chalk.gray(serverConfig.command)} ${chalk.gray(\n serverConfig.args.join(\" \")\n )}`\n );\n if (toolCount > 0) {\n console.log(\n ` 工具: ${chalk.green(enabledCount)} 启用 / ${chalk.yellow(\n toolCount\n )} 总计`\n );\n } else {\n console.log(` 工具: ${chalk.gray(\"未扫描 (请先启动服务)\")}`);\n }\n console.log();\n }\n }\n\n console.log(chalk.gray(\"💡 提示:\"));\n console.log(chalk.gray(\" - 使用 'xiaozhi mcp list --tools' 查看所有工具\"));\n console.log(\n chalk.gray(\" - 使用 'xiaozhi mcp <服务名> list' 查看指定服务的工具\")\n );\n console.log(\n chalk.gray(\n \" - 使用 'xiaozhi mcp <服务名> <工具名> enable/disable' 启用/禁用工具\"\n )\n );\n } catch (error) {\n spinner.fail(\"获取 MCP 服务列表失败\");\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n}\n\n/**\n * 列出指定服务的工具\n */\nexport async function listServerTools(serverName: string): Promise<void> {\n const spinner = ora(`获取 ${serverName} 服务的工具列表...`).start();\n\n try {\n const mcpServers = configManager.getMcpServers();\n\n if (!mcpServers[serverName]) {\n spinner.fail(`服务 '${serverName}' 不存在`);\n console.log(\n chalk.yellow(\"💡 提示: 使用 'xiaozhi mcp list' 查看所有可用服务\")\n );\n return;\n }\n\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n\n if (toolNames.length === 0) {\n spinner.warn(`服务 '${serverName}' 暂无工具信息`);\n console.log(chalk.yellow(\"💡 提示: 请先启动服务以扫描工具列表\"));\n return;\n }\n\n spinner.succeed(`服务 '${serverName}' 共有 ${toolNames.length} 个工具`);\n\n console.log();\n console.log(chalk.bold(`${serverName} 服务工具列表:`));\n console.log();\n\n // 使用 cli-table3 创建表格\n const table = new Table({\n head: [chalk.bold(\"工具名称\"), chalk.bold(\"状态\"), chalk.bold(\"描述\")],\n colWidths: [30, 8, 50], // 工具名称 | 状态 | 描述\n wordWrap: true,\n style: {\n head: [],\n border: [],\n },\n });\n\n for (const toolName of toolNames) {\n const toolConfig = toolsConfig[toolName];\n const status = toolConfig.enable\n ? chalk.green(\"启用\")\n : chalk.red(\"禁用\");\n\n // 截断描述到最大40个字符宽度(约20个中文字符)\n const description = truncateToWidth(toolConfig.description || \"\", 40);\n\n table.push([toolName, status, description]);\n }\n\n console.log(table.toString());\n\n console.log();\n console.log(chalk.gray(\"💡 提示:\"));\n console.log(\n chalk.gray(\n ` - 使用 'xiaozhi mcp ${serverName} <工具名> enable' 启用工具`\n )\n );\n console.log(\n chalk.gray(\n ` - 使用 'xiaozhi mcp ${serverName} <工具名> disable' 禁用工具`\n )\n );\n } catch (error) {\n spinner.fail(\"获取工具列表失败\");\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n}\n\n/**\n * 启用或禁用工具\n */\nexport async function setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean\n): Promise<void> {\n const action = enabled ? \"启用\" : \"禁用\";\n const spinner = ora(`${action}工具 ${serverName}/${toolName}...`).start();\n\n try {\n const mcpServers = configManager.getMcpServers();\n\n if (!mcpServers[serverName]) {\n spinner.fail(`服务 '${serverName}' 不存在`);\n console.log(\n chalk.yellow(\"💡 提示: 使用 'xiaozhi mcp list' 查看所有可用服务\")\n );\n return;\n }\n\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n\n if (!toolsConfig[toolName]) {\n spinner.fail(`工具 '${toolName}' 在服务 '${serverName}' 中不存在`);\n console.log(\n chalk.yellow(\n `💡 提示: 使用 'xiaozhi mcp ${serverName} list' 查看该服务的所有工具`\n )\n );\n return;\n }\n\n // 更新工具状态\n configManager.setToolEnabled(\n serverName,\n toolName,\n enabled,\n toolsConfig[toolName].description\n );\n\n spinner.succeed(\n `成功${action}工具 ${chalk.cyan(serverName)}/${chalk.cyan(toolName)}`\n );\n\n console.log();\n console.log(chalk.gray(\"💡 提示: 工具状态更改将在下次启动服务时生效\"));\n } catch (error) {\n spinner.fail(`${action}工具失败`);\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n}\n"],"mappings":";+EAEA,OAAS,SAAAA,MAAa,gBACtB,OAAOC,MAAQ,KACf,OAAOC,MAAQ,KACf,OAAOC,MAAU,OACjB,OAAS,iBAAAC,MAAqB,MAC9B,OAAOC,MAAW,QAClB,OAAS,WAAAC,OAAe,YACxB,OAAOC,MAAS,MCThB,OAAOC,OAAc,WCArB,OAAS,gBAAAC,EAAc,cAAAC,EAAY,gBAAAC,EAAc,iBAAAC,MAAqB,KACtE,OAAS,WAAAC,EAAS,WAAAC,MAAe,OACjC,OAAS,iBAAAC,OAAqB,MAG9B,IAAMC,GAAYC,EAAQC,GAAc,YAAY,GAAG,CAAC,EA4B3CC,EAAN,MAAMC,CAAc,CAjC3B,MAiC2B,CAAAC,EAAA,sBACzB,OAAe,SACP,kBACA,OAA2B,KAE3B,aAAc,CACpB,KAAK,kBAAoBC,EAAQN,GAAW,6BAA6B,CAC3E,CAKQ,mBAA4B,CAElC,IAAMO,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAChE,OAAOD,EAAQC,EAAW,qBAAqB,CACjD,CAKA,OAAc,aAA6B,CACzC,OAAKH,EAAc,WACjBA,EAAc,SAAW,IAAIA,GAExBA,EAAc,QACvB,CAKO,cAAwB,CAC7B,IAAMI,EAAa,KAAK,kBAAkB,EAC1C,OAAOC,EAAWD,CAAU,CAC9B,CAMO,YAAmB,CACxB,GAAI,CAACC,EAAW,KAAK,iBAAiB,EACpC,MAAM,IAAI,MAAM,qFAAwC,EAG1D,GAAI,KAAK,aAAa,EACpB,MAAM,IAAI,MAAM,iHAAsC,EAGxD,IAAMD,EAAa,KAAK,kBAAkB,EAC1CE,EAAa,KAAK,kBAAmBF,CAAU,EAC/C,KAAK,OAAS,IAChB,CAKQ,YAAwB,CAC9B,GAAI,CAAC,KAAK,aAAa,EACrB,MAAM,IAAI,MACR,2IACF,EAGF,GAAI,CACF,IAAMA,EAAa,KAAK,kBAAkB,EACpCG,EAAaC,EAAaJ,EAAY,MAAM,EAC5CK,EAAS,KAAK,MAAMF,CAAU,EAGpC,YAAK,eAAeE,CAAM,EAEnBA,CACT,OAASC,EAAO,CACd,MAAIA,aAAiB,YACb,IAAI,MAAM,qDAAaA,EAAM,OAAO,EAAE,EAExCA,CACR,CACF,CAKQ,eAAeD,EAAuB,CAC5C,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAI,MAAM,sFAAgB,EAGlC,IAAME,EAAYF,EAElB,GAAI,CAACE,EAAU,aAAe,OAAOA,EAAU,aAAgB,SAC7D,MAAM,IAAI,MAAM,4FAA2B,EAG7C,GAAI,CAACA,EAAU,YAAc,OAAOA,EAAU,YAAe,SAC3D,MAAM,IAAI,MAAM,2FAA0B,EAI5C,OAAW,CAACC,EAAYC,CAAY,IAAK,OAAO,QAC9CF,EAAU,UACZ,EAAG,CACD,GAAI,CAACE,GAAgB,OAAOA,GAAiB,SAC3C,MAAM,IAAI,MAAM,oEAAuBD,CAAU,eAAK,EAGxD,IAAME,EAAKD,EACX,GAAI,CAACC,EAAG,SAAW,OAAOA,EAAG,SAAY,SACvC,MAAM,IAAI,MACR,oEAAuBF,CAAU,uBACnC,EAGF,GAAI,CAAC,MAAM,QAAQE,EAAG,IAAI,EACxB,MAAM,IAAI,MACR,oEAAuBF,CAAU,sCACnC,EAGF,GAAIE,EAAG,KAAO,OAAOA,EAAG,KAAQ,SAC9B,MAAM,IAAI,MACR,oEAAuBF,CAAU,qCACnC,CAEJ,CACF,CAKO,WAAiC,CACtC,OAAK,KAAK,SACR,KAAK,OAAS,KAAK,WAAW,GAIzB,KAAK,MAAM,KAAK,UAAU,KAAK,MAAM,CAAC,CAC/C,CAKO,gBAAyB,CAE9B,OADe,KAAK,UAAU,EAChB,WAChB,CAKO,eAA2D,CAEhE,OADe,KAAK,UAAU,EAChB,UAChB,CAKO,oBAAqE,CAE1E,OADe,KAAK,UAAU,EAChB,iBAAmB,CAAC,CACpC,CAKO,qBACLA,EACyC,CAEzC,OADqB,KAAK,mBAAmB,EACzBA,CAAU,GAAG,OAAS,CAAC,CAC7C,CAKO,cAAcA,EAAoBG,EAA2B,CAGlE,OAFoB,KAAK,qBAAqBH,CAAU,EACzBG,CAAQ,GACpB,SAAW,EAChC,CAKO,kBAAkBC,EAAwB,CAC/C,GAAI,CAACA,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,kEAAgB,EAIlC,IAAMC,EAAY,CAAE,GADL,KAAK,UAAU,EACC,YAAaD,CAAS,EACrD,KAAK,WAAWC,CAAS,CAC3B,CAKO,gBACLL,EACAC,EACM,CACN,GAAI,CAACD,GAAc,OAAOA,GAAe,SACvC,MAAM,IAAI,MAAM,0EAAc,EAIhC,GAAI,CAACC,EAAa,SAAW,OAAOA,EAAa,SAAY,SAC3D,MAAM,IAAI,MAAM,qGAA0B,EAG5C,GAAI,CAAC,MAAM,QAAQA,EAAa,IAAI,EAClC,MAAM,IAAI,MAAM,gFAAoB,EAGtC,GAAIA,EAAa,KAAO,OAAOA,EAAa,KAAQ,SAClD,MAAM,IAAI,MAAM,+EAAmB,EAGrC,IAAMJ,EAAS,KAAK,UAAU,EACxBQ,EAAY,CAChB,GAAGR,EACH,WAAY,CACV,GAAGA,EAAO,WACV,CAACG,CAAU,EAAGC,CAChB,CACF,EACA,KAAK,WAAWI,CAAS,CAC3B,CAKO,gBAAgBL,EAA0B,CAC/C,GAAI,CAACA,GAAc,OAAOA,GAAe,SACvC,MAAM,IAAI,MAAM,0EAAc,EAGhC,IAAMH,EAAS,KAAK,UAAU,EAC9B,GAAI,CAACA,EAAO,WAAWG,CAAU,EAC/B,MAAM,IAAI,MAAM,gBAAMA,CAAU,qBAAM,EAGxC,IAAMM,EAAgB,CAAE,GAAGT,EAAO,UAAW,EAC7C,OAAOS,EAAcN,CAAU,EAE/B,IAAMK,EAAY,CAChB,GAAGR,EACH,WAAYS,CACd,EACA,KAAK,WAAWD,CAAS,CAC3B,CAKO,wBACLL,EACAO,EACM,CAEN,IAAMF,EAAY,CAAE,GADL,KAAK,UAAU,CACA,EAGzBA,EAAU,kBACbA,EAAU,gBAAkB,CAAC,GAI/BA,EAAU,gBAAgBL,CAAU,EAAI,CACtC,MAAOO,CACT,EAEA,KAAK,WAAWF,CAAS,CAC3B,CAKO,eACLL,EACAG,EACAK,EACAC,EACM,CAEN,IAAMJ,EAAY,CAAE,GADL,KAAK,UAAU,CACA,EAGzBA,EAAU,kBACbA,EAAU,gBAAkB,CAAC,GAI1BA,EAAU,gBAAgBL,CAAU,IACvCK,EAAU,gBAAgBL,CAAU,EAAI,CAAE,MAAO,CAAC,CAAE,GAItDK,EAAU,gBAAgBL,CAAU,EAAE,MAAMG,CAAQ,EAAI,CACtD,OAAQK,EACR,GAAIC,GAAe,CAAE,YAAAA,CAAY,CACnC,EAEA,KAAK,WAAWJ,CAAS,CAC3B,CAKQ,WAAWR,EAAyB,CAC1C,GAAI,CAEF,KAAK,eAAeA,CAAM,EAG1B,IAAML,EAAa,KAAK,kBAAkB,EACpCkB,EAAa,KAAK,UAAUb,EAAQ,KAAM,CAAC,EACjDc,EAAcnB,EAAYkB,EAAY,MAAM,EAG5C,KAAK,OAASb,CAChB,OAASC,EAAO,CACd,MAAM,IAAI,MACR,yCAAWA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKO,cAAqB,CAC1B,KAAK,OAAS,IAChB,CAKO,eAAwB,CAC7B,OAAO,KAAK,kBAAkB,CAChC,CAKO,sBAA+B,CACpC,OAAO,KAAK,iBACd,CACF,EAGac,EAAgBzB,EAAc,YAAY,EDxXvD,SAAS0B,IAA8B,CACrC,GAAI,CACF,GAAI,CAACC,EAAc,aAAa,EAC9B,MAAO,CAAC,EAEV,IAAMC,EAAaD,EAAc,cAAc,EAC/C,OAAO,OAAO,KAAKC,CAAU,CAC/B,MAAgB,CACd,MAAO,CAAC,CACV,CACF,CAVSC,EAAAH,GAAA,qBAeT,SAASI,GAAmBC,EAA8B,CACxD,GAAI,CACF,GAAI,CAACJ,EAAc,aAAa,EAC9B,MAAO,CAAC,EAEV,IAAMK,EAAcL,EAAc,qBAAqBI,CAAU,EACjE,OAAO,OAAO,KAAKC,CAAW,CAChC,MAAgB,CACd,MAAO,CAAC,CACV,CACF,CAVSH,EAAAC,GAAA,sBAeF,SAASG,GAA4B,CAE1C,IAAMC,EAAaC,GAAS,mBAAmB,EAgH/C,GA7GAD,EAAW,GAAG,UAAW,CAAC,CAAE,MAAAE,CAAM,IAAM,CACtCA,EAAM,CACJ,SACA,OACA,SACA,QACA,OACA,SACA,SACA,UACA,MACA,YACF,CAAC,CACH,CAAC,EAGDF,EAAW,GAAG,WAAY,CAACG,EAAU,CAAE,KAAAC,EAAM,OAAAC,EAAQ,MAAAH,CAAM,IAAM,CAE3D,QAAQ,IAAI,0BACd,QAAQ,MACN,6BAA6BE,CAAI,eAAeC,CAAM,iBAAiBF,CAAQ,GACjF,EAGF,IAAMG,EAAQF,EAAK,KAAK,EAAE,MAAM,KAAK,EAE/BG,EADgBH,IAASA,EAAK,KAAK,EACJE,EAAM,OAASA,EAAM,OAAS,EAGnE,GAAIA,EAAM,CAAC,IAAM,MAAO,CACtB,IAAME,EAAaF,EAAM,CAAC,EAE1B,GAAIC,IAAiB,EAAG,CAEtB,IAAME,EAAc,CAAC,OAAQ,SAAU,MAAM,EACvCC,EAAUJ,EAAM,CAAC,GAAK,GACtBK,EAAUF,EAAY,OAAQG,GAAQA,EAAI,WAAWF,CAAO,CAAC,EACnER,EAAMS,CAAO,EACb,MACF,CAEA,GAAIJ,IAAiB,EAAG,CACtB,OAAQC,EAAY,CAClB,IAAK,OAAQ,CACX,IAAMK,EAAU,CAAC,SAAS,EACpBH,EAAUJ,EAAM,CAAC,GAAK,GACtBK,EAAUE,EAAQ,OAAQC,GAAQA,EAAI,WAAWJ,CAAO,CAAC,EAC/DR,EAAMS,CAAO,EACb,KACF,CACA,IAAK,SACL,IAAK,OAAQ,CACX,IAAMI,EAAcvB,GAAkB,EAChCkB,EAAUJ,EAAM,CAAC,GAAK,GACtBK,EAAUI,EAAY,OAAQC,GAClCA,EAAK,WAAWN,CAAO,CACzB,EACAR,EAAMS,CAAO,EACb,KACF,CACA,QACET,EAAM,CAAC,CAAC,CACZ,CACA,MACF,CAEA,GAAIK,IAAiB,GAAKC,IAAe,OAAQ,CAC/C,IAAMX,EAAaS,EAAM,CAAC,EACpBW,EAAYrB,GAAmBC,CAAU,EACzCa,EAAUJ,EAAM,CAAC,GAAK,GACtBK,EAAUM,EAAU,OAAQD,GAASA,EAAK,WAAWN,CAAO,CAAC,EACnER,EAAMS,CAAO,EACb,MACF,CAEA,GAAIJ,IAAiB,GAAKC,IAAe,OAAQ,CAC/C,IAAMU,EAAU,CAAC,SAAU,SAAS,EAC9BR,EAAUJ,EAAM,CAAC,GAAK,GACtBK,EAAUO,EAAQ,OAAQC,GAAWA,EAAO,WAAWT,CAAO,CAAC,EACrER,EAAMS,CAAO,EACb,MACF,CACF,CAGA,GAAIJ,IAAiB,EAAG,CAEtB,OADgBD,EAAM,CAAC,EACN,CACf,IAAK,SACHJ,EAAM,CAAC,aAAc,IAAI,CAAC,EAC1B,MACF,IAAK,QACL,IAAK,UACHA,EAAM,CAAC,WAAY,IAAI,CAAC,EACxB,MACF,IAAK,aACHA,EAAM,CAAC,UAAW,WAAW,CAAC,EAC9B,MACF,QACEA,EAAM,CAAC,CAAC,CACZ,CACA,MACF,CAGAA,EAAM,CAAC,CAAC,CACV,CAAC,EAGG,QAAQ,KAAK,SAAS,cAAc,EAAG,CAEzC,GAAI,CACF,QAAQ,IAAIF,EAAW,mBAAmB,CAAC,CAC7C,OAASoB,EAAO,CACd,QAAQ,MAAM,sEAAgBA,CAAK,CACrC,CACA,QAAQ,KAAK,CAAC,CAChB,CAEI,QAAQ,KAAK,SAAS,mBAAmB,IAE3C,QAAQ,IAAIpB,EAAW,mBAAmB,MAAM,CAAC,EACjD,QAAQ,KAAK,CAAC,GAId,QAAQ,KAAK,SAAS,WAAW,GACjC,QAAQ,KAAK,SAAS,YAAY,EAOpCA,EAAW,KAAK,CAClB,CA5IgBL,EAAAI,EAAA,uBAiJT,SAASsB,GAA2B,CACzC,QAAQ,IAAI,wDAAmB,EAC/B,QAAQ,IAAI,EACZ,QAAQ,IAAI,+HAA2B,EACvC,QAAQ,IAAI,EACZ,QAAQ,IAAI,+BAAc,EAC1B,QAAQ,IAAI,qDAAqD,EACjE,QAAQ,IAAI,uDAAuD,EACnE,QAAQ,IAAI,mBAAmB,EAC/B,QAAQ,IAAI,EACZ,QAAQ,IAAI,iBAAU,EACtB,QAAQ,IAAI,sDAAsD,EAClE,QAAQ,IAAI,+DAA+D,EAC3E,QAAQ,IAAI,0BAA0B,EACtC,QAAQ,IAAI,EACZ,QAAQ,IAAI,iBAAU,EACtB,QAAQ,IACN,wEACF,EACA,QAAQ,IAAI,EACZ,QAAQ,IAAI,4IAA8B,EAC1C,QAAQ,IAAI,EACZ,QAAQ,IAAI,yBAAQ,EACpB,QAAQ,IAAI,yCAAoC,EAChD,QAAQ,IAAI,0CAAqC,EACjD,QAAQ,IAAI,4FAA0C,CACxD,CA1BgB1B,EAAA0B,EAAA,sBEzLhB,OAAOC,MAAW,QAClB,OAAOC,MAAW,aAClB,OAAOC,MAAS,MAUT,SAASC,EAAgBC,EAAqB,CACnD,IAAIC,EAAQ,EACZ,QAAWC,KAAQF,EAEb,4CAA4C,KAAKE,CAAI,EACvDD,GAAS,EAETA,GAAS,EAGb,OAAOA,CACT,CAXgBE,EAAAJ,EAAA,mBAgBT,SAASK,EAAgBJ,EAAaK,EAA0B,CACrE,GAAIN,EAAgBC,CAAG,GAAKK,EAC1B,OAAOL,EAIT,GAAIK,GAAY,EACd,MAAO,GAGT,IAAIC,EAAS,GACTC,EAAe,EACfC,EAAe,GAEnB,QAAWN,KAAQF,EAAK,CACtB,IAAMS,EAAY,4CAA4C,KAAKP,CAAI,EACnE,EACA,EAGJ,GAAIK,EAAeE,EAAYJ,EAAW,EAAG,CAE3C,GAAI,CAACG,EACH,MAAO,GAGTF,GAAU,MACV,KACF,CAEAA,GAAUJ,EACVK,GAAgBE,EAChBD,EAAe,EACjB,CAEA,OAAOF,CACT,CApCgBH,EAAAC,EAAA,mBAyChB,eAAsBM,EACpBC,EAA+B,CAAC,EACjB,CACf,IAAMC,EAAUC,EAAI,8CAAgB,EAAE,MAAM,EAE5C,GAAI,CACF,IAAMC,EAAaC,EAAc,cAAc,EACzCC,EAAc,OAAO,KAAKF,CAAU,EAE1C,GAAIE,EAAY,SAAW,EAAG,CAC5BJ,EAAQ,KAAK,iDAAc,EAC3B,QAAQ,IACNK,EAAM,OAAO,iGAAwC,CACvD,EACA,MACF,CAIA,GAFAL,EAAQ,QAAQ,gBAAMI,EAAY,MAAM,0BAAW,EAE/CL,EAAQ,MAAO,CAEjB,QAAQ,IAAI,EACZ,QAAQ,IAAIM,EAAM,KAAK,2CAAa,CAAC,EACrC,QAAQ,IAAI,EAGZ,IAAIC,EAAmB,EACjBC,EAAyB,CAAC,EAEhC,QAAWC,KAAcJ,EAAa,CACpC,IAAMK,EAAcN,EAAc,qBAAqBK,CAAU,EAC3DE,EAAY,OAAO,KAAKD,CAAW,EACzCF,EAAa,KAAK,GAAGG,CAAS,CAChC,CAGA,QAAWC,KAAYJ,EAAc,CACnC,IAAMlB,EAAQF,EAAgBwB,CAAQ,EAClCtB,EAAQiB,IACVA,EAAmBjB,EAEvB,CAGAiB,EAAmB,KAAK,IAAI,GAAI,KAAK,IAAIA,EAAmB,EAAG,EAAE,CAAC,EAGlE,IAAMM,EAAQ,IAAIC,EAAM,CACtB,KAAM,CACJR,EAAM,KAAK,KAAK,EAChBA,EAAM,KAAK,0BAAM,EACjBA,EAAM,KAAK,cAAI,EACfA,EAAM,KAAK,cAAI,CACjB,EACA,UAAW,CAAC,GAAIC,EAAkB,EAAG,EAAE,EACvC,SAAU,GACV,MAAO,CACL,KAAM,CAAC,EACP,OAAQ,CAAC,CACX,CACF,CAAC,EAED,QAAWE,KAAcJ,EAAa,CACpC,IAAMK,EAAcN,EAAc,qBAAqBK,CAAU,EAC3DE,EAAY,OAAO,KAAKD,CAAW,EAEzC,GAAIC,EAAU,SAAW,EAEvBE,EAAM,KAAK,CACTP,EAAM,KAAKG,CAAU,EACrBH,EAAM,KAAK,sBAAO,EAClBA,EAAM,KAAK,GAAG,EACdA,EAAM,KAAK,8DAAY,CACzB,CAAC,MACI,CAEDO,EAAM,OAAS,GACjBA,EAAM,KAAK,CAAC,CAAE,QAAS,EAAG,QAAS,EAAG,CAAC,CAAC,EAG1C,QAAWD,KAAYD,EAAW,CAChC,IAAMI,EAAaL,EAAYE,CAAQ,EACjCI,EAASD,EAAW,OACtBT,EAAM,MAAM,cAAI,EAChBA,EAAM,IAAI,cAAI,EAGZW,EAAcxB,EAClBsB,EAAW,aAAe,GAC1B,EACF,EAGAF,EAAM,KAAK,CAACJ,EAAYG,EAAUI,EAAQC,CAAW,CAAC,CACxD,CACF,CACF,CAEA,QAAQ,IAAIJ,EAAM,SAAS,CAAC,CAC9B,KAAO,CAEL,QAAQ,IAAI,EACZ,QAAQ,IAAIP,EAAM,KAAK,+BAAW,CAAC,EACnC,QAAQ,IAAI,EAEZ,QAAWG,KAAcJ,EAAa,CACpC,IAAMa,EAAef,EAAWM,CAAU,EACpCC,EAAcN,EAAc,qBAAqBK,CAAU,EAC3DU,EAAY,OAAO,KAAKT,CAAW,EAAE,OACrCU,EAAe,OAAO,OAAOV,CAAW,EAAE,OAC7CW,GAAMA,EAAE,SAAW,EACtB,EAAE,OAEF,QAAQ,IAAI,GAAGf,EAAM,KAAK,QAAG,CAAC,IAAIA,EAAM,KAAKG,CAAU,CAAC,EAAE,EAC1D,QAAQ,IACN,mBAASH,EAAM,KAAKY,EAAa,OAAO,CAAC,IAAIZ,EAAM,KACjDY,EAAa,KAAK,KAAK,GAAG,CAC5B,CAAC,EACH,EACIC,EAAY,EACd,QAAQ,IACN,mBAASb,EAAM,MAAMc,CAAY,CAAC,mBAASd,EAAM,OAC/Ca,CACF,CAAC,eACH,EAEA,QAAQ,IAAI,mBAASb,EAAM,KAAK,2DAAc,CAAC,EAAE,EAEnD,QAAQ,IAAI,CACd,CACF,CAEA,QAAQ,IAAIA,EAAM,KAAK,yBAAQ,CAAC,EAChC,QAAQ,IAAIA,EAAM,KAAK,kFAA0C,CAAC,EAClE,QAAQ,IACNA,EAAM,KAAK,iHAA2C,CACxD,EACA,QAAQ,IACNA,EAAM,KACJ,+HACF,CACF,CACF,OAASgB,EAAO,CACdrB,EAAQ,KAAK,uDAAe,EAC5B,QAAQ,MACNK,EAAM,IACJ,iBAAOgB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EAC/D,CACF,EACA,QAAQ,KAAK,CAAC,CAChB,CACF,CAvJsB9B,EAAAO,EAAA,kBA4JtB,eAAsBwB,EAAgBd,EAAmC,CACvE,IAAMR,EAAUC,EAAI,gBAAMO,CAAU,gDAAa,EAAE,MAAM,EAEzD,GAAI,CAGF,GAAI,CAFeL,EAAc,cAAc,EAE/BK,CAAU,EAAG,CAC3BR,EAAQ,KAAK,iBAAOQ,CAAU,sBAAO,EACrC,QAAQ,IACNH,EAAM,OAAO,0GAAuC,CACtD,EACA,MACF,CAEA,IAAMI,EAAcN,EAAc,qBAAqBK,CAAU,EAC3DE,EAAY,OAAO,KAAKD,CAAW,EAEzC,GAAIC,EAAU,SAAW,EAAG,CAC1BV,EAAQ,KAAK,iBAAOQ,CAAU,wCAAU,EACxC,QAAQ,IAAIH,EAAM,OAAO,wGAAsB,CAAC,EAChD,MACF,CAEAL,EAAQ,QAAQ,iBAAOQ,CAAU,kBAAQE,EAAU,MAAM,qBAAM,EAE/D,QAAQ,IAAI,EACZ,QAAQ,IAAIL,EAAM,KAAK,GAAGG,CAAU,wCAAU,CAAC,EAC/C,QAAQ,IAAI,EAGZ,IAAMI,EAAQ,IAAIC,EAAM,CACtB,KAAM,CAACR,EAAM,KAAK,0BAAM,EAAGA,EAAM,KAAK,cAAI,EAAGA,EAAM,KAAK,cAAI,CAAC,EAC7D,UAAW,CAAC,GAAI,EAAG,EAAE,EACrB,SAAU,GACV,MAAO,CACL,KAAM,CAAC,EACP,OAAQ,CAAC,CACX,CACF,CAAC,EAED,QAAWM,KAAYD,EAAW,CAChC,IAAMI,EAAaL,EAAYE,CAAQ,EACjCI,EAASD,EAAW,OACtBT,EAAM,MAAM,cAAI,EAChBA,EAAM,IAAI,cAAI,EAGZW,EAAcxB,EAAgBsB,EAAW,aAAe,GAAI,EAAE,EAEpEF,EAAM,KAAK,CAACD,EAAUI,EAAQC,CAAW,CAAC,CAC5C,CAEA,QAAQ,IAAIJ,EAAM,SAAS,CAAC,EAE5B,QAAQ,IAAI,EACZ,QAAQ,IAAIP,EAAM,KAAK,yBAAQ,CAAC,EAChC,QAAQ,IACNA,EAAM,KACJ,iCAAuBG,CAAU,wDACnC,CACF,EACA,QAAQ,IACNH,EAAM,KACJ,iCAAuBG,CAAU,yDACnC,CACF,CACF,OAASa,EAAO,CACdrB,EAAQ,KAAK,kDAAU,EACvB,QAAQ,MACNK,EAAM,IACJ,iBAAOgB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EAC/D,CACF,EACA,QAAQ,KAAK,CAAC,CAChB,CACF,CA3EsB9B,EAAA+B,EAAA,mBAgFtB,eAAsBC,EACpBf,EACAG,EACAa,EACe,CACf,IAAMC,EAASD,EAAU,eAAO,eAC1BxB,EAAUC,EAAI,GAAGwB,CAAM,gBAAMjB,CAAU,IAAIG,CAAQ,KAAK,EAAE,MAAM,EAEtE,GAAI,CAGF,GAAI,CAFeR,EAAc,cAAc,EAE/BK,CAAU,EAAG,CAC3BR,EAAQ,KAAK,iBAAOQ,CAAU,sBAAO,EACrC,QAAQ,IACNH,EAAM,OAAO,0GAAuC,CACtD,EACA,MACF,CAEA,IAAMI,EAAcN,EAAc,qBAAqBK,CAAU,EAEjE,GAAI,CAACC,EAAYE,CAAQ,EAAG,CAC1BX,EAAQ,KAAK,iBAAOW,CAAQ,yBAAUH,CAAU,4BAAQ,EACxD,QAAQ,IACNH,EAAM,OACJ,qDAA0BG,CAAU,qEACtC,CACF,EACA,MACF,CAGAL,EAAc,eACZK,EACAG,EACAa,EACAf,EAAYE,CAAQ,EAAE,WACxB,EAEAX,EAAQ,QACN,eAAKyB,CAAM,gBAAMpB,EAAM,KAAKG,CAAU,CAAC,IAAIH,EAAM,KAAKM,CAAQ,CAAC,EACjE,EAEA,QAAQ,IAAI,EACZ,QAAQ,IAAIN,EAAM,KAAK,gIAA0B,CAAC,CACpD,OAASgB,EAAO,CACdrB,EAAQ,KAAK,GAAGyB,CAAM,0BAAM,EAC5B,QAAQ,MACNpB,EAAM,IACJ,iBAAOgB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EAC/D,CACF,EACA,QAAQ,KAAK,CAAC,CAChB,CACF,CAtDsB9B,EAAAgC,EAAA,kBHnStB,IAAMG,EAAU,IAAIC,GACdC,EAAe,sBAKd,SAASC,GAAqB,CACnC,GAAI,CAEF,IAAMC,EAAaC,EAAc,YAAY,GAAG,EAC1CC,EAAaC,EAAK,QAAQH,CAAU,EAGpCI,EAAgB,CAEpBD,EAAK,KAAKD,EAAY,KAAM,cAAc,EAE1CC,EAAK,KAAKD,EAAY,KAAM,cAAc,EAE1CC,EAAK,KAAKD,EAAY,KAAM,KAAM,cAAc,EAEhDC,EAAK,KAAKD,EAAY,cAAc,CACtC,EAEA,QAAWG,KAAeD,EACxB,GAAIE,EAAG,WAAWD,CAAW,EAAG,CAC9B,IAAME,EAAc,KAAK,MAAMD,EAAG,aAAaD,EAAa,MAAM,CAAC,EACnE,GAAIE,EAAY,QACd,OAAOA,EAAY,OAEvB,CAIF,MAAO,SACT,OAASC,EAAO,CACd,eAAQ,KAAK,qDAAsDA,CAAK,EACjE,SACT,CACF,CAjCgBC,EAAAV,EAAA,cAoChB,IAAMW,EAAWP,EAAK,KAAKQ,EAAG,OAAO,EAAG,GAAGb,CAAY,MAAM,EACvDc,EAAWT,EAAK,KAAKQ,EAAG,OAAO,EAAG,GAAGb,CAAY,MAAM,EAYtD,SAASe,GAAkC,CAChD,GAAI,CACF,GAAI,CAACP,EAAG,WAAWI,CAAQ,EACzB,MAAO,CAAE,QAAS,EAAM,EAG1B,IAAMI,EAAaR,EAAG,aAAaI,EAAU,MAAM,EAAE,KAAK,EACpD,CAACK,EAAQC,EAAWC,CAAI,EAAIH,EAAW,MAAM,GAAG,EAChDI,EAAM,OAAO,SAASH,CAAM,EAElC,GAAI,OAAO,MAAMG,CAAG,EAElB,OAAAZ,EAAG,WAAWI,CAAQ,EACf,CAAE,QAAS,EAAM,EAI1B,GAAI,CACF,QAAQ,KAAKQ,EAAK,CAAC,EAGnB,IAAMC,EAAQ,OAAO,SAASH,CAAS,EACjCI,EAASC,GAAa,KAAK,IAAI,EAAIF,CAAK,EAE9C,MAAO,CACL,QAAS,GACT,IAAAD,EACA,OAAAE,EACA,KAAOH,GAAoC,YAC7C,CACF,MAAgB,CAEd,OAAAX,EAAG,WAAWI,CAAQ,EACf,CAAE,QAAS,EAAM,CAC1B,CACF,MAAgB,CACd,MAAO,CAAE,QAAS,EAAM,CAC1B,CACF,CAtCgBD,EAAAI,EAAA,oBA2CT,SAASQ,GAAaC,EAAoB,CAC/C,IAAMC,EAAU,KAAK,MAAMD,EAAK,GAAI,EAC9BE,EAAU,KAAK,MAAMD,EAAU,EAAE,EACjCE,EAAQ,KAAK,MAAMD,EAAU,EAAE,EAC/BE,EAAO,KAAK,MAAMD,EAAQ,EAAE,EAElC,OAAIC,EAAO,EACF,GAAGA,CAAI,UAAKD,EAAQ,EAAE,gBAAMD,EAAU,EAAE,eAE7CC,EAAQ,EACH,GAAGA,CAAK,gBAAMD,EAAU,EAAE,eAE/BA,EAAU,EACL,GAAGA,CAAO,gBAAMD,EAAU,EAAE,SAE9B,GAAGA,CAAO,QACnB,CAhBgBd,EAAAY,GAAA,gBAqBhB,SAASM,EAAYT,EAAaD,EAA+B,CAC/D,IAAMW,EAAU,GAAGV,CAAG,IAAI,KAAK,IAAI,CAAC,IAAID,CAAI,GAC5CX,EAAG,cAAcI,EAAUkB,CAAO,CACpC,CAHSnB,EAAAkB,EAAA,eAQT,SAASE,GAAiB,CACxB,GAAI,CACEvB,EAAG,WAAWI,CAAQ,GACxBJ,EAAG,WAAWI,CAAQ,CAE1B,MAAgB,CAEhB,CACF,CARSD,EAAAoB,EAAA,kBAaF,SAASC,IAA4B,CAE1C,GAAI,CAACC,EAAc,aAAa,EAC9B,eAAQ,MAAMC,EAAM,IAAI,iEAAe,CAAC,EACxC,QAAQ,IAAIA,EAAM,OAAO,0FAAiC,CAAC,EACpD,GAGT,GAAI,CAEF,IAAMC,EAAWF,EAAc,eAAe,EAC9C,MAAI,CAACE,GAAYA,EAAS,SAAS,qBAAM,GACvC,QAAQ,MAAMD,EAAM,IAAI,yDAAiB,CAAC,EAC1C,QAAQ,IACNA,EAAM,OACJ,sHACF,CACF,EACO,IAEF,EACT,OAASxB,EAAO,CACd,eAAQ,MACNwB,EAAM,IACJ,+DACExB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,EACA,QAAQ,IAAIwB,EAAM,OAAO,sGAAmC,CAAC,EACtD,EACT,CACF,CAhCgBvB,EAAAqB,GAAA,oBAqChB,SAASI,IAAsE,CAE7E,IAAMC,EAAYhC,EAAK,QAAQF,EAAc,YAAY,GAAG,CAAC,EAGzDmC,EACJ,OAAID,EAAU,SAAS,cAAc,EAEnCC,EAAUD,EAaVC,EARsB,CACpBjC,EAAK,KAAKgC,EAAW,KAAM,UAAW,MAAM,EAC5ChC,EAAK,KAAKgC,EAAW,KAAM,KAAM,UAAW,MAAM,EAClDhC,EAAK,KAAKgC,EAAW,KAAM,KAAM,KAAM,UAAW,MAAM,EACxDhC,EAAK,KAAK,QAAQ,IAAI,EAAG,UAAW,MAAM,EAC1CA,EAAK,KAAK,QAAQ,IAAI,EAAG,MAAM,CACjC,EAGgB,KACXkC,GACC/B,EAAG,WAAWH,EAAK,KAAKkC,EAAG,YAAY,CAAC,GACxC/B,EAAG,WAAWH,EAAK,KAAKkC,EAAG,mBAAmB,CAAC,CACnD,GAAKF,EAGF,CACL,QAAS,OACT,KAAM,CAAC,aAAc,mBAAmB,EACxC,IAAKC,CACP,CACF,CAlCS3B,EAAAyB,GAAA,qBAuCT,eAAeI,EAAaC,EAAS,GAAsB,CACzD,IAAMC,EAAUC,EAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CAEF,IAAMC,EAAS7B,EAAiB,EAChC,GAAI6B,EAAO,QAAS,CAClBF,EAAQ,KAAK,oDAAiBE,EAAO,GAAG,GAAG,EAC3C,MACF,CAIA,GADAF,EAAQ,KAAO,0CACX,CAACV,GAAiB,EAAG,CACvBU,EAAQ,KAAK,kDAAU,EACvB,MACF,CAGA,GAAM,CAAE,QAAAG,EAAS,KAAAC,EAAM,IAAAC,CAAI,EAAIX,GAAkB,EAIjD,GAFAM,EAAQ,KAAO,6BAASD,EAAS,2BAAS,0BAAM,OAE5CA,EAAQ,CAEV,IAAMO,EAAQC,EAAMJ,EAASC,EAAM,CACjC,IAAAC,EACA,SAAU,GACV,MAAO,CAAC,SAAU,OAAQ,MAAM,EAChC,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,CAClC,CACF,CAAC,EAGDlB,EAAYmB,EAAM,IAAM,QAAQ,EAGhC,IAAME,EAAY1C,EAAG,kBAAkBM,EAAU,CAAE,MAAO,GAAI,CAAC,EAC/DkC,EAAM,QAAQ,KAAKE,CAAS,EAC5BF,EAAM,QAAQ,KAAKE,CAAS,EAG5BF,EAAM,MAAM,EAEZN,EAAQ,QAAQ,0DAAkBM,EAAM,GAAG,GAAG,EAC9C,QAAQ,IAAId,EAAM,KAAK,6BAASpB,CAAQ,EAAE,CAAC,EAC3C,QAAQ,IAAIoB,EAAM,KAAK,gFAA8B,CAAC,CACxD,KAAO,CAELQ,EAAQ,QAAQ,mCAAU,EAE1B,IAAMM,EAAQC,EAAMJ,EAASC,EAAM,CACjC,IAAAC,EACA,MAAO,UACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,CAClC,CACF,CAAC,EAGDlB,EAAYmB,EAAM,IAAM,YAAY,EAGpCA,EAAM,GAAG,OAAQ,CAACG,EAAMC,IAAW,CACjCrB,EAAe,EAEb,QAAQ,IADNoB,IAAS,EAETjB,EAAM,IAAI;AAAA,sDAAiBiB,CAAI,mBAASC,CAAM,GAAG,EAGvClB,EAAM,MAAM;AAAA,+BAAS,CAFjC,CAIJ,CAAC,EAGD,QAAQ,GAAG,SAAU,IAAM,CACzB,QAAQ,IAAIA,EAAM,OAAO;AAAA,wCAAa,CAAC,EACvCc,EAAM,KAAK,SAAS,CACtB,CAAC,EAED,QAAQ,GAAG,UAAW,IAAM,CAC1BA,EAAM,KAAK,SAAS,CACtB,CAAC,CACH,CACF,OAAStC,EAAO,CACdgC,EAAQ,KACN,yCAAWhC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CA5FeC,EAAA6B,EAAA,gBAiGf,eAAea,GAA6B,CAC1C,IAAMX,EAAUC,EAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CACF,IAAMC,EAAS7B,EAAiB,EAEhC,GAAI,CAAC6B,EAAO,QAAS,CACnBF,EAAQ,KAAK,sCAAQ,EACrB,MACF,CAEAA,EAAQ,KAAO,kCAAcE,EAAO,GAAG,OAEvC,GAAI,CAEF,QAAQ,KAAKA,EAAO,IAAM,SAAS,EAGnC,IAAIU,EAAW,EACTC,EAAc,GAEpB,KAAOD,EAAWC,GAAa,CAC7B,MAAM,IAAI,QAASC,GAAY,WAAWA,EAAS,GAAG,CAAC,EAEvD,GAAI,CACF,QAAQ,KAAKZ,EAAO,IAAM,CAAC,EAC3BU,GACF,MAAQ,CAEN,KACF,CACF,CAGA,GAAI,CACF,QAAQ,KAAKV,EAAO,IAAM,CAAC,EAE3BF,EAAQ,KAAO,0CACf,QAAQ,KAAKE,EAAO,IAAM,SAAS,EACnC,MAAM,IAAI,QAASY,GAAY,WAAWA,EAAS,GAAG,CAAC,CACzD,MAAQ,CAER,CAEAzB,EAAe,EACfW,EAAQ,QAAQ,gCAAO,CACzB,OAAShC,EAAO,CACdqB,EAAe,EACfW,EAAQ,KACN,yCACEhC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,OAASA,EAAO,CACdgC,EAAQ,KACN,yCAAWhC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CA3DeC,EAAA0C,EAAA,eAgEf,eAAeI,IAA6B,CAC1C,IAAMf,EAAUC,EAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CACF,IAAMC,EAAS7B,EAAiB,EAE5B6B,EAAO,SACTF,EAAQ,QAAQ,0BAAM,EACtB,QAAQ,IAAIR,EAAM,MAAM,6CAAU,CAAC,EACnC,QAAQ,IAAIA,EAAM,KAAK,WAAWU,EAAO,GAAG,EAAE,CAAC,EAC/C,QAAQ,IAAIV,EAAM,KAAK,gCAAYU,EAAO,MAAM,EAAE,CAAC,EACnD,QAAQ,IACNV,EAAM,KACJ,gCAAYU,EAAO,OAAS,SAAW,2BAAS,0BAAM,EACxD,CACF,EAEIA,EAAO,OAAS,UAClB,QAAQ,IAAIV,EAAM,KAAK,gCAAYpB,CAAQ,EAAE,CAAC,IAGhD4B,EAAQ,QAAQ,0BAAM,EACtB,QAAQ,IAAIR,EAAM,IAAI,uCAAS,CAAC,EAEpC,OAASxB,EAAO,CACdgC,EAAQ,KACN,yCAAWhC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CA7BeC,EAAA8C,GAAA,eAkCf,eAAeC,IAA+B,CAC5C,IAAMhB,EAAUC,EAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CACF,IAAMC,EAAS7B,EAAiB,EAEhC,GAAI,CAAC6B,EAAO,QAAS,CACnBF,EAAQ,KAAK,sCAAQ,EACrB,MACF,CAEA,GAAIE,EAAO,OAAS,SAAU,CAC5BF,EAAQ,KAAK,oEAAa,EAC1B,MACF,CAQA,GANAA,EAAQ,QAAQ,+CAAY,EAC5B,QAAQ,IAAIR,EAAM,MAAM,8CAAgBU,EAAO,GAAG,GAAG,CAAC,EACtD,QAAQ,IAAIV,EAAM,KAAK,oGAAyB,CAAC,EACjD,QAAQ,IAAIA,EAAM,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC,EAGlC1B,EAAG,WAAWM,CAAQ,EAExB,GAAI,QAAQ,WAAa,QAAS,CAEhC,GAAM,CAAE,MAAAmC,CAAM,EAAI,KAAM,QAAO,eAAoB,EAC7CU,EAAOV,EACX,aACA,CAAC,WAAY,sBAAsBnC,CAAQ,SAAS,EACpD,CAAE,MAAO,SAAU,CACrB,EAGA,QAAQ,GAAG,SAAU,IAAM,CACzB,QAAQ,IAAIoB,EAAM,OAAO;AAAA,qFAAkB,CAAC,EAC5CyB,EAAK,KAAK,EACV,QAAQ,KAAK,CAAC,CAChB,CAAC,EAEDA,EAAK,GAAG,OAAQ,IAAM,CACpB,QAAQ,KAAK,CAAC,CAChB,CAAC,CACH,KAAO,CAEL,GAAM,CAAE,MAAAV,CAAM,EAAI,KAAM,QAAO,eAAoB,EAC7CU,EAAOV,EAAM,OAAQ,CAAC,KAAMnC,CAAQ,EAAG,CAAE,MAAO,SAAU,CAAC,EAGjE,QAAQ,GAAG,SAAU,IAAM,CACzB,QAAQ,IAAIoB,EAAM,OAAO;AAAA,qFAAkB,CAAC,EAC5CyB,EAAK,KAAK,EACV,QAAQ,KAAK,CAAC,CAChB,CAAC,EAEDA,EAAK,GAAG,OAAQ,IAAM,CACpB,QAAQ,KAAK,CAAC,CAChB,CAAC,CACH,MAEA,QAAQ,IAAIzB,EAAM,OAAO,4CAAS,CAAC,CAEvC,OAASxB,EAAO,CACdgC,EAAQ,KACN,6BAAShC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACjE,CACF,CACF,CAnEeC,EAAA+C,GAAA,iBAwEf,eAAeE,GAAenB,EAAS,GAAsB,CAC3D,QAAQ,IAAIP,EAAM,KAAK,uCAAY,CAAC,EAGpC,MAAMmB,EAAY,EAGlB,MAAM,IAAI,QAASG,GAAY,WAAWA,EAAS,GAAI,CAAC,EAGxD,MAAMhB,EAAaC,CAAM,CAC3B,CAXe9B,EAAAiD,GAAA,kBAgBf,SAASC,IAAyB,CAChC,IAAMC,EAAU7D,EAAW,EAC3B,QAAQ,IAAIiC,EAAM,KAAK,YAAY4B,CAAO,EAAE,CAAC,EAC7C,QAAQ,IAAI5B,EAAM,KAAK,iCAAiC,CAAC,EACzD,QAAQ,IAAIA,EAAM,KAAK,mCAAmC,CAAC,EAC3D,QAAQ,IAAIA,EAAM,KAAK,YAAY,QAAQ,OAAO,EAAE,CAAC,EACrD,QAAQ,IAAIA,EAAM,KAAK,aAAa,QAAQ,QAAQ,IAAI,QAAQ,IAAI,EAAE,CAAC,CACzE,CAPSvB,EAAAkD,GAAA,oBAYT,eAAeE,IAA4B,CACzC,IAAMrB,EAAUC,EAAI,mCAAU,EAAE,MAAM,EAEtC,GAAI,CACF,GAAIV,EAAc,aAAa,EAAG,CAChCS,EAAQ,KAAK,4CAAS,EACtB,QAAQ,IACNR,EAAM,OAAO,6HAAwC,CACvD,EACA,MACF,CAEAD,EAAc,WAAW,EACzBS,EAAQ,QAAQ,wDAAW,EAE3B,QAAQ,IAAIR,EAAM,MAAM,wEAAgC,CAAC,EACzD,QAAQ,IAAIA,EAAM,OAAO,gGAAwB,CAAC,EAClD,QAAQ,IACNA,EAAM,KAAK,4CAAcD,EAAc,cAAc,CAAC,EAAE,CAC1D,EACA,QAAQ,IAAIC,EAAM,OAAO,6DAAc,CAAC,EACxC,QAAQ,IACNA,EAAM,KAAK,mDAAmD,CAChE,CACF,OAASxB,EAAO,CACdgC,EAAQ,KACN,+CACEhC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,CA/BeC,EAAAoD,GAAA,cAoCf,SAASC,IAAkC,CACzC,IAAM3B,EAAYhC,EAAK,QAAQF,EAAc,YAAY,GAAG,CAAC,EAOvD8D,EANgB,CACpB5D,EAAK,KAAKgC,EAAW,KAAM,WAAW,EACtChC,EAAK,KAAKgC,EAAW,WAAW,EAChChC,EAAK,KAAKgC,EAAW,KAAM,KAAM,WAAW,CAC9C,EAEmC,KAAME,GAAM/B,EAAG,WAAW+B,CAAC,CAAC,EAC/D,OAAK0B,EAIEzD,EAAG,YAAYyD,CAAY,EAAE,OAAQC,GAAS,CACnD,IAAMC,EAAW9D,EAAK,KAAK4D,EAAcC,CAAI,EAC7C,OAAO1D,EAAG,SAAS2D,CAAQ,EAAE,YAAY,CAC3C,CAAC,EANQ,CAAC,CAOZ,CAjBSxD,EAAAqD,GAAA,yBAsBF,SAASI,EAAoBC,EAAcC,EAAsB,CACtE,IAAMC,EAAOF,EAAK,OACZG,EAAOF,EAAK,OACZG,EAAS,MAAMF,EAAO,CAAC,EAC1B,KAAK,IAAI,EACT,IAAI,IAAM,MAAMC,EAAO,CAAC,EAAE,KAAK,CAAC,CAAC,EAEpC,QAASE,EAAI,EAAGA,GAAKH,EAAMG,IAAKD,EAAOC,CAAC,EAAE,CAAC,EAAIA,EAC/C,QAASC,EAAI,EAAGA,GAAKH,EAAMG,IAAKF,EAAO,CAAC,EAAEE,CAAC,EAAIA,EAE/C,QAASD,EAAI,EAAGA,GAAKH,EAAMG,IACzB,QAASC,EAAI,EAAGA,GAAKH,EAAMG,IACrBN,EAAKK,EAAI,CAAC,IAAMJ,EAAKK,EAAI,CAAC,EAC5BF,EAAOC,CAAC,EAAEC,CAAC,EAAIF,EAAOC,EAAI,CAAC,EAAEC,EAAI,CAAC,EAElCF,EAAOC,CAAC,EAAEC,CAAC,EAAI,KAAK,IAClBF,EAAOC,EAAI,CAAC,EAAEC,CAAC,EAAI,EACnBF,EAAOC,CAAC,EAAEC,EAAI,CAAC,EAAI,EACnBF,EAAOC,EAAI,CAAC,EAAEC,EAAI,CAAC,EAAI,CACzB,EAKN,IAAMC,EAAS,KAAK,IAAIL,EAAMC,CAAI,EAClC,OAAOI,IAAW,EAAI,GAAKA,EAASH,EAAOF,CAAI,EAAEC,CAAI,GAAKI,CAC5D,CA1BgBjE,EAAAyD,EAAA,uBA+BhB,SAASS,GACPC,EACAC,EACe,CACf,GAAIA,EAAU,SAAW,EAAG,OAAO,KAEnC,IAAIC,EAAYD,EAAU,CAAC,EACvBE,EAAiBb,EACnBU,EAAM,YAAY,EAClBE,EAAU,YAAY,CACxB,EAEA,QAAWE,KAAYH,EAAU,MAAM,CAAC,EAAG,CACzC,IAAMI,EAAaf,EACjBU,EAAM,YAAY,EAClBI,EAAS,YAAY,CACvB,EACIC,EAAaF,IACfA,EAAiBE,EACjBH,EAAYE,EAEhB,CAGA,OAAOD,EAAiB,GAAMD,EAAY,IAC5C,CAzBSrE,EAAAkE,GAAA,uBA8BT,eAAeO,GAAoBC,EAAoC,CAErE,GAAI,CAAC,QAAQ,MAAM,MAEjB,eAAQ,IAAI,0CAAY,EACjB,GAIT,IAAMC,EAAW,KAAM,QAAO,UAAe,EAE7C,OAAO,IAAI,QAAS9B,GAAY,CAC9B,QAAQ,OAAO,MAAM6B,CAAQ,EAE7B,IAAME,EAAKD,EAAS,gBAAgB,CAClC,MAAO,QAAQ,MACf,OAAQ,QAAQ,MAClB,CAAC,EAEKE,EAAc7E,EAACmE,GAAkB,CACrC,IAAMW,EAAOX,EAAM,KAAK,EAAE,YAAY,EAClCW,IAAS,KAAOA,IAAS,OAC3BF,EAAG,MAAM,EACT/B,EAAQ,EAAI,GACHiC,IAAS,KAAOA,IAAS,MAAQA,IAAS,IACnDF,EAAG,MAAM,EACT/B,EAAQ,EAAK,GAGb,QAAQ,OAAO,MAAM,iCAAa,CAEtC,EAZoB,eAcpB+B,EAAG,GAAG,OAAQC,CAAW,EACzBD,EAAG,GAAG,SAAU,IAAM,CACpBA,EAAG,MAAM,EACT/B,EAAQ,EAAK,CACf,CAAC,CACH,CAAC,CACH,CAvCe7C,EAAAyE,GAAA,uBA4Cf,SAASM,GAAkBC,EAA2B,CACpD,IAAMC,EAAgB,CACpB,YAAa,sHACb,WAAY,CAAC,CACf,EAEMC,EAAaxF,EAAK,KAAKsF,EAAa,qBAAqB,EAC/DnF,EAAG,cAAcqF,EAAY,KAAK,UAAUD,EAAe,KAAM,CAAC,EAAG,MAAM,CAC7E,CARSjF,EAAA+E,GAAA,qBAaT,eAAeI,GACbC,EACAC,EACe,CACf,IAAMtD,EAAUC,EAAI,mCAAU,EAAE,MAAM,EAEtC,GAAI,CAEF,IAAMsD,EAAa5F,EAAK,KAAK,QAAQ,IAAI,EAAG0F,CAAW,EAGvD,GAAIvF,EAAG,WAAWyF,CAAU,EAAG,CAC7BvD,EAAQ,KAAK,iBAAOqD,CAAW,sBAAO,EACtC,QAAQ,IAAI7D,EAAM,OAAO,gIAA0B,CAAC,EACpD,MACF,CAEA,GAAI8D,EAAQ,SAAU,CAEpBtD,EAAQ,KAAO,8BAGf,IAAMwD,EAAqBlC,GAAsB,EAEjD,GAAIkC,EAAmB,SAAW,EAAG,CACnCxD,EAAQ,KAAK,2CAAkB,EAC/B,QAAQ,IAAIR,EAAM,OAAO,oFAAgC,CAAC,EAC1D,MACF,CAGA,GAAI,CAACgE,EAAmB,SAASF,EAAQ,QAAQ,EAAG,CAClDtD,EAAQ,KAAK,iBAAOsD,EAAQ,QAAQ,sBAAO,EAG3C,IAAMG,EAAkBtB,GACtBmB,EAAQ,SACRE,CACF,EAEA,GAAIC,EAQF,GAPA,QAAQ,IACNjE,EAAM,OAAO,yDAAeiE,CAAe,gBAAM,CACnD,EACkB,MAAMf,GACtBlD,EAAM,KAAK,yDAAiB,CAC9B,EAGE8D,EAAQ,SAAWG,MACd,CACL,QAAQ,IAAIjE,EAAM,OAAO,iCAAQ,CAAC,EAClC,QAAWgD,KAAYgB,EACrB,QAAQ,IAAIhE,EAAM,KAAK,OAAOgD,CAAQ,EAAE,CAAC,EAE3C,MACF,KACK,CACL,QAAQ,IAAIhD,EAAM,OAAO,iCAAQ,CAAC,EAClC,QAAWgD,KAAYgB,EACrB,QAAQ,IAAIhE,EAAM,KAAK,OAAOgD,CAAQ,EAAE,CAAC,EAE3C,MACF,CACF,CAGA,IAAM7C,EAAYhC,EAAK,QAAQF,EAAc,YAAY,GAAG,CAAC,EAMvD8D,EALgB,CACpB5D,EAAK,KAAKgC,EAAW,KAAM,WAAW,EACtChC,EAAK,KAAKgC,EAAW,WAAW,EAChChC,EAAK,KAAKgC,EAAW,KAAM,KAAM,WAAW,CAC9C,EACmC,KAAME,GAAM/B,EAAG,WAAW+B,CAAC,CAAC,EACzD6D,EAAe/F,EAAK,KAAK4D,EAAc+B,EAAQ,QAAQ,EAE7DtD,EAAQ,KAAO,uBAAQsD,EAAQ,QAAQ,+BAAWD,CAAW,OAG7DM,EAAcD,EAAcH,EAAY,CACtC,eACA,kBACA,gBACF,CAAC,EAEDvD,EAAQ,QAAQ,iBAAOqD,CAAW,4BAAQ,EAE1C,QAAQ,IAAI7D,EAAM,MAAM,8CAAW,CAAC,EACpC,QAAQ,IAAIA,EAAM,OAAO,iDAAY,CAAC,EACtC,QAAQ,IAAIA,EAAM,KAAK,SAAS6D,CAAW,EAAE,CAAC,EAC9C,QAAQ,IAAI7D,EAAM,KAAK,6CAAyB,CAAC,EACjD,QAAQ,IACNA,EAAM,KAAK,iFAAyC,CACtD,EACA,QAAQ,IAAIA,EAAM,KAAK,8CAA0B,CAAC,CACpD,MAEEQ,EAAQ,KAAO,yCAAWqD,CAAW,OAGrCvF,EAAG,UAAUyF,EAAY,CAAE,UAAW,EAAK,CAAC,EAG5CP,GAAkBO,CAAU,EAE5BvD,EAAQ,QAAQ,iBAAOqD,CAAW,4BAAQ,EAE1C,QAAQ,IAAI7D,EAAM,MAAM,0DAAa,CAAC,EACtC,QAAQ,IAAIA,EAAM,OAAO,iDAAY,CAAC,EACtC,QAAQ,IAAIA,EAAM,KAAK,SAAS6D,CAAW,EAAE,CAAC,EAC9C,QAAQ,IACN7D,EAAM,KAAK,mGAA4C,CACzD,EACA,QAAQ,IAAIA,EAAM,KAAK,8CAA0B,CAAC,EAClD,QAAQ,IACNA,EAAM,OAAO,oHAAkC,CACjD,CAEJ,OAASxB,EAAO,CACdgC,EAAQ,KACN,yCAAWhC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CA3HeC,EAAAmF,GAAA,iBAgIf,SAASO,EACPC,EACAC,EACAC,EAA4B,CAAC,EACvB,CAEDhG,EAAG,WAAW+F,CAAI,GACrB/F,EAAG,UAAU+F,EAAM,CAAE,UAAW,EAAK,CAAC,EAGxC,IAAME,EAAQjG,EAAG,YAAY8F,CAAG,EAEhC,QAAWpC,KAAQuC,EAAO,CAExB,GAAID,EAAgB,KAAME,GAAYxC,EAAK,SAASwC,CAAO,CAAC,EAC1D,SAGF,IAAMC,EAAUtG,EAAK,KAAKiG,EAAKpC,CAAI,EAC7B0C,EAAWvG,EAAK,KAAKkG,EAAMrC,CAAI,EACxB1D,EAAG,SAASmG,CAAO,EAEvB,YAAY,EACnBN,EAAcM,EAASC,EAAUJ,CAAe,EAEhDhG,EAAG,aAAamG,EAASC,CAAQ,CAErC,CACF,CA5BSjG,EAAA0F,EAAA,iBAiCT,eAAeQ,GAAcC,EAAaC,EAA+B,CACvE,IAAMrE,EAAUC,EAAI,6BAAS,EAAE,MAAM,EAErC,GAAI,CACF,GAAI,CAACV,EAAc,aAAa,EAAG,CACjCS,EAAQ,KAAK,4CAAS,EACtB,QAAQ,IAAIR,EAAM,OAAO,gGAAkC,CAAC,EAC5D,MACF,CAEA,GAAK6E,EAgCH,OAAQD,EAAK,CACX,IAAK,cACH7E,EAAc,kBAAkB8E,CAAK,EACrCrE,EAAQ,QAAQ,6CAAeqE,CAAK,EAAE,EACtC,MACF,QACErE,EAAQ,KAAK,sBAAOoE,CAAG,+DAAa,EACpC,QAAQ,IAAI5E,EAAM,OAAO,+DAAuB,CAAC,EACjD,MACJ,KAzCU,CAEVQ,EAAQ,KAAO,8BACf,IAAMsE,EAAS/E,EAAc,UAAU,EAEvC,OAAQ6E,EAAK,CACX,IAAK,cACHpE,EAAQ,QAAQ,0BAAM,EACtB,QAAQ,IAAIR,EAAM,MAAM,qBAAW8E,EAAO,WAAW,EAAE,CAAC,EACxD,MACF,IAAK,aACHtE,EAAQ,QAAQ,0BAAM,EACtB,QAAQ,IAAIR,EAAM,MAAM,mBAAS,CAAC,EAClC,OAAW,CAAC+E,EAAMC,CAAY,IAAK,OAAO,QACxCF,EAAO,UACT,EACE,QAAQ,IACN9E,EAAM,KACJ,KAAK+E,CAAI,KAAKC,EAAa,OAAO,IAAIA,EAAa,KAAK,KACtD,GACF,CAAC,EACH,CACF,EAEF,MACF,QACExE,EAAQ,KAAK,yCAAWoE,CAAG,EAAE,EAC7B,QAAQ,IAAI5E,EAAM,OAAO,+DAAiC,CAAC,EAC3D,MACJ,CACF,CAaF,OAASxB,EAAO,CACdgC,EAAQ,KACN,yCAAWhC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CA1DeC,EAAAkG,GAAA,iBA+Df,SAASM,IAAiB,CACxB,QAAQ,IAAIjF,EAAM,KAAK,KAAK,sCAAsC,CAAC,EACnE,QAAQ,IAAI,EACZ,QAAQ,IAAIA,EAAM,OAAO,2BAAO,CAAC,EACjC,QAAQ,IAAI,+BAA+B,EAC3C,QAAQ,IAAI,EACZ,QAAQ,IAAIA,EAAM,OAAO,eAAK,CAAC,EAC/B,QAAQ,IAAI,qDAAiC,EAC7C,QAAQ,IAAI,uEAAoC,EAChD,QAAQ,IAAI,uEAAoC,EAChD,QAAQ,IAAI,yFAAiD,EAC7D,QAAQ,IAAI,qDAAiC,EAC7C,QAAQ,IAAI,iEAAmC,EAC/C,QAAQ,IAAI,+FAAwC,EACpD,QAAQ,IAAI,yFAAiD,EAC7D,QAAQ,IAAI,yFAAuC,EACnD,QAAQ,IAAI,EACZ,QAAQ,IAAIA,EAAM,OAAO,eAAK,CAAC,EAC/B,QAAQ,IAAI,iEAAmC,EAC/C,QAAQ,IAAI,iEAAmC,EAC/C,QAAQ,IAAI,iEAAmC,EAC/C,QAAQ,IAAI,6GAAiD,EAC7D,QAAQ,IAAI,EACZ,QAAQ,IAAIA,EAAM,OAAO,2BAAO,CAAC,EACjC,QAAQ,IAAI,mFAAqD,EACjE,QAAQ,IACN,oFACF,EACA,QAAQ,IACN,oGACF,EACA,QAAQ,IAAI,EACZ,QAAQ,IAAIA,EAAM,OAAO,2BAAO,CAAC,EACjC,QAAQ,IAAI,0EAAiD,EAC7D,QAAQ,IAAI,0EAAsD,EAClE,QAAQ,IAAI,0EAAsD,EAClE,QAAQ,IAAI,EACZ,QAAQ,IAAIA,EAAM,OAAO,2BAAO,CAAC,EACjC,QAAQ,IAAI,uEAAyC,EACrD,QAAQ,IAAI,uEAAyC,EACrD,QAAQ,IAAI,uEAAyC,EACrD,QAAQ,IAAI,mFAA2C,EACvD,QAAQ,IAAI,2DAAuC,EACnD,QAAQ,IAAI,EACZ,QAAQ,IAAIA,EAAM,OAAO,+BAAW,CAAC,EACrC,QAAQ,IAAI,4EAA8C,EAC1D,QAAQ,IAAI,yFAA4C,EACxD,QAAQ,IAAI,yFAA4C,EACxD,QAAQ,IAAI,wEAAoD,EAChE,QAAQ,IAAI,wEAAoD,EAChE,QAAQ,IAAI,EACZ,QAAQ,IAAIA,EAAM,OAAO,2BAAO,CAAC,EACjC,QAAQ,IAAI,+FAA6C,EACzD,QAAQ,IAAI,uHAA6B,CAC3C,CAtDSvB,EAAAwG,GAAA,YAyDTrH,EACG,KAAK,SAAS,EACd,YAAY,iCAAiC,EAC7C,QAAQG,EAAW,EAAG,gBAAiB,sCAAQ,EAC/C,WAAW,aAAc,sCAAQ,EAGpCH,EACG,QAAQ,sBAAsB,EAC9B,YAAY,0BAAM,EAClB,OAAO,gCAAiC,8DAAY,EACpD,OAAO,MAAOiG,EAAaC,IAAY,CACtC,MAAMF,GAAcC,EAAaC,CAAO,CAC1C,CAAC,EAGHlG,EACG,QAAQ,MAAM,EACd,YAAY,4CAAS,EACrB,OAAO,SAAY,CAClB,MAAMiE,GAAW,CACnB,CAAC,EAGHjE,EACG,QAAQ,sBAAsB,EAC9B,YAAY,4CAAS,EACrB,OAAO,MAAOgH,EAAKC,IAAU,CAC5B,MAAMF,GAAcC,EAAKC,CAAK,CAChC,CAAC,EAGHjH,EACG,QAAQ,OAAO,EACf,YAAY,0BAAM,EAClB,OAAO,eAAgB,4CAAS,EAChC,OAAO,MAAOkG,GAAY,CACzB,MAAMxD,EAAawD,EAAQ,MAAM,CACnC,CAAC,EAGHlG,EACG,QAAQ,MAAM,EACd,YAAY,0BAAM,EAClB,OAAO,SAAY,CAClB,MAAMuD,EAAY,CACpB,CAAC,EAGHvD,EACG,QAAQ,QAAQ,EAChB,YAAY,sCAAQ,EACpB,OAAO,SAAY,CAClB,MAAM2D,GAAY,CACpB,CAAC,EAGH3D,EACG,QAAQ,QAAQ,EAChB,YAAY,oEAAa,EACzB,OAAO,SAAY,CAClB,MAAM4D,GAAc,CACtB,CAAC,EAGH5D,EACG,QAAQ,SAAS,EACjB,YAAY,0BAAM,EAClB,OAAO,eAAgB,4CAAS,EAChC,OAAO,MAAOkG,GAAY,CACzB,MAAMpC,GAAeoC,EAAQ,MAAM,CACrC,CAAC,EAGH,IAAMoB,EAAatH,EAAQ,QAAQ,KAAK,EAAE,YAAY,gDAAa,EAGnEsH,EACG,QAAQ,MAAM,EACd,YAAY,+BAAW,EACvB,OAAO,UAAW,oEAAa,EAC/B,OAAO,MAAOpB,GAAY,CACzB,MAAMqB,EAAerB,CAAO,CAC9B,CAAC,EAGHoB,EACG,QAAQ,qBAAqB,EAC7B,YAAY,iDAAc,EAC1B,OAAO,MAAOE,GAAe,CAC5B,MAAMC,EAAgBD,CAAU,CAClC,CAAC,EAGHF,EACG,QAAQ,uCAAuC,EAC/C,YAAY,0EAAc,EAC1B,OAAO,MAAOE,EAAYE,EAAUC,IAAW,CAC1CA,IAAW,UAAYA,IAAW,YACpC,QAAQ,MAAMvF,EAAM,IAAI,wEAAgC,CAAC,EACzD,QAAQ,KAAK,CAAC,GAIhB,MAAMwF,EAAeJ,EAAYE,EADjBC,IAAW,QACuB,CACpD,CAAC,EAGH3H,EACG,QAAQ,YAAY,EACpB,YAAY,8DAAY,EACxB,OAAO,SAAY,CAClB6H,EAAmB,CACrB,CAAC,EAGH7H,EAAQ,OAAO,KAAM,sCAAQ,EAAE,OAAQkG,GAAY,CAC7CA,EAAQ,IACVnC,GAAiB,EACjB,QAAQ,KAAK,CAAC,EAElB,CAAC,EAGD+D,EAAoB,EAGhB,QAAQ,KAAK,QAAU,IACzBT,GAAS,EACT,QAAQ,KAAK,CAAC,GAIhBrH,EAAQ,MAAM,QAAQ,IAAI","names":["spawn","fs","os","path","fileURLToPath","chalk","Command","ora","omelette","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","__dirname","dirname","fileURLToPath","ConfigManager","_ConfigManager","__name","resolve","configDir","configPath","existsSync","copyFileSync","configData","readFileSync","config","error","configObj","serverName","serverConfig","sc","toolName","endpoint","newConfig","newMcpServers","toolsConfig","enabled","description","configJson","writeFileSync","configManager","getMcpServerNames","configManager","mcpServers","__name","getServerToolNames","serverName","toolsConfig","setupAutoCompletion","completion","omelette","reply","fragment","line","before","parts","currentIndex","subcommand","subcommands","current","matches","cmd","options","opt","serverNames","name","toolNames","actions","action","error","showCompletionHelp","chalk","Table","ora","getDisplayWidth","str","width","char","__name","truncateToWidth","maxWidth","result","currentWidth","hasAddedChar","charWidth","listMcpServers","options","spinner","ora","mcpServers","configManager","serverNames","chalk","maxToolNameWidth","allToolNames","serverName","toolsConfig","toolNames","toolName","table","Table","toolConfig","status","description","serverConfig","toolCount","enabledCount","t","error","listServerTools","setToolEnabled","enabled","action","program","Command","SERVICE_NAME","getVersion","__filename","fileURLToPath","currentDir","path","possiblePaths","packagePath","fs","packageJson","error","__name","PID_FILE","os","LOG_FILE","getServiceStatus","pidContent","pidStr","startTime","mode","pid","start","uptime","formatUptime","ms","seconds","minutes","hours","days","savePidInfo","pidInfo","cleanupPidFile","checkEnvironment","configManager","chalk","endpoint","getServiceCommand","scriptDir","distDir","p","startService","daemon","spinner","ora","status","command","args","cwd","child","spawn","logStream","code","signal","stopService","attempts","maxAttempts","resolve","checkStatus","attachService","tail","restartService","showDetailedInfo","version","initConfig","getAvailableTemplates","templatesDir","item","itemPath","calculateSimilarity","str1","str2","len1","len2","matrix","i","j","maxLen","findSimilarTemplate","input","templates","bestMatch","bestSimilarity","template","similarity","askUserConfirmation","question","readline","rl","handleInput","char","createBasicConfig","projectPath","configContent","configPath","createProject","projectName","options","targetPath","availableTemplates","similarTemplate","templatePath","copyDirectory","src","dest","excludePatterns","items","pattern","srcPath","destPath","configCommand","key","value","config","name","serverConfig","showHelp","mcpCommand","listMcpServers","serverName","listServerTools","toolName","action","setToolEnabled","showCompletionHelp","setupAutoCompletion"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/autoCompletion.ts","../src/configManager.ts","../src/mcpCommands.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\nimport { setupAutoCompletion, showCompletionHelp } from \"./autoCompletion\";\nimport { configManager } from \"./configManager\";\nimport { listMcpServers, listServerTools, setToolEnabled } from \"./mcpCommands\";\n\nconst program = new Command();\nconst SERVICE_NAME = \"xiaozhi-mcp-service\";\n\n/**\n * 获取版本号\n */\nexport function getVersion(): string {\n try {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n // 尝试多个可能的 package.json 路径\n const possiblePaths = [\n // 开发环境:src/cli.ts -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 构建后环境:dist/cli.js -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"package.json\"),\n // 如果 package.json 被复制到 dist 目录\n path.join(currentDir, \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n if (packageJson.version) {\n return packageJson.version;\n }\n }\n }\n\n // 如果都找不到,返回默认版本\n return \"unknown\";\n } catch (error) {\n console.warn(\"Warning: Could not read version from package.json:\", error);\n return \"unknown\";\n }\n}\n\n// PID 文件路径\nconst PID_FILE = path.join(os.tmpdir(), `${SERVICE_NAME}.pid`);\nconst LOG_FILE = path.join(os.tmpdir(), `${SERVICE_NAME}.log`);\n\ninterface ServiceStatus {\n running: boolean;\n pid?: number;\n uptime?: string;\n mode?: \"foreground\" | \"daemon\";\n}\n\n/**\n * 获取服务状态\n */\nexport function getServiceStatus(): ServiceStatus {\n try {\n if (!fs.existsSync(PID_FILE)) {\n return { running: false };\n }\n\n const pidContent = fs.readFileSync(PID_FILE, \"utf8\").trim();\n const [pidStr, startTime, mode] = pidContent.split(\"|\");\n const pid = Number.parseInt(pidStr);\n\n if (Number.isNaN(pid)) {\n // PID 文件损坏,删除它\n fs.unlinkSync(PID_FILE);\n return { running: false };\n }\n\n // 检查进程是否还在运行\n try {\n process.kill(pid, 0); // 发送信号 0 来检查进程是否存在\n\n // 计算运行时间\n const start = Number.parseInt(startTime);\n const uptime = formatUptime(Date.now() - start);\n\n return {\n running: true,\n pid,\n uptime,\n mode: (mode as \"foreground\" | \"daemon\") || \"foreground\",\n };\n } catch (error) {\n // 进程不存在,删除 PID 文件\n fs.unlinkSync(PID_FILE);\n return { running: false };\n }\n } catch (error) {\n return { running: false };\n }\n}\n\n/**\n * 格式化运行时间\n */\nexport function formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}天 ${hours % 24}小时 ${minutes % 60}分钟`;\n }\n if (hours > 0) {\n return `${hours}小时 ${minutes % 60}分钟`;\n }\n if (minutes > 0) {\n return `${minutes}分钟 ${seconds % 60}秒`;\n }\n return `${seconds}秒`;\n}\n\n/**\n * 保存 PID 信息\n */\nfunction savePidInfo(pid: number, mode: \"foreground\" | \"daemon\") {\n const pidInfo = `${pid}|${Date.now()}|${mode}`;\n fs.writeFileSync(PID_FILE, pidInfo);\n}\n\n/**\n * 清理 PID 文件\n */\nfunction cleanupPidFile() {\n try {\n if (fs.existsSync(PID_FILE)) {\n fs.unlinkSync(PID_FILE);\n }\n } catch (error) {\n // 忽略清理错误\n }\n}\n\n/**\n * 检查配置文件和环境\n */\nexport function checkEnvironment(): boolean {\n // 首先检查配置文件是否存在\n if (!configManager.configExists()) {\n console.error(chalk.red(\"❌ 错误: 配置文件不存在\"));\n console.log(chalk.yellow('💡 提示: 请运行 \"xiaozhi init\" 初始化配置'));\n return false;\n }\n\n try {\n // 检查配置是否有效\n const endpoint = configManager.getMcpEndpoint();\n if (!endpoint || endpoint.includes(\"<请填写\")) {\n console.error(chalk.red(\"❌ 错误: MCP 端点未配置\"));\n console.log(\n chalk.yellow(\n '💡 提示: 请运行 \"xiaozhi config mcpEndpoint <your-endpoint-url>\" 设置端点'\n )\n );\n return false;\n }\n return true;\n } catch (error) {\n console.error(\n chalk.red(\n `❌ 错误: 配置文件无效 - ${\n error instanceof Error ? error.message : String(error)\n }`\n )\n );\n console.log(chalk.yellow('💡 提示: 请运行 \"xiaozhi init\" 重新初始化配置'));\n return false;\n }\n}\n\n/**\n * 获取服务启动命令和参数\n */\nfunction getServiceCommand(): { command: string; args: string[]; cwd: string } {\n // 获取当前脚本所在目录\n const scriptDir = path.dirname(fileURLToPath(import.meta.url));\n\n // 检查是否在开发环境(js-demo/dist)还是全局安装环境\n let distDir: string;\n if (scriptDir.includes(\"js-demo/dist\")) {\n // 开发环境\n distDir = scriptDir;\n } else {\n // 全局安装环境,需要找到实际的项目目录\n // 通常全局安装后,脚本在 node_modules/.bin 或类似位置\n // 我们需要找到实际的 dist 目录\n const possiblePaths = [\n path.join(scriptDir, \"..\", \"js-demo\", \"dist\"),\n path.join(scriptDir, \"..\", \"..\", \"js-demo\", \"dist\"),\n path.join(scriptDir, \"..\", \"..\", \"..\", \"js-demo\", \"dist\"),\n path.join(process.cwd(), \"js-demo\", \"dist\"),\n path.join(process.cwd(), \"dist\"),\n ];\n\n distDir =\n possiblePaths.find(\n (p) =>\n fs.existsSync(path.join(p, \"mcpPipe.js\")) &&\n fs.existsSync(path.join(p, \"mcpServerProxy.js\"))\n ) || scriptDir;\n }\n\n return {\n command: \"node\",\n args: [\"mcpPipe.js\", \"mcpServerProxy.js\"],\n cwd: distDir,\n };\n}\n\n/**\n * 启动服务\n */\nasync function startService(daemon = false): Promise<void> {\n const spinner = ora(\"检查服务状态...\").start();\n\n try {\n // 检查服务是否已经在运行\n const status = getServiceStatus();\n if (status.running) {\n spinner.fail(`服务已经在运行 (PID: ${status.pid})`);\n return;\n }\n\n // 检查环境变量\n spinner.text = \"检查环境配置...\";\n if (!checkEnvironment()) {\n spinner.fail(\"环境配置检查失败\");\n return;\n }\n\n // 获取启动命令\n const { command, args, cwd } = getServiceCommand();\n\n spinner.text = `启动服务 (${daemon ? \"后台模式\" : \"前台模式\"})...`;\n\n if (daemon) {\n // 后台模式\n const child = spawn(command, args, {\n cwd,\n detached: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.cwd(), // 传递用户的当前工作目录\n XIAOZHI_DAEMON: \"true\", // 标记这是守护进程模式\n },\n });\n\n // 保存 PID 信息\n savePidInfo(child.pid!, \"daemon\");\n\n // 设置日志输出\n const logStream = fs.createWriteStream(LOG_FILE, { flags: \"a\" });\n child.stdout?.pipe(logStream);\n child.stderr?.pipe(logStream);\n\n // 监听进程异常退出\n child.on(\"exit\", (code, signal) => {\n if (code !== 0 && code !== null) {\n // 进程异常退出,记录日志\n const errorLog = `\\n[${new Date().toISOString()}] 后台服务异常退出 (代码: ${code}, 信号: ${signal})\\n`;\n fs.appendFileSync(LOG_FILE, errorLog);\n }\n cleanupPidFile();\n });\n\n // 监听进程错误\n child.on(\"error\", (error) => {\n const errorLog = `\\n[${new Date().toISOString()}] 后台服务启动错误: ${error.message}\\n`;\n fs.appendFileSync(LOG_FILE, errorLog);\n cleanupPidFile();\n spinner.fail(`后台服务启动失败: ${error.message}`);\n return;\n });\n\n // 分离进程\n child.unref();\n\n spinner.succeed(`服务已在后台启动 (PID: ${child.pid})`);\n console.log(chalk.gray(`日志文件: ${LOG_FILE}`));\n console.log(chalk.gray(`使用 'xiaozhi attach' 可以查看实时日志`));\n } else {\n // 前台模式\n spinner.succeed(\"服务启动中...\");\n\n const child = spawn(command, args, {\n cwd,\n stdio: \"inherit\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.cwd(), // 传递用户的当前工作目录\n },\n });\n\n // 保存 PID 信息\n savePidInfo(child.pid!, \"foreground\");\n\n // 处理进程退出\n child.on(\"exit\", (code, signal) => {\n cleanupPidFile();\n if (code !== 0) {\n console.log(\n chalk.red(`\\n服务异常退出 (代码: ${code}, 信号: ${signal})`)\n );\n } else {\n console.log(chalk.green(\"\\n服务已停止\"));\n }\n });\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(chalk.yellow(\"\\n正在停止服务...\"));\n child.kill(\"SIGTERM\");\n });\n\n process.on(\"SIGTERM\", () => {\n child.kill(\"SIGTERM\");\n });\n }\n } catch (error) {\n spinner.fail(\n `启动服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 停止服务\n */\nasync function stopService(): Promise<void> {\n const spinner = ora(\"检查服务状态...\").start();\n\n try {\n const status = getServiceStatus();\n\n if (!status.running) {\n spinner.warn(\"服务未在运行\");\n return;\n }\n\n spinner.text = `停止服务 (PID: ${status.pid})...`;\n\n try {\n // 尝试优雅停止\n process.kill(status.pid!, \"SIGTERM\");\n\n // 等待进程停止\n let attempts = 0;\n const maxAttempts = 30; // 3秒超时\n\n while (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n try {\n process.kill(status.pid!, 0);\n attempts++;\n } catch {\n // 进程已停止\n break;\n }\n }\n\n // 检查是否还在运行\n try {\n process.kill(status.pid!, 0);\n // 如果还在运行,强制停止\n spinner.text = \"强制停止服务...\";\n process.kill(status.pid!, \"SIGKILL\");\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n // 进程已停止\n }\n\n cleanupPidFile();\n spinner.succeed(\"服务已停止\");\n } catch (error) {\n cleanupPidFile();\n spinner.fail(\n `停止服务失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n } catch (error) {\n spinner.fail(\n `停止服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 检查服务状态\n */\nasync function checkStatus(): Promise<void> {\n const spinner = ora(\"检查服务状态...\").start();\n\n try {\n const status = getServiceStatus();\n\n if (status.running) {\n spinner.succeed(\"服务状态\");\n console.log(chalk.green(\"✅ 服务正在运行\"));\n console.log(chalk.gray(` PID: ${status.pid}`));\n console.log(chalk.gray(` 运行时间: ${status.uptime}`));\n console.log(\n chalk.gray(\n ` 运行模式: ${status.mode === \"daemon\" ? \"后台模式\" : \"前台模式\"}`\n )\n );\n\n if (status.mode === \"daemon\") {\n console.log(chalk.gray(` 日志文件: ${LOG_FILE}`));\n }\n } else {\n spinner.succeed(\"服务状态\");\n console.log(chalk.red(\"❌ 服务未运行\"));\n }\n } catch (error) {\n spinner.fail(\n `检查状态失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 附加到后台服务\n */\nasync function attachService(): Promise<void> {\n const spinner = ora(\"检查服务状态...\").start();\n\n try {\n const status = getServiceStatus();\n\n if (!status.running) {\n spinner.fail(\"服务未在运行\");\n return;\n }\n\n if (status.mode !== \"daemon\") {\n spinner.fail(\"服务不是在后台模式运行\");\n return;\n }\n\n spinner.succeed(\"连接到后台服务...\");\n console.log(chalk.green(`已连接到服务 (PID: ${status.pid})`));\n console.log(chalk.gray(\"按 Ctrl+C 可以断开连接(不会停止服务)\"));\n console.log(chalk.gray(\"=\".repeat(50)));\n\n // 显示日志文件内容\n if (fs.existsSync(LOG_FILE)) {\n // 跨平台的日志查看实现\n if (process.platform === \"win32\") {\n // Windows 使用 PowerShell 的 Get-Content -Wait\n const { spawn } = await import(\"node:child_process\");\n const tail = spawn(\n \"powershell\",\n [\"-Command\", `Get-Content -Path \"${LOG_FILE}\" -Wait`],\n { stdio: \"inherit\" }\n );\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(chalk.yellow(\"\\n断开连接,服务继续在后台运行\"));\n tail.kill();\n process.exit(0);\n });\n\n tail.on(\"exit\", () => {\n process.exit(0);\n });\n } else {\n // Unix/Linux/macOS 使用 tail -f\n const { spawn } = await import(\"node:child_process\");\n const tail = spawn(\"tail\", [\"-f\", LOG_FILE], { stdio: \"inherit\" });\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(chalk.yellow(\"\\n断开连接,服务继续在后台运行\"));\n tail.kill();\n process.exit(0);\n });\n\n tail.on(\"exit\", () => {\n process.exit(0);\n });\n }\n } else {\n console.log(chalk.yellow(\"日志文件不存在\"));\n }\n } catch (error) {\n spinner.fail(\n `连接失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 重启服务\n */\nasync function restartService(daemon = false): Promise<void> {\n console.log(chalk.blue(\"🔄 重启服务...\"));\n\n // 先停止服务\n await stopService();\n\n // 等待一下确保完全停止\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n // 重新启动服务\n await startService(daemon);\n}\n\n/**\n * 显示详细信息\n */\nfunction showDetailedInfo(): void {\n const version = getVersion();\n console.log(chalk.blue(`xiaozhi v${version}`));\n console.log(chalk.gray(\"MCP Calculator Service CLI Tool\"));\n console.log(chalk.gray(\"Built with Node.js and TypeScript\"));\n console.log(chalk.gray(`Node.js: ${process.version}`));\n console.log(chalk.gray(`Platform: ${process.platform} ${process.arch}`));\n}\n\n/**\n * 初始化配置\n */\nasync function initConfig(): Promise<void> {\n const spinner = ora(\"初始化配置...\").start();\n\n try {\n if (configManager.configExists()) {\n spinner.warn(\"配置文件已存在\");\n console.log(\n chalk.yellow(\"如需重新初始化,请先删除现有的 xiaozhi.config.json 文件\")\n );\n return;\n }\n\n configManager.initConfig();\n spinner.succeed(\"配置文件初始化成功\");\n\n console.log(chalk.green(\"✅ 配置文件已创建: xiaozhi.config.json\"));\n console.log(chalk.yellow(\"📝 请编辑配置文件设置你的 MCP 端点:\"));\n console.log(\n chalk.gray(` 配置文件路径: ${configManager.getConfigPath()}`)\n );\n console.log(chalk.yellow(\"💡 或者使用命令设置:\"));\n console.log(\n chalk.gray(\" xiaozhi config mcpEndpoint <your-endpoint-url>\")\n );\n } catch (error) {\n spinner.fail(\n `初始化配置失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n}\n\n/**\n * 获取可用模板列表\n */\nfunction getAvailableTemplates(): string[] {\n const scriptDir = path.dirname(fileURLToPath(import.meta.url));\n const possiblePaths = [\n path.join(scriptDir, \"..\", \"templates\"), // 开发环境\n path.join(scriptDir, \"templates\"), // 打包后的环境\n path.join(scriptDir, \"..\", \"..\", \"templates\"), // npm 全局安装\n ];\n\n const templatesDir = possiblePaths.find((p) => fs.existsSync(p));\n if (!templatesDir) {\n return [];\n }\n\n return fs.readdirSync(templatesDir).filter((item) => {\n const itemPath = path.join(templatesDir, item);\n return fs.statSync(itemPath).isDirectory();\n });\n}\n\n/**\n * 计算字符串相似度(简单的编辑距离算法)\n */\nexport function calculateSimilarity(str1: string, str2: string): number {\n const len1 = str1.length;\n const len2 = str2.length;\n const matrix = Array(len1 + 1)\n .fill(null)\n .map(() => Array(len2 + 1).fill(0));\n\n for (let i = 0; i <= len1; i++) matrix[i][0] = i;\n for (let j = 0; j <= len2; j++) matrix[0][j] = j;\n\n for (let i = 1; i <= len1; i++) {\n for (let j = 1; j <= len2; j++) {\n if (str1[i - 1] === str2[j - 1]) {\n matrix[i][j] = matrix[i - 1][j - 1];\n } else {\n matrix[i][j] = Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + 1\n );\n }\n }\n }\n\n const maxLen = Math.max(len1, len2);\n return maxLen === 0 ? 1 : (maxLen - matrix[len1][len2]) / maxLen;\n}\n\n/**\n * 查找最相似的模板\n */\nfunction findSimilarTemplate(\n input: string,\n templates: string[]\n): string | null {\n if (templates.length === 0) return null;\n\n let bestMatch = templates[0];\n let bestSimilarity = calculateSimilarity(\n input.toLowerCase(),\n bestMatch.toLowerCase()\n );\n\n for (const template of templates.slice(1)) {\n const similarity = calculateSimilarity(\n input.toLowerCase(),\n template.toLowerCase()\n );\n if (similarity > bestSimilarity) {\n bestSimilarity = similarity;\n bestMatch = template;\n }\n }\n\n // 只有相似度超过 0.5 才认为是可能的匹配\n return bestSimilarity > 0.5 ? bestMatch : null;\n}\n\n/**\n * 询问用户确认\n */\nasync function askUserConfirmation(question: string): Promise<boolean> {\n // 检查是否在交互式终端中\n if (!process.stdin.isTTY) {\n // 非交互式环境,默认返回 false\n console.log(\"n (非交互式环境)\");\n return false;\n }\n\n // 使用 readline 接口处理用户输入\n const readline = await import(\"node:readline\");\n\n return new Promise((resolve) => {\n process.stdout.write(question);\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const handleInput = (input: string) => {\n const char = input.trim().toLowerCase();\n if (char === \"y\" || char === \"yes\") {\n rl.close();\n resolve(true);\n } else if (char === \"n\" || char === \"no\" || char === \"\") {\n rl.close();\n resolve(false);\n } else {\n // 无效输入,重新询问\n process.stdout.write(\"请输入 y 或 n: \");\n }\n };\n\n rl.on(\"line\", handleInput);\n rl.on(\"SIGINT\", () => {\n rl.close();\n resolve(false);\n });\n });\n}\n\n/**\n * 创建基本的 xiaozhi.config.json 文件\n */\nfunction createBasicConfig(projectPath: string): void {\n const configContent = {\n mcpEndpoint: \"<请填写你的接入点地址(获取地址在 xiaozhi.me)>\",\n mcpServers: {},\n };\n\n const configPath = path.join(projectPath, \"xiaozhi.config.json\");\n fs.writeFileSync(configPath, JSON.stringify(configContent, null, 2), \"utf8\");\n}\n\n/**\n * 创建项目命令\n */\nasync function createProject(\n projectName: string,\n options: { template?: string }\n): Promise<void> {\n const spinner = ora(\"初始化项目...\").start();\n\n try {\n // 确定目标目录\n const targetPath = path.join(process.cwd(), projectName);\n\n // 检查目标目录是否已存在\n if (fs.existsSync(targetPath)) {\n spinner.fail(`目录 \"${projectName}\" 已存在`);\n console.log(chalk.yellow(\"💡 提示: 请选择不同的项目名称或删除现有目录\"));\n return;\n }\n\n if (options.template) {\n // 使用模板创建项目\n spinner.text = \"检查模板...\";\n\n // 获取可用模板列表\n const availableTemplates = getAvailableTemplates();\n\n if (availableTemplates.length === 0) {\n spinner.fail(\"找不到 templates 目录\");\n console.log(chalk.yellow(\"💡 提示: 请确保 xiaozhi-client 正确安装\"));\n return;\n }\n\n // 检查模板是否存在\n if (!availableTemplates.includes(options.template)) {\n spinner.fail(`模板 \"${options.template}\" 不存在`);\n\n // 尝试找到相似的模板\n const similarTemplate = findSimilarTemplate(\n options.template,\n availableTemplates\n );\n\n if (similarTemplate) {\n console.log(\n chalk.yellow(`💡 你是想使用模板 \"${similarTemplate}\" 吗?`)\n );\n const confirmed = await askUserConfirmation(\n chalk.cyan(\"确认使用此模板?(y/n): \")\n );\n\n if (confirmed) {\n options.template = similarTemplate;\n } else {\n console.log(chalk.yellow(\"可用的模板:\"));\n for (const template of availableTemplates) {\n console.log(chalk.gray(` - ${template}`));\n }\n return;\n }\n } else {\n console.log(chalk.yellow(\"可用的模板:\"));\n for (const template of availableTemplates) {\n console.log(chalk.gray(` - ${template}`));\n }\n return;\n }\n }\n\n // 获取模板路径 (ESM 环境)\n const scriptDir = path.dirname(fileURLToPath(import.meta.url));\n const possiblePaths = [\n path.join(scriptDir, \"..\", \"templates\"), // 开发环境\n path.join(scriptDir, \"templates\"), // 打包后的环境\n path.join(scriptDir, \"..\", \"..\", \"templates\"), // npm 全局安装\n ];\n const templatesDir = possiblePaths.find((p) => fs.existsSync(p))!;\n const templatePath = path.join(templatesDir, options.template);\n\n spinner.text = `从模板 \"${options.template}\" 创建项目 \"${projectName}\"...`;\n\n // 复制模板到目标目录\n copyDirectory(templatePath, targetPath, [\n \"node_modules\",\n \".pnpm-debug.log\",\n \"pnpm-lock.yaml\",\n ]);\n\n spinner.succeed(`项目 \"${projectName}\" 创建成功`);\n\n console.log(chalk.green(\"✅ 项目创建完成!\"));\n console.log(chalk.yellow(\"📝 接下来的步骤:\"));\n console.log(chalk.gray(` cd ${projectName}`));\n console.log(chalk.gray(\" pnpm install # 安装依赖\"));\n console.log(\n chalk.gray(\" # 编辑 xiaozhi.config.json 设置你的 MCP 端点\")\n );\n console.log(chalk.gray(\" xiaozhi start # 启动服务\"));\n } else {\n // 创建基本项目(只有配置文件)\n spinner.text = `创建基本项目 \"${projectName}\"...`;\n\n // 创建项目目录\n fs.mkdirSync(targetPath, { recursive: true });\n\n // 创建基本的 xiaozhi.config.json\n createBasicConfig(targetPath);\n\n spinner.succeed(`项目 \"${projectName}\" 创建成功`);\n\n console.log(chalk.green(\"✅ 基本项目创建完成!\"));\n console.log(chalk.yellow(\"📝 接下来的步骤:\"));\n console.log(chalk.gray(` cd ${projectName}`));\n console.log(\n chalk.gray(\" # 编辑 xiaozhi.config.json 设置你的 MCP 端点和服务\")\n );\n console.log(chalk.gray(\" xiaozhi start # 启动服务\"));\n console.log(\n chalk.yellow(\"💡 提示: 使用 --template 选项可以从模板创建项目\")\n );\n }\n } catch (error) {\n spinner.fail(\n `创建项目失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 递归复制目录\n */\nfunction copyDirectory(\n src: string,\n dest: string,\n excludePatterns: string[] = []\n): void {\n // 创建目标目录\n if (!fs.existsSync(dest)) {\n fs.mkdirSync(dest, { recursive: true });\n }\n\n const items = fs.readdirSync(src);\n\n for (const item of items) {\n // 检查是否应该排除此项\n if (excludePatterns.some((pattern) => item.includes(pattern))) {\n continue;\n }\n\n const srcPath = path.join(src, item);\n const destPath = path.join(dest, item);\n const stat = fs.statSync(srcPath);\n\n if (stat.isDirectory()) {\n copyDirectory(srcPath, destPath, excludePatterns);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\n/**\n * 配置管理命令\n */\nasync function configCommand(key: string, value?: string): Promise<void> {\n const spinner = ora(\"更新配置...\").start();\n\n try {\n if (!configManager.configExists()) {\n spinner.fail(\"配置文件不存在\");\n console.log(chalk.yellow('💡 提示: 请先运行 \"xiaozhi init\" 初始化配置'));\n return;\n }\n\n if (!value) {\n // 显示配置值\n spinner.text = \"读取配置...\";\n const config = configManager.getConfig();\n\n switch (key) {\n case \"mcpEndpoint\":\n spinner.succeed(\"配置信息\");\n console.log(chalk.green(`MCP 端点: ${config.mcpEndpoint}`));\n break;\n case \"mcpServers\":\n spinner.succeed(\"配置信息\");\n console.log(chalk.green(\"MCP 服务:\"));\n for (const [name, serverConfig] of Object.entries(\n config.mcpServers\n )) {\n console.log(\n chalk.gray(\n ` ${name}: ${serverConfig.command} ${serverConfig.args.join(\n \" \"\n )}`\n )\n );\n }\n break;\n default:\n spinner.fail(`未知的配置项: ${key}`);\n console.log(chalk.yellow(\"支持的配置项: mcpEndpoint, mcpServers\"));\n return;\n }\n } else {\n // 设置配置值\n switch (key) {\n case \"mcpEndpoint\":\n configManager.updateMcpEndpoint(value);\n spinner.succeed(`MCP 端点已更新为: ${value}`);\n break;\n default:\n spinner.fail(`配置项 ${key} 不支持通过命令行设置`);\n console.log(chalk.yellow(\"支持设置的配置项: mcpEndpoint\"));\n return;\n }\n }\n } catch (error) {\n spinner.fail(\n `配置操作失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 显示帮助信息\n */\nfunction showHelp(): void {\n console.log(chalk.blue.bold(\"xiaozhi - MCP Calculator Service CLI\"));\n console.log();\n console.log(chalk.yellow(\"使用方法:\"));\n console.log(\" xiaozhi <command> [options]\");\n console.log();\n console.log(chalk.yellow(\"命令:\"));\n console.log(\" create <projectName> 创建项目\");\n console.log(\" init 初始化配置文件\");\n console.log(\" config <key> [value] 查看或设置配置\");\n console.log(\" start [--daemon] 启动服务 (--daemon 后台运行)\");\n console.log(\" stop 停止服务\");\n console.log(\" status 检查服务状态\");\n console.log(\" attach 连接到后台服务查看日志\");\n console.log(\" restart [--daemon] 重启服务 (--daemon 后台运行)\");\n console.log(\" completion 显示自动补全设置说明\");\n console.log();\n console.log(chalk.yellow(\"选项:\"));\n console.log(\" -v, --version 显示版本信息\");\n console.log(\" -V 显示详细信息\");\n console.log(\" -h, --help 显示帮助信息\");\n console.log(\" -t, --template <name> 指定模板名称(用于 create 命令)\");\n console.log();\n console.log(chalk.yellow(\"项目示例:\"));\n console.log(\" xiaozhi create my-app # 创建基本项目\");\n console.log(\n \" xiaozhi create my-app -t hello-world # 使用 hello-world 模板\"\n );\n console.log(\n \" xiaozhi create my-app --template hello-world # 同上,完整选项名\"\n );\n console.log();\n console.log(chalk.yellow(\"配置示例:\"));\n console.log(\" xiaozhi init # 初始化配置\");\n console.log(\" xiaozhi config mcpEndpoint # 查看 MCP 端点\");\n console.log(\" xiaozhi config mcpEndpoint wss://... # 设置 MCP 端点\");\n console.log();\n console.log(chalk.yellow(\"服务示例:\"));\n console.log(\" xiaozhi start # 前台启动服务\");\n console.log(\" xiaozhi start --daemon # 后台启动服务\");\n console.log(\" xiaozhi status # 检查服务状态\");\n console.log(\" xiaozhi attach # 查看后台服务日志\");\n console.log(\" xiaozhi stop # 停止服务\");\n console.log();\n console.log(chalk.yellow(\"MCP 管理示例:\"));\n console.log(\" xiaozhi mcp list # 列出所有 MCP 服务\");\n console.log(\" xiaozhi mcp list --tools # 列出所有服务的工具\");\n console.log(\" xiaozhi mcp server <name> # 列出指定服务的工具\");\n console.log(\" xiaozhi mcp tool <server> <tool> enable # 启用工具\");\n console.log(\" xiaozhi mcp tool <server> <tool> disable # 禁用工具\");\n console.log();\n console.log(chalk.yellow(\"自动补全:\"));\n console.log(\" xiaozhi completion # 显示自动补全设置说明\");\n console.log(\" # 设置后可使用 Tab 键进行命令、参数自动补全\");\n}\n\n// 配置 Commander 程序\nprogram\n .name(\"xiaozhi\")\n .description(\"MCP Calculator Service CLI Tool\")\n .version(getVersion(), \"-v, --version\", \"显示版本信息\")\n .helpOption(\"-h, --help\", \"显示帮助信息\");\n\n// create 命令\nprogram\n .command(\"create <projectName>\")\n .description(\"创建项目\")\n .option(\"-t, --template <templateName>\", \"使用指定模板创建项目\")\n .action(async (projectName, options) => {\n await createProject(projectName, options);\n });\n\n// init 命令\nprogram\n .command(\"init\")\n .description(\"初始化配置文件\")\n .action(async () => {\n await initConfig();\n });\n\n// config 命令\nprogram\n .command(\"config <key> [value]\")\n .description(\"查看或设置配置\")\n .action(async (key, value) => {\n await configCommand(key, value);\n });\n\n// start 命令\nprogram\n .command(\"start\")\n .description(\"启动服务\")\n .option(\"-d, --daemon\", \"在后台运行服务\")\n .action(async (options) => {\n await startService(options.daemon);\n });\n\n// stop 命令\nprogram\n .command(\"stop\")\n .description(\"停止服务\")\n .action(async () => {\n await stopService();\n });\n\n// status 命令\nprogram\n .command(\"status\")\n .description(\"检查服务状态\")\n .action(async () => {\n await checkStatus();\n });\n\n// attach 命令\nprogram\n .command(\"attach\")\n .description(\"连接到后台服务查看日志\")\n .action(async () => {\n await attachService();\n });\n\n// restart 命令\nprogram\n .command(\"restart\")\n .description(\"重启服务\")\n .option(\"-d, --daemon\", \"在后台运行服务\")\n .action(async (options) => {\n await restartService(options.daemon);\n });\n\n// mcp 命令组\nconst mcpCommand = program.command(\"mcp\").description(\"MCP 服务和工具管理\");\n\n// mcp list 命令\nmcpCommand\n .command(\"list\")\n .description(\"列出 MCP 服务\")\n .option(\"--tools\", \"显示所有服务的工具列表\")\n .action(async (options) => {\n await listMcpServers(options);\n });\n\n// mcp <server> list 命令\nmcpCommand\n .command(\"server <serverName>\")\n .description(\"管理指定的 MCP 服务\")\n .action(async (serverName) => {\n await listServerTools(serverName);\n });\n\n// mcp <server> <tool> enable/disable 命令\nmcpCommand\n .command(\"tool <serverName> <toolName> <action>\")\n .description(\"启用或禁用指定服务的工具\")\n .action(async (serverName, toolName, action) => {\n if (action !== \"enable\" && action !== \"disable\") {\n console.error(chalk.red(\"错误: 操作必须是 'enable' 或 'disable'\"));\n process.exit(1);\n }\n\n const enabled = action === \"enable\";\n await setToolEnabled(serverName, toolName, enabled);\n });\n\n// completion 命令\nprogram\n .command(\"completion\")\n .description(\"显示自动补全设置说明\")\n .action(async () => {\n showCompletionHelp();\n });\n\n// -V 选项 (详细信息)\nprogram.option(\"-V\", \"显示详细信息\").action((options) => {\n if (options.V) {\n showDetailedInfo();\n process.exit(0);\n }\n});\n\n// 设置自动补全\nsetupAutoCompletion();\n\n// 处理无参数情况,显示帮助\nif (process.argv.length <= 2) {\n showHelp();\n process.exit(0);\n}\n\n// 解析命令行参数\nprogram.parse(process.argv);\n","import omelette from \"omelette\";\nimport { configManager } from \"./configManager\";\n\n/**\n * 自动补全功能模块\n */\n\n/**\n * 获取所有可用的MCP服务器名称\n */\nfunction getMcpServerNames(): string[] {\n try {\n if (!configManager.configExists()) {\n return [];\n }\n const mcpServers = configManager.getMcpServers();\n return Object.keys(mcpServers);\n } catch (error) {\n return [];\n }\n}\n\n/**\n * 获取指定服务器的工具名称\n */\nfunction getServerToolNames(serverName: string): string[] {\n try {\n if (!configManager.configExists()) {\n return [];\n }\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n return Object.keys(toolsConfig);\n } catch (error) {\n return [];\n }\n}\n\n/**\n * 设置自动补全功能\n */\nexport function setupAutoCompletion(): void {\n // 创建 omelette 实例,使用简单的模板\n const completion = omelette(\"xiaozhi <command>\");\n\n // 处理主命令补全\n completion.on(\"command\", ({ reply }) => {\n reply([\n \"create\",\n \"init\",\n \"config\",\n \"start\",\n \"stop\",\n \"status\",\n \"attach\",\n \"restart\",\n \"mcp\",\n \"completion\",\n ]);\n });\n\n // 处理复杂的多级命令补全\n completion.on(\"complete\", (fragment, { line, before, reply }) => {\n // 调试信息\n if (process.env.XIAOZHI_DEBUG_COMPLETION) {\n console.error(\n `Debug completion - line: \"${line}\", before: \"${before}\", fragment: \"${fragment}\"`\n );\n }\n\n const parts = line.trim().split(/\\s+/);\n const endsWithSpace = line !== line.trim();\n const currentIndex = endsWithSpace ? parts.length : parts.length - 1;\n\n // MCP 相关的补全\n if (parts[1] === \"mcp\") {\n const subcommand = parts[2];\n\n if (currentIndex === 2) {\n // mcp 子命令\n const subcommands = [\"list\", \"server\", \"tool\"];\n const current = parts[2] || \"\";\n const matches = subcommands.filter((cmd) => cmd.startsWith(current));\n reply(matches);\n return;\n }\n\n if (currentIndex === 3) {\n switch (subcommand) {\n case \"list\": {\n const options = [\"--tools\"];\n const current = parts[3] || \"\";\n const matches = options.filter((opt) => opt.startsWith(current));\n reply(matches);\n break;\n }\n case \"server\":\n case \"tool\": {\n const serverNames = getMcpServerNames();\n const current = parts[3] || \"\";\n const matches = serverNames.filter((name) =>\n name.startsWith(current)\n );\n reply(matches);\n break;\n }\n default:\n reply([]);\n }\n return;\n }\n\n if (currentIndex === 4 && subcommand === \"tool\") {\n const serverName = parts[3];\n const toolNames = getServerToolNames(serverName);\n const current = parts[4] || \"\";\n const matches = toolNames.filter((name) => name.startsWith(current));\n reply(matches);\n return;\n }\n\n if (currentIndex === 5 && subcommand === \"tool\") {\n const actions = [\"enable\", \"disable\"];\n const current = parts[5] || \"\";\n const matches = actions.filter((action) => action.startsWith(current));\n reply(matches);\n return;\n }\n }\n\n // 其他命令的子参数补全\n if (currentIndex === 2) {\n const command = parts[1];\n switch (command) {\n case \"create\":\n reply([\"--template\", \"-t\"]);\n break;\n case \"start\":\n case \"restart\":\n reply([\"--daemon\", \"-d\"]);\n break;\n case \"completion\":\n reply([\"install\", \"uninstall\"]);\n break;\n default:\n reply([]);\n }\n return;\n }\n\n // 默认情况\n reply([]);\n });\n\n // 处理补全相关的命令行参数\n if (process.argv.includes(\"--completion\")) {\n // 输出补全脚本供shell使用\n try {\n console.log(completion.setupShellInitFile());\n } catch (error) {\n console.error(\"生成自动补全脚本时出错:\", error);\n }\n process.exit(0);\n }\n\n if (process.argv.includes(\"--completion-fish\")) {\n // Fish shell 补全\n console.log(completion.setupShellInitFile(\"fish\"));\n process.exit(0);\n }\n\n if (\n process.argv.includes(\"--compzsh\") ||\n process.argv.includes(\"--compbash\")\n ) {\n // 处理实际的补全请求 - 这些是omelette内部使用的参数\n // 不需要手动处理,让omelette自己处理\n }\n\n // 初始化补全\n completion.init();\n}\n\n/**\n * 显示自动补全安装说明\n */\nexport function showCompletionHelp(): void {\n console.log(\"🚀 xiaozhi 自动补全设置\");\n console.log();\n console.log(\"要启用自动补全,请根据你的shell执行以下命令:\");\n console.log();\n console.log(\"📝 Zsh (推荐):\");\n console.log(\" xiaozhi --completion >> ~/.xiaozhi-completion.zsh\");\n console.log(\" echo 'source ~/.xiaozhi-completion.zsh' >> ~/.zshrc\");\n console.log(\" source ~/.zshrc\");\n console.log();\n console.log(\"📝 Bash:\");\n console.log(\" xiaozhi --completion >> ~/.xiaozhi-completion.bash\");\n console.log(\" echo 'source ~/.xiaozhi-completion.bash' >> ~/.bash_profile\");\n console.log(\" source ~/.bash_profile\");\n console.log();\n console.log(\"📝 Fish:\");\n console.log(\n \" xiaozhi --completion-fish >> ~/.config/fish/completions/xiaozhi.fish\"\n );\n console.log();\n console.log(\"✨ 设置完成后,你就可以使用 Tab 键进行自动补全了!\");\n console.log();\n console.log(\"💡 示例:\");\n console.log(\" xiaozhi m<Tab> # → mcp\");\n console.log(\" xiaozhi mcp l<Tab> # → list\");\n console.log(\" xiaozhi mcp tool <Tab> # → 显示所有服务器名称\");\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 配置文件接口定义\nexport interface MCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface AppConfig {\n mcpEndpoint: string;\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n\n private constructor() {\n this.defaultConfigPath = resolve(__dirname, \"xiaozhi.config.default.json\");\n }\n\n /**\n * 获取配置文件路径(动态计算)\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n const configPath = this.getConfigFilePath();\n return existsSync(configPath);\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n */\n public initConfig(): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(\"默认配置文件 xiaozhi.config.default.json 不存在\");\n }\n\n if (this.configExists()) {\n throw new Error(\"配置文件 xiaozhi.config.json 已存在,无需重复初始化\");\n }\n\n const configPath = this.getConfigFilePath();\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\n \"配置文件 xiaozhi.config.json 不存在,请先运行 xiaozhi init 初始化配置\"\n );\n }\n\n try {\n const configPath = this.getConfigFilePath();\n const configData = readFileSync(configPath, \"utf8\");\n const config = JSON.parse(configData) as AppConfig;\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (!configObj.mcpEndpoint || typeof configObj.mcpEndpoint !== \"string\") {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n const sc = serverConfig as Record<string, unknown>;\n if (!sc.command || typeof sc.command !== \"string\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.command 无效`\n );\n }\n\n if (!Array.isArray(sc.args)) {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.args 必须是数组`\n );\n }\n\n if (sc.env && typeof sc.env !== \"object\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.env 必须是对象`\n );\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取 MCP 端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n return config.mcpEndpoint;\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点\n */\n public updateMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getConfig();\n const newConfig = { ...config, mcpEndpoint: endpoint };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 验证服务配置\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n throw new Error(\"服务配置的 command 字段必须是非空字符串\");\n }\n\n if (!Array.isArray(serverConfig.args)) {\n throw new Error(\"服务配置的 args 字段必须是数组\");\n }\n\n if (serverConfig.env && typeof serverConfig.env !== \"object\") {\n throw new Error(\"服务配置的 env 字段必须是对象\");\n }\n\n const config = this.getConfig();\n const newConfig = {\n ...config,\n mcpServers: {\n ...config.mcpServers,\n [serverName]: serverConfig,\n },\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getConfig();\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n const newMcpServers = { ...config.mcpServers };\n delete newMcpServers[serverName];\n\n const newConfig = {\n ...config,\n mcpServers: newMcpServers,\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 更新指定服务的工具配置\n newConfig.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!newConfig.mcpServerConfig[serverName]) {\n newConfig.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n newConfig.mcpServerConfig[serverName].tools[toolName] = {\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 保存配置到文件\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 格式化 JSON 并保存\n const configPath = this.getConfigFilePath();\n const configJson = JSON.stringify(config, null, 2);\n writeFileSync(configPath, configJson, \"utf8\");\n\n // 更新缓存\n this.config = config;\n } catch (error) {\n throw new Error(\n `保存配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n","import chalk from \"chalk\";\nimport Table from \"cli-table3\";\nimport ora from \"ora\";\nimport { configManager } from \"./configManager\";\n\n/**\n * MCP 相关的命令行功能\n */\n\n/**\n * 计算字符串的显示宽度(中文字符占2个宽度,英文字符占1个宽度)\n */\nexport function getDisplayWidth(str: string): number {\n let width = 0;\n for (const char of str) {\n // 判断是否为中文字符(包括中文标点符号)\n if (/[\\u4e00-\\u9fff\\u3400-\\u4dbf\\uff00-\\uffef]/.test(char)) {\n width += 2;\n } else {\n width += 1;\n }\n }\n return width;\n}\n\n/**\n * 截断字符串到指定的显示宽度\n */\nexport function truncateToWidth(str: string, maxWidth: number): string {\n if (getDisplayWidth(str) <= maxWidth) {\n return str;\n }\n\n // 如果最大宽度小于等于省略号的宽度,返回空字符串\n if (maxWidth <= 3) {\n return \"\";\n }\n\n let result = \"\";\n let currentWidth = 0;\n let hasAddedChar = false;\n\n for (const char of str) {\n const charWidth = /[\\u4e00-\\u9fff\\u3400-\\u4dbf\\uff00-\\uffef]/.test(char)\n ? 2\n : 1;\n\n // 如果加上当前字符会超出限制\n if (currentWidth + charWidth > maxWidth - 3) {\n // 如果还没有添加任何字符,说明连一个字符都放不下,返回空字符串\n if (!hasAddedChar) {\n return \"\";\n }\n // 否则添加省略号并退出\n result += \"...\";\n break;\n }\n\n result += char;\n currentWidth += charWidth;\n hasAddedChar = true;\n }\n\n return result;\n}\n\n/**\n * 列出所有 MCP 服务\n */\nexport async function listMcpServers(\n options: { tools?: boolean } = {}\n): Promise<void> {\n const spinner = ora(\"获取 MCP 服务列表...\").start();\n\n try {\n const mcpServers = configManager.getMcpServers();\n const serverNames = Object.keys(mcpServers);\n\n if (serverNames.length === 0) {\n spinner.warn(\"未配置任何 MCP 服务\");\n console.log(\n chalk.yellow(\"💡 提示: 使用 'xiaozhi config' 命令配置 MCP 服务\")\n );\n return;\n }\n\n spinner.succeed(`找到 ${serverNames.length} 个 MCP 服务`);\n\n if (options.tools) {\n // 显示所有服务的工具列表\n console.log();\n console.log(chalk.bold(\"MCP 服务工具列表:\"));\n console.log();\n\n // 计算所有工具名称的最大长度,用于动态设置列宽\n let maxToolNameWidth = 8; // 默认最小宽度\n const allToolNames: string[] = [];\n\n for (const serverName of serverNames) {\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n allToolNames.push(...toolNames);\n }\n\n // 计算最长工具名称的显示宽度\n for (const toolName of allToolNames) {\n const width = getDisplayWidth(toolName);\n if (width > maxToolNameWidth) {\n maxToolNameWidth = width;\n }\n }\n\n // 确保工具名称列宽度至少为10,最多为30\n maxToolNameWidth = Math.max(10, Math.min(maxToolNameWidth + 2, 30));\n\n // 使用 cli-table3 创建表格\n const table = new Table({\n head: [\n chalk.bold(\"MCP\"),\n chalk.bold(\"工具名称\"),\n chalk.bold(\"状态\"),\n chalk.bold(\"描述\"),\n ],\n colWidths: [15, maxToolNameWidth, 8, 40], // MCP | 工具名称 | 状态 | 描述\n wordWrap: true,\n style: {\n head: [],\n border: [],\n },\n });\n\n for (const serverName of serverNames) {\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n\n if (toolNames.length === 0) {\n // 服务没有工具时显示提示信息\n table.push([\n chalk.gray(serverName),\n chalk.gray(\"(无工具)\"),\n chalk.gray(\"-\"),\n chalk.gray(\"请先启动服务扫描工具\"),\n ]);\n } else {\n // 添加服务分隔行\n if (table.length > 0) {\n table.push([{ colSpan: 4, content: \"\" }]);\n }\n\n for (const toolName of toolNames) {\n const toolConfig = toolsConfig[toolName];\n const status = toolConfig.enable\n ? chalk.green(\"启用\")\n : chalk.red(\"禁用\");\n\n // 截断描述到最大32个字符宽度(约16个中文字符)\n const description = truncateToWidth(\n toolConfig.description || \"\",\n 32\n );\n\n // 只显示工具名称,不包含服务名前缀\n table.push([serverName, toolName, status, description]);\n }\n }\n }\n\n console.log(table.toString());\n } else {\n // 只显示服务列表\n console.log();\n console.log(chalk.bold(\"MCP 服务列表:\"));\n console.log();\n\n for (const serverName of serverNames) {\n const serverConfig = mcpServers[serverName];\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolCount = Object.keys(toolsConfig).length;\n const enabledCount = Object.values(toolsConfig).filter(\n (t) => t.enable !== false\n ).length;\n\n console.log(`${chalk.cyan(\"•\")} ${chalk.bold(serverName)}`);\n console.log(\n ` 命令: ${chalk.gray(serverConfig.command)} ${chalk.gray(\n serverConfig.args.join(\" \")\n )}`\n );\n if (toolCount > 0) {\n console.log(\n ` 工具: ${chalk.green(enabledCount)} 启用 / ${chalk.yellow(\n toolCount\n )} 总计`\n );\n } else {\n console.log(` 工具: ${chalk.gray(\"未扫描 (请先启动服务)\")}`);\n }\n console.log();\n }\n }\n\n console.log(chalk.gray(\"💡 提示:\"));\n console.log(chalk.gray(\" - 使用 'xiaozhi mcp list --tools' 查看所有工具\"));\n console.log(\n chalk.gray(\" - 使用 'xiaozhi mcp <服务名> list' 查看指定服务的工具\")\n );\n console.log(\n chalk.gray(\n \" - 使用 'xiaozhi mcp <服务名> <工具名> enable/disable' 启用/禁用工具\"\n )\n );\n } catch (error) {\n spinner.fail(\"获取 MCP 服务列表失败\");\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n}\n\n/**\n * 列出指定服务的工具\n */\nexport async function listServerTools(serverName: string): Promise<void> {\n const spinner = ora(`获取 ${serverName} 服务的工具列表...`).start();\n\n try {\n const mcpServers = configManager.getMcpServers();\n\n if (!mcpServers[serverName]) {\n spinner.fail(`服务 '${serverName}' 不存在`);\n console.log(\n chalk.yellow(\"💡 提示: 使用 'xiaozhi mcp list' 查看所有可用服务\")\n );\n return;\n }\n\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n\n if (toolNames.length === 0) {\n spinner.warn(`服务 '${serverName}' 暂无工具信息`);\n console.log(chalk.yellow(\"💡 提示: 请先启动服务以扫描工具列表\"));\n return;\n }\n\n spinner.succeed(`服务 '${serverName}' 共有 ${toolNames.length} 个工具`);\n\n console.log();\n console.log(chalk.bold(`${serverName} 服务工具列表:`));\n console.log();\n\n // 使用 cli-table3 创建表格\n const table = new Table({\n head: [chalk.bold(\"工具名称\"), chalk.bold(\"状态\"), chalk.bold(\"描述\")],\n colWidths: [30, 8, 50], // 工具名称 | 状态 | 描述\n wordWrap: true,\n style: {\n head: [],\n border: [],\n },\n });\n\n for (const toolName of toolNames) {\n const toolConfig = toolsConfig[toolName];\n const status = toolConfig.enable\n ? chalk.green(\"启用\")\n : chalk.red(\"禁用\");\n\n // 截断描述到最大40个字符宽度(约20个中文字符)\n const description = truncateToWidth(toolConfig.description || \"\", 40);\n\n table.push([toolName, status, description]);\n }\n\n console.log(table.toString());\n\n console.log();\n console.log(chalk.gray(\"💡 提示:\"));\n console.log(\n chalk.gray(\n ` - 使用 'xiaozhi mcp ${serverName} <工具名> enable' 启用工具`\n )\n );\n console.log(\n chalk.gray(\n ` - 使用 'xiaozhi mcp ${serverName} <工具名> disable' 禁用工具`\n )\n );\n } catch (error) {\n spinner.fail(\"获取工具列表失败\");\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n}\n\n/**\n * 启用或禁用工具\n */\nexport async function setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean\n): Promise<void> {\n const action = enabled ? \"启用\" : \"禁用\";\n const spinner = ora(`${action}工具 ${serverName}/${toolName}...`).start();\n\n try {\n const mcpServers = configManager.getMcpServers();\n\n if (!mcpServers[serverName]) {\n spinner.fail(`服务 '${serverName}' 不存在`);\n console.log(\n chalk.yellow(\"💡 提示: 使用 'xiaozhi mcp list' 查看所有可用服务\")\n );\n return;\n }\n\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n\n if (!toolsConfig[toolName]) {\n spinner.fail(`工具 '${toolName}' 在服务 '${serverName}' 中不存在`);\n console.log(\n chalk.yellow(\n `💡 提示: 使用 'xiaozhi mcp ${serverName} list' 查看该服务的所有工具`\n )\n );\n return;\n }\n\n // 更新工具状态\n configManager.setToolEnabled(\n serverName,\n toolName,\n enabled,\n toolsConfig[toolName].description\n );\n\n spinner.succeed(\n `成功${action}工具 ${chalk.cyan(serverName)}/${chalk.cyan(toolName)}`\n );\n\n console.log();\n console.log(chalk.gray(\"💡 提示: 工具状态更改将在下次启动服务时生效\"));\n } catch (error) {\n spinner.fail(`${action}工具失败`);\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["spawn","fs","os","path","fileURLToPath","chalk","Command","ora","omelette","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","__dirname","dirname","fileURLToPath","ConfigManager","_ConfigManager","__name","resolve","configDir","configPath","existsSync","copyFileSync","configData","readFileSync","config","error","configObj","serverName","serverConfig","sc","toolName","endpoint","newConfig","newMcpServers","toolsConfig","enabled","description","configJson","writeFileSync","configManager","getMcpServerNames","configManager","mcpServers","__name","getServerToolNames","serverName","toolsConfig","setupAutoCompletion","completion","omelette","reply","fragment","line","before","parts","currentIndex","subcommand","subcommands","current","matches","cmd","options","opt","serverNames","name","toolNames","actions","action","error","showCompletionHelp","chalk","Table","ora","getDisplayWidth","str","width","char","__name","truncateToWidth","maxWidth","result","currentWidth","hasAddedChar","charWidth","listMcpServers","options","spinner","ora","mcpServers","configManager","serverNames","chalk","maxToolNameWidth","allToolNames","serverName","toolsConfig","toolNames","toolName","table","Table","toolConfig","status","description","serverConfig","toolCount","enabledCount","t","error","listServerTools","setToolEnabled","enabled","action","program","Command","SERVICE_NAME","getVersion","__filename","fileURLToPath","currentDir","path","possiblePaths","packagePath","fs","packageJson","error","__name","PID_FILE","os","LOG_FILE","getServiceStatus","pidContent","pidStr","startTime","mode","pid","start","uptime","formatUptime","ms","seconds","minutes","hours","days","savePidInfo","pidInfo","cleanupPidFile","checkEnvironment","configManager","chalk","endpoint","getServiceCommand","scriptDir","distDir","p","startService","daemon","spinner","ora","status","command","args","cwd","child","spawn","logStream","code","signal","errorLog","stopService","attempts","maxAttempts","resolve","checkStatus","attachService","tail","restartService","showDetailedInfo","version","initConfig","getAvailableTemplates","templatesDir","item","itemPath","calculateSimilarity","str1","str2","len1","len2","matrix","i","j","maxLen","findSimilarTemplate","input","templates","bestMatch","bestSimilarity","template","similarity","askUserConfirmation","question","readline","rl","handleInput","char","createBasicConfig","projectPath","configContent","configPath","createProject","projectName","options","targetPath","availableTemplates","similarTemplate","templatePath","copyDirectory","src","dest","excludePatterns","items","pattern","srcPath","destPath","configCommand","key","value","config","name","serverConfig","showHelp","mcpCommand","listMcpServers","serverName","listServerTools","toolName","action","setToolEnabled","showCompletionHelp","setupAutoCompletion"]}
package/dist/mcpPipe.d.ts CHANGED
@@ -25,10 +25,17 @@ declare class MCPPipe {
25
25
  private shouldReconnect;
26
26
  private isConnected;
27
27
  private shutdownResolve?;
28
+ private heartbeatTimer?;
29
+ private heartbeatTimeoutTimer?;
30
+ private reconnectTimer?;
31
+ private mcpProcessRestartAttempts;
28
32
  constructor(mcpScript: string, endpointUrl: string);
29
33
  start(): Promise<void>;
30
34
  connectToServer(): Promise<void>;
31
35
  scheduleReconnect(): void;
36
+ private startHeartbeat;
37
+ private stopHeartbeat;
38
+ private restartMCPProcess;
32
39
  startMCPProcess(): void;
33
40
  cleanup(): void;
34
41
  sleep(ms: number): Promise<void>;
package/dist/mcpPipe.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- var S=Object.defineProperty;var c=(r,e)=>S(r,"name",{value:e,configurable:!0});import{spawn as y}from"child_process";import n from"process";import{fileURLToPath as x}from"url";import{config as I}from"dotenv";import C from"ws";import{copyFileSync as b,existsSync as u,readFileSync as P,writeFileSync as E}from"fs";import{dirname as M,resolve as m}from"path";import{fileURLToPath as R}from"url";var $=M(R(import.meta.url)),h=class r{static{c(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=m($,"xiaozhi.config.default.json")}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return m(e,"xiaozhi.config.json")}static getInstance(){return r.instance||(r.instance=new r),r.instance}configExists(){let e=this.getConfigFilePath();return u(e)}initConfig(){if(!u(this.defaultConfigPath))throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.default.json \u4E0D\u5B58\u5728");if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let e=this.getConfigFilePath();b(this.defaultConfigPath,e),this.config=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let e=this.getConfigFilePath(),t=P(e,"utf8"),o=JSON.parse(t);return this.validateConfig(o),o}catch(e){throw e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let t=e;if(!t.mcpEndpoint||typeof t.mcpEndpoint!="string")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(!t.mcpServers||typeof t.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[o,s]of Object.entries(t.mcpServers)){if(!s||typeof s!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o} \u65E0\u6548`);let g=s;if(!g.command||typeof g.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.command \u65E0\u6548`);if(!Array.isArray(g.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.args \u5FC5\u987B\u662F\u6570\u7EC4`);if(g.env&&typeof g.env!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o}.env \u5FC5\u987B\u662F\u5BF9\u8C61`)}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMcpEndpoint(){return this.getConfig().mcpEndpoint}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,t){return this.getServerToolsConfig(e)[t]?.enable!==!1}updateMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let o={...this.getConfig(),mcpEndpoint:e};this.saveConfig(o)}updateMcpServer(e,t){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!t.command||typeof t.command!="string")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 command \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!Array.isArray(t.args))throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4");if(t.env&&typeof t.env!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61");let o=this.getConfig(),s={...o,mcpServers:{...o.mcpServers,[e]:t}};this.saveConfig(s)}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 s={...t,mcpServers:o};this.saveConfig(s)}updateServerToolsConfig(e,t){let s={...this.getConfig()};s.mcpServerConfig||(s.mcpServerConfig={}),s.mcpServerConfig[e]={tools:t},this.saveConfig(s)}setToolEnabled(e,t,o,s){let f={...this.getConfig()};f.mcpServerConfig||(f.mcpServerConfig={}),f.mcpServerConfig[e]||(f.mcpServerConfig[e]={tools:{}}),f.mcpServerConfig[e].tools[t]={enable:o,...s&&{description:s}},this.saveConfig(f)}saveConfig(e){try{this.validateConfig(e);let t=this.getConfigFilePath(),o=JSON.stringify(e,null,2);E(t,o,"utf8"),this.config=e}catch(t){throw new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}reloadConfig(){this.config=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}},a=h.getInstance();I();var l=class{static{c(this,"Logger")}name;constructor(e){this.name=e}info(e){let t=new Date().toISOString();console.error(`${t} - ${this.name} - INFO - ${e}`)}error(e){let t=new Date().toISOString();console.error(`${t} - ${this.name} - ERROR - ${e}`)}warning(e){let t=new Date().toISOString();console.error(`${t} - ${this.name} - WARNING - ${e}`)}debug(e){let t=new Date().toISOString();console.error(`${t} - ${this.name} - DEBUG - ${e}`)}},i=new l("MCP_PIPE"),v=1e3,k=3e4,p=0,w=v,d=class{static{c(this,"MCPPipe")}mcpScript;endpointUrl;process;websocket;shouldReconnect;isConnected;shutdownResolve;constructor(e,t){this.mcpScript=e,this.endpointUrl=t,this.process=null,this.websocket=null,this.shouldReconnect=!0,this.isConnected=!1}async start(){return this.startMCPProcess(),await this.connectToServer(),new Promise(e=>{this.shutdownResolve=e})}async connectToServer(){this.isConnected||(i.info("Connecting to WebSocket server..."),this.websocket=new C(this.endpointUrl),this.websocket.on("open",()=>{i.info("Successfully connected to WebSocket server"),this.isConnected=!0,p=0,w=v}),this.websocket.on("message",e=>{let t=e.toString();i.debug(`<< ${t.substring(0,120)}...`),this.process?.stdin&&!this.process.stdin.destroyed&&this.process.stdin.write(`${t}
3
- `)}),this.websocket.on("close",(e,t)=>{i.error(`WebSocket connection closed: ${e} ${t}`),this.isConnected=!1,this.websocket=null,this.shouldReconnect&&e!==4004&&this.scheduleReconnect()}),this.websocket.on("error",e=>{i.error(`WebSocket error: ${e.message}`),this.isConnected=!1}))}scheduleReconnect(){if(!this.shouldReconnect)return;p++;let e=Math.min(w*2**(p-1),k);i.info(`Scheduling reconnection attempt ${p} in ${(e/1e3).toFixed(2)} seconds...`),setTimeout(()=>{this.shouldReconnect&&this.connectToServer()},e)}startMCPProcess(){if(this.process){i.info(`${this.mcpScript} process already running`);return}i.info(`Starting ${this.mcpScript} process`),this.process=y("node",[this.mcpScript],{stdio:["pipe","pipe","pipe"]}),this.process.stdout?.on("data",e=>{let t=e.toString();i.debug(`>> ${t.substring(0,120)}...`),this.websocket&&this.websocket.readyState===C.OPEN&&this.websocket.send(t)}),this.process.stderr?.on("data",e=>{n.stderr.write(e)}),this.process.on("exit",(e,t)=>{i.info(`${this.mcpScript} process exited with code ${e}, signal ${t}`),this.process=null,this.shouldReconnect=!1,this.websocket&&this.websocket.close()}),this.process.on("error",e=>{i.error(`Process error: ${e.message}`),this.process=null,this.shouldReconnect=!1,this.websocket&&this.websocket.close()})}cleanup(){if(this.process){i.info(`Terminating ${this.mcpScript} process`);try{this.process.kill("SIGTERM"),setTimeout(()=>{this.process&&!this.process.killed&&this.process.kill("SIGKILL")},5e3)}catch(e){i.error(`Error terminating process: ${e instanceof Error?e.message:String(e)}`)}this.process=null}this.websocket&&(this.websocket=null),this.isConnected=!1}sleep(e){return new Promise(t=>setTimeout(t,e))}shutdown(){i.info("Shutting down MCP Pipe..."),this.shouldReconnect=!1,this.cleanup(),this.websocket&&this.websocket.close(),this.shutdownResolve&&this.shutdownResolve(),n.exit(0)}};function T(r){n.on("SIGINT",()=>{i.info("Received interrupt signal, shutting down..."),r.shutdown()}),n.on("SIGTERM",()=>{i.info("Received terminate signal, shutting down..."),r.shutdown()})}c(T,"setupSignalHandlers");async function O(){n.argv.length<3&&(i.error("Usage: node mcp_pipe.js <mcp_script>"),n.exit(1));let r=n.argv[2],e;try{n.stderr.write(`[DEBUG] XIAOZHI_CONFIG_DIR: ${n.env.XIAOZHI_CONFIG_DIR}
4
- `),n.stderr.write(`[DEBUG] process.cwd(): ${n.cwd()}
5
- `),n.stderr.write(`[DEBUG] configManager.getConfigPath(): ${a.getConfigPath()}
6
- `),n.stderr.write(`[DEBUG] configManager.configExists(): ${a.configExists()}
7
- `),a.configExists()?(e=a.getMcpEndpoint(),i.info("\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\u4E2D\u7684 MCP \u7AEF\u70B9")):(e=n.env.MCP_ENDPOINT||"",e||(i.error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\u4E14\u672A\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF"),i.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),n.exit(1)),i.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\uFF08\u5EFA\u8BAE\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\uFF09"))}catch(o){i.error(`\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`),e=n.env.MCP_ENDPOINT||"",e||(i.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),n.exit(1)),i.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\u4F5C\u4E3A\u5907\u7528\u65B9\u6848")}(!e||e.includes("<\u8BF7\u586B\u5199"))&&(i.error("MCP \u7AEF\u70B9\u672A\u914D\u7F6E\u6216\u914D\u7F6E\u65E0\u6548"),i.error('\u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9'),n.exit(1));let t=new d(r,e);T(t);try{await t.start()}catch(o){i.error(`Program execution error: ${o instanceof Error?o.message:String(o)}`),n.exit(1)}}c(O,"main");var D=import.meta.url,A=x(D),F=n.argv[1];A===F&&O().catch(r=>{i.error(`Unhandled error: ${r instanceof Error?r.message:String(r)}`),n.exit(1)});export{l as Logger,d as MCPPipe,T as setupSignalHandlers};
2
+ var w=Object.defineProperty;var c=(n,e)=>w(n,"name",{value:e,configurable:!0});import{spawn as M}from"child_process";import o from"process";import{fileURLToPath as $}from"url";import{config as y}from"dotenv";import h from"ws";import{copyFileSync as S,existsSync as u,readFileSync as b,writeFileSync as P}from"fs";import{dirname as T,resolve as C}from"path";import{fileURLToPath as E}from"url";var R=T(E(import.meta.url)),p=class n{static{c(this,"ConfigManager")}static instance;defaultConfigPath;config=null;constructor(){this.defaultConfigPath=C(R,"xiaozhi.config.default.json")}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd();return C(e,"xiaozhi.config.json")}static getInstance(){return n.instance||(n.instance=new n),n.instance}configExists(){let e=this.getConfigFilePath();return u(e)}initConfig(){if(!u(this.defaultConfigPath))throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.default.json \u4E0D\u5B58\u5728");if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let e=this.getConfigFilePath();S(this.defaultConfigPath,e),this.config=null}loadConfig(){if(!this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6 xiaozhi.config.json \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");try{let e=this.getConfigFilePath(),t=b(e,"utf8"),r=JSON.parse(t);return this.validateConfig(r),r}catch(e){throw e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let t=e;if(!t.mcpEndpoint||typeof t.mcpEndpoint!="string")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(!t.mcpServers||typeof t.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[r,s]of Object.entries(t.mcpServers)){if(!s||typeof s!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${r} \u65E0\u6548`);let a=s;if(!a.command||typeof a.command!="string")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${r}.command \u65E0\u6548`);if(!Array.isArray(a.args))throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${r}.args \u5FC5\u987B\u662F\u6570\u7EC4`);if(a.env&&typeof a.env!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${r}.env \u5FC5\u987B\u662F\u5BF9\u8C61`)}}getConfig(){return this.config||(this.config=this.loadConfig()),JSON.parse(JSON.stringify(this.config))}getMcpEndpoint(){return this.getConfig().mcpEndpoint}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,t){return this.getServerToolsConfig(e)[t]?.enable!==!1}updateMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let r={...this.getConfig(),mcpEndpoint:e};this.saveConfig(r)}updateMcpServer(e,t){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!t.command||typeof t.command!="string")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 command \u5B57\u6BB5\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");if(!Array.isArray(t.args))throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4");if(t.env&&typeof t.env!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61");let r=this.getConfig(),s={...r,mcpServers:{...r.mcpServers,[e]:t}};this.saveConfig(s)}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 r={...t.mcpServers};delete r[e];let s={...t,mcpServers:r};this.saveConfig(s)}updateServerToolsConfig(e,t){let s={...this.getConfig()};s.mcpServerConfig||(s.mcpServerConfig={}),s.mcpServerConfig[e]={tools:t},this.saveConfig(s)}setToolEnabled(e,t,r,s){let g={...this.getConfig()};g.mcpServerConfig||(g.mcpServerConfig={}),g.mcpServerConfig[e]||(g.mcpServerConfig[e]={tools:{}}),g.mcpServerConfig[e].tools[t]={enable:r,...s&&{description:s}},this.saveConfig(g)}saveConfig(e){try{this.validateConfig(e);let t=this.getConfigFilePath(),r=JSON.stringify(e,null,2);P(t,r,"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}},f=p.getInstance();y();var m=class{static{c(this,"Logger")}name;constructor(e){this.name=e}info(e){let t=new Date().toISOString();console.error(`${t} - ${this.name} - INFO - ${e}`)}error(e){let t=new Date().toISOString();console.error(`${t} - ${this.name} - ERROR - ${e}`)}warning(e){let t=new Date().toISOString();console.error(`${t} - ${this.name} - WARNING - ${e}`)}debug(e){let t=new Date().toISOString();console.error(`${t} - ${this.name} - DEBUG - ${e}`)}},i=new m("MCP_PIPE"),v=5e3,I=3e4,x=1e4,l=0,d=class{static{c(this,"MCPPipe")}mcpScript;endpointUrl;process;websocket;shouldReconnect;isConnected;shutdownResolve;heartbeatTimer;heartbeatTimeoutTimer;reconnectTimer;mcpProcessRestartAttempts;constructor(e,t){this.mcpScript=e,this.endpointUrl=t,this.process=null,this.websocket=null,this.shouldReconnect=!0,this.isConnected=!1,this.mcpProcessRestartAttempts=0}async start(){return this.startMCPProcess(),await this.connectToServer(),new Promise(e=>{this.shutdownResolve=e})}async connectToServer(){this.isConnected||(i.info("Connecting to WebSocket server..."),this.websocket=new h(this.endpointUrl),this.websocket.on("open",()=>{i.info("Successfully connected to WebSocket server"),this.isConnected=!0,l=0,this.mcpProcessRestartAttempts=0,this.startHeartbeat()}),this.websocket.on("message",e=>{let t=e.toString();i.debug(`<< ${t.substring(0,120)}...`),this.process?.stdin&&!this.process.stdin.destroyed&&this.process.stdin.write(`${t}
3
+ `)}),this.websocket.on("close",(e,t)=>{i.error(`WebSocket connection closed: ${e} ${t}`),this.isConnected=!1,this.websocket=null,this.stopHeartbeat(),this.shouldReconnect&&e!==4004&&this.scheduleReconnect()}),this.websocket.on("error",e=>{i.error(`WebSocket error: ${e.message}`),this.isConnected=!1,this.stopHeartbeat()}),this.websocket.on("pong",()=>{this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=void 0)}))}scheduleReconnect(){this.shouldReconnect&&(this.reconnectTimer&&clearTimeout(this.reconnectTimer),l++,i.info(`Scheduling reconnection attempt ${l} in ${(v/1e3).toFixed(2)} seconds...`),this.reconnectTimer=setTimeout(()=>{this.shouldReconnect&&((!this.process||this.process.killed)&&(i.info("MCP process not running, attempting to restart..."),this.restartMCPProcess()),this.connectToServer())},v))}startHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(()=>{this.websocket&&this.websocket.readyState===h.OPEN&&(this.websocket.ping(),this.heartbeatTimeoutTimer=setTimeout(()=>{i.warning("Heartbeat timeout, connection may be lost"),this.websocket&&this.websocket.terminate()},x))},I)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0),this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=void 0)}restartMCPProcess(){if(this.mcpProcessRestartAttempts>=3){i.error("MCP process restart attempts exceeded, giving up");return}if(this.mcpProcessRestartAttempts++,i.info(`Attempting to restart MCP process (attempt ${this.mcpProcessRestartAttempts})`),this.process){try{this.process.kill("SIGTERM")}catch(e){i.warning(`Error killing existing MCP process: ${e}`)}this.process=null}this.startMCPProcess()}startMCPProcess(){if(this.process){i.info(`${this.mcpScript} process already running`);return}i.info(`Starting ${this.mcpScript} process`),this.process=M("node",[this.mcpScript],{stdio:["pipe","pipe","pipe"]}),this.process.stdout?.on("data",e=>{let t=e.toString();i.debug(`>> ${t.substring(0,120)}...`),this.websocket&&this.websocket.readyState===h.OPEN&&this.websocket.send(t)}),this.process.stderr?.on("data",e=>{o.stderr.write(e)}),this.process.on("exit",(e,t)=>{i.warning(`${this.mcpScript} process exited with code ${e}, signal ${t}`),this.process=null,this.shouldReconnect&&t!=="SIGTERM"&&t!=="SIGKILL"&&i.info("MCP process unexpectedly exited, will attempt restart on next reconnection")}),this.process.on("error",e=>{i.error(`Process error: ${e.message}`),this.process=null,this.shouldReconnect&&i.info("MCP process error occurred, will attempt restart on next reconnection")})}cleanup(){if(this.stopHeartbeat(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=void 0),this.process){i.info(`Terminating ${this.mcpScript} process`);try{this.process.kill("SIGTERM"),setTimeout(()=>{this.process&&!this.process.killed&&this.process.kill("SIGKILL")},5e3)}catch(e){i.error(`Error terminating process: ${e instanceof Error?e.message:String(e)}`)}this.process=null}if(this.websocket){try{this.websocket.close()}catch(e){i.warning(`Error closing websocket: ${e}`)}this.websocket=null}this.isConnected=!1}sleep(e){return new Promise(t=>setTimeout(t,e))}shutdown(){i.info("Shutting down MCP Pipe..."),this.shouldReconnect=!1,this.cleanup(),this.websocket&&this.websocket.close(),this.shutdownResolve&&this.shutdownResolve(),o.exit(0)}};function k(n){let e=o.env.XIAOZHI_DAEMON==="true";o.on("SIGINT",()=>{i.info("Received interrupt signal, shutting down..."),n.shutdown()}),o.on("SIGTERM",()=>{i.info("Received terminate signal, shutting down..."),n.shutdown()}),e&&(o.on("SIGHUP",()=>{i.info("Received SIGHUP signal (terminal closed), continuing in daemon mode...")}),o.on("uncaughtException",t=>{i.error(`Uncaught exception in daemon mode: ${t.message}`),i.error(t.stack||"No stack trace available")}),o.on("unhandledRejection",(t,r)=>{i.error(`Unhandled promise rejection in daemon mode: ${t}`),i.error(`Promise: ${r}`)}),i.info("Daemon mode signal handlers initialized"))}c(k,"setupSignalHandlers");async function A(){o.argv.length<3&&(i.error("Usage: node mcp_pipe.js <mcp_script>"),o.exit(1));let n=o.argv[2],e;try{o.stderr.write(`[DEBUG] XIAOZHI_CONFIG_DIR: ${o.env.XIAOZHI_CONFIG_DIR}
4
+ `),o.stderr.write(`[DEBUG] process.cwd(): ${o.cwd()}
5
+ `),o.stderr.write(`[DEBUG] configManager.getConfigPath(): ${f.getConfigPath()}
6
+ `),o.stderr.write(`[DEBUG] configManager.configExists(): ${f.configExists()}
7
+ `),f.configExists()?(e=f.getMcpEndpoint(),i.info("\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\u4E2D\u7684 MCP \u7AEF\u70B9")):(e=o.env.MCP_ENDPOINT||"",e||(i.error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\u4E14\u672A\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF"),i.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),o.exit(1)),i.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\uFF08\u5EFA\u8BAE\u4F7F\u7528\u914D\u7F6E\u6587\u4EF6\uFF09"))}catch(r){i.error(`\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`),e=o.env.MCP_ENDPOINT||"",e||(i.error('\u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u6216\u8BBE\u7F6E MCP_ENDPOINT \u73AF\u5883\u53D8\u91CF'),o.exit(1)),i.info("\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u4E2D\u7684 MCP \u7AEF\u70B9\u4F5C\u4E3A\u5907\u7528\u65B9\u6848")}(!e||e.includes("<\u8BF7\u586B\u5199"))&&(i.error("MCP \u7AEF\u70B9\u672A\u914D\u7F6E\u6216\u914D\u7F6E\u65E0\u6548"),i.error('\u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9'),o.exit(1));let t=new d(n,e);k(t);try{await t.start()}catch(r){i.error(`Program execution error: ${r instanceof Error?r.message:String(r)}`),o.exit(1)}}c(A,"main");var O=import.meta.url,N=$(O),D=o.argv[1];N===D&&A().catch(n=>{i.error(`Unhandled error: ${n instanceof Error?n.message:String(n)}`),o.exit(1)});export{m as Logger,d as MCPPipe,k as setupSignalHandlers};
8
8
  //# sourceMappingURL=mcpPipe.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcpPipe.ts","../src/configManager.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Pipe - JavaScript Implementation\n * Connects to MCP server and pipes input/output to WebSocket endpoint\n * d\n * Version: 0.2.0\n *\n * Usage:\n * export MCP_ENDPOINT=<mcp_endpoint>\n * node mcp_pipe.js <mcp_script>\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\nimport { config } from \"dotenv\";\nimport WebSocket from \"ws\";\nimport { configManager } from \"./configManager\";\n\n// Load environment variables\nconfig();\n\n// Logger utility\nexport class Logger {\n private name: string;\n\n constructor(name: string) {\n this.name = name;\n }\n\n info(message: string): void {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - ${this.name} - INFO - ${message}`);\n }\n\n error(message: string): void {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - ${this.name} - ERROR - ${message}`);\n }\n\n warning(message: string): void {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - ${this.name} - WARNING - ${message}`);\n }\n\n debug(message: string): void {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - ${this.name} - DEBUG - ${message}`);\n }\n}\n\nconst logger = new Logger(\"MCP_PIPE\");\n\n// Reconnection settings\nconst INITIAL_BACKOFF = 1000; // Initial wait time in milliseconds\nconst MAX_BACKOFF = 30000; // Maximum wait time in milliseconds (reduced)\nlet reconnectAttempt = 0;\nlet backoff = INITIAL_BACKOFF;\n\nexport class MCPPipe {\n private mcpScript: string;\n private endpointUrl: string;\n private process: ChildProcess | null;\n private websocket: WebSocket | null;\n private shouldReconnect: boolean;\n private isConnected: boolean;\n private shutdownResolve?: () => void;\n\n constructor(mcpScript: string, endpointUrl: string) {\n this.mcpScript = mcpScript;\n this.endpointUrl = endpointUrl;\n this.process = null;\n this.websocket = null;\n this.shouldReconnect = true;\n this.isConnected = false;\n }\n\n async start() {\n // Start MCP script process\n this.startMCPProcess();\n\n // Start WebSocket connection\n await this.connectToServer();\n\n // Keep the process running\n return new Promise<void>((resolve) => {\n // This promise will only resolve when shutdown is called\n this.shutdownResolve = resolve;\n });\n }\n\n async connectToServer() {\n if (this.isConnected) {\n return;\n }\n\n logger.info(\"Connecting to WebSocket server...\");\n\n this.websocket = new WebSocket(this.endpointUrl);\n\n this.websocket.on(\"open\", () => {\n logger.info(\"Successfully connected to WebSocket server\");\n this.isConnected = true;\n\n // Reset reconnection counter\n reconnectAttempt = 0;\n backoff = INITIAL_BACKOFF;\n });\n\n this.websocket.on(\"message\", (data: WebSocket.Data) => {\n const message = data.toString();\n logger.debug(`<< ${message.substring(0, 120)}...`);\n\n // Write to process stdin\n if (this.process?.stdin && !this.process.stdin.destroyed) {\n this.process.stdin.write(`${message}\\n`);\n }\n });\n\n this.websocket.on(\"close\", (code: number, reason: Buffer) => {\n logger.error(`WebSocket connection closed: ${code} ${reason}`);\n this.isConnected = false;\n this.websocket = null;\n\n // Only reconnect if we should and it's not a permanent error\n if (this.shouldReconnect && code !== 4004) {\n this.scheduleReconnect();\n }\n });\n\n this.websocket.on(\"error\", (error: Error) => {\n logger.error(`WebSocket error: ${error.message}`);\n this.isConnected = false;\n });\n }\n\n scheduleReconnect() {\n if (!this.shouldReconnect) return;\n\n reconnectAttempt++;\n const waitTime = Math.min(\n backoff * 2 ** (reconnectAttempt - 1),\n MAX_BACKOFF\n );\n\n logger.info(\n `Scheduling reconnection attempt ${reconnectAttempt} in ${(waitTime / 1000).toFixed(2)} seconds...`\n );\n\n setTimeout(() => {\n if (this.shouldReconnect) {\n this.connectToServer();\n }\n }, waitTime);\n }\n\n startMCPProcess() {\n if (this.process) {\n logger.info(`${this.mcpScript} process already running`);\n return;\n }\n\n logger.info(`Starting ${this.mcpScript} process`);\n\n this.process = spawn(\"node\", [this.mcpScript], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n // Handle process stdout - send to WebSocket\n this.process.stdout?.on(\"data\", (data: Buffer) => {\n const message = data.toString();\n logger.debug(`>> ${message.substring(0, 120)}...`);\n\n if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {\n this.websocket.send(message);\n }\n });\n\n // Handle process stderr - print to terminal\n this.process.stderr?.on(\"data\", (data: Buffer) => {\n process.stderr.write(data);\n });\n\n // Handle process exit\n this.process.on(\n \"exit\",\n (code: number | null, signal: NodeJS.Signals | null) => {\n logger.info(\n `${this.mcpScript} process exited with code ${code}, signal ${signal}`\n );\n this.process = null;\n this.shouldReconnect = false;\n if (this.websocket) {\n this.websocket.close();\n }\n }\n );\n\n // Handle process error\n this.process.on(\"error\", (error: Error) => {\n logger.error(`Process error: ${error.message}`);\n this.process = null;\n this.shouldReconnect = false;\n if (this.websocket) {\n this.websocket.close();\n }\n });\n }\n\n cleanup() {\n if (this.process) {\n logger.info(`Terminating ${this.mcpScript} process`);\n try {\n this.process.kill(\"SIGTERM\");\n\n // Force kill after timeout\n setTimeout(() => {\n if (this.process && !this.process.killed) {\n this.process.kill(\"SIGKILL\");\n }\n }, 5000);\n } catch (error) {\n logger.error(\n `Error terminating process: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n this.process = null;\n }\n\n if (this.websocket) {\n this.websocket = null;\n }\n\n this.isConnected = false;\n }\n\n sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n shutdown() {\n logger.info(\"Shutting down MCP Pipe...\");\n this.shouldReconnect = false;\n this.cleanup();\n if (this.websocket) {\n this.websocket.close();\n }\n if (this.shutdownResolve) {\n this.shutdownResolve();\n }\n process.exit(0);\n }\n}\n\n// Signal handlers\nexport function setupSignalHandlers(mcpPipe: MCPPipe): void {\n process.on(\"SIGINT\", () => {\n logger.info(\"Received interrupt signal, shutting down...\");\n mcpPipe.shutdown();\n });\n\n process.on(\"SIGTERM\", () => {\n logger.info(\"Received terminate signal, shutting down...\");\n mcpPipe.shutdown();\n });\n}\n\n// Main execution\nasync function main() {\n // Check command line arguments\n if (process.argv.length < 3) {\n logger.error(\"Usage: node mcp_pipe.js <mcp_script>\");\n process.exit(1);\n }\n\n const mcpScript = process.argv[2];\n\n // Get endpoint URL from config file or environment variable (fallback)\n let endpointUrl: string;\n\n try {\n // 调试信息 - 使用 process.stderr.write 确保能看到\n process.stderr.write(\n `[DEBUG] XIAOZHI_CONFIG_DIR: ${process.env.XIAOZHI_CONFIG_DIR}\\n`\n );\n process.stderr.write(`[DEBUG] process.cwd(): ${process.cwd()}\\n`);\n process.stderr.write(\n `[DEBUG] configManager.getConfigPath(): ${configManager.getConfigPath()}\\n`\n );\n process.stderr.write(\n `[DEBUG] configManager.configExists(): ${configManager.configExists()}\\n`\n );\n\n // 首先尝试从配置文件读取\n if (configManager.configExists()) {\n endpointUrl = configManager.getMcpEndpoint();\n logger.info(\"使用配置文件中的 MCP 端点\");\n } else {\n // 如果配置文件不存在,尝试从环境变量读取(向后兼容)\n endpointUrl = process.env.MCP_ENDPOINT || \"\";\n if (!endpointUrl) {\n logger.error(\"配置文件不存在且未设置 MCP_ENDPOINT 环境变量\");\n logger.error(\n '请运行 \"xiaozhi init\" 初始化配置,或设置 MCP_ENDPOINT 环境变量'\n );\n process.exit(1);\n }\n logger.info(\"使用环境变量中的 MCP 端点(建议使用配置文件)\");\n }\n } catch (error) {\n logger.error(\n `读取配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n\n // 尝试从环境变量读取作为备用方案\n endpointUrl = process.env.MCP_ENDPOINT || \"\";\n if (!endpointUrl) {\n logger.error(\n '请运行 \"xiaozhi init\" 初始化配置,或设置 MCP_ENDPOINT 环境变量'\n );\n process.exit(1);\n }\n logger.info(\"使用环境变量中的 MCP 端点作为备用方案\");\n }\n\n // 验证端点 URL\n if (!endpointUrl || endpointUrl.includes(\"<请填写\")) {\n logger.error(\"MCP 端点未配置或配置无效\");\n logger.error(\n '请运行 \"xiaozhi config mcpEndpoint <your-endpoint-url>\" 设置端点'\n );\n process.exit(1);\n }\n\n // Create MCP Pipe instance\n const mcpPipe = new MCPPipe(mcpScript, endpointUrl);\n\n // Setup signal handlers\n setupSignalHandlers(mcpPipe);\n\n // Start the MCP pipe\n try {\n await mcpPipe.start();\n } catch (error) {\n logger.error(\n `Program execution error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n}\n\n// Run if this file is executed directly\n// Use fileURLToPath to properly handle Windows paths\nconst currentFileUrl = import.meta.url;\nconst scriptPath = fileURLToPath(currentFileUrl);\nconst argv1Path = process.argv[1];\n\nif (scriptPath === argv1Path) {\n main().catch((error) => {\n logger.error(\n `Unhandled error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n });\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 配置文件接口定义\nexport interface MCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface AppConfig {\n mcpEndpoint: string;\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n\n private constructor() {\n this.defaultConfigPath = resolve(__dirname, \"xiaozhi.config.default.json\");\n }\n\n /**\n * 获取配置文件路径(动态计算)\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n const configPath = this.getConfigFilePath();\n return existsSync(configPath);\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n */\n public initConfig(): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(\"默认配置文件 xiaozhi.config.default.json 不存在\");\n }\n\n if (this.configExists()) {\n throw new Error(\"配置文件 xiaozhi.config.json 已存在,无需重复初始化\");\n }\n\n const configPath = this.getConfigFilePath();\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\n \"配置文件 xiaozhi.config.json 不存在,请先运行 xiaozhi init 初始化配置\"\n );\n }\n\n try {\n const configPath = this.getConfigFilePath();\n const configData = readFileSync(configPath, \"utf8\");\n const config = JSON.parse(configData) as AppConfig;\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (!configObj.mcpEndpoint || typeof configObj.mcpEndpoint !== \"string\") {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n const sc = serverConfig as Record<string, unknown>;\n if (!sc.command || typeof sc.command !== \"string\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.command 无效`\n );\n }\n\n if (!Array.isArray(sc.args)) {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.args 必须是数组`\n );\n }\n\n if (sc.env && typeof sc.env !== \"object\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.env 必须是对象`\n );\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取 MCP 端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n return config.mcpEndpoint;\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点\n */\n public updateMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getConfig();\n const newConfig = { ...config, mcpEndpoint: endpoint };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 验证服务配置\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n throw new Error(\"服务配置的 command 字段必须是非空字符串\");\n }\n\n if (!Array.isArray(serverConfig.args)) {\n throw new Error(\"服务配置的 args 字段必须是数组\");\n }\n\n if (serverConfig.env && typeof serverConfig.env !== \"object\") {\n throw new Error(\"服务配置的 env 字段必须是对象\");\n }\n\n const config = this.getConfig();\n const newConfig = {\n ...config,\n mcpServers: {\n ...config.mcpServers,\n [serverName]: serverConfig,\n },\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getConfig();\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n const newMcpServers = { ...config.mcpServers };\n delete newMcpServers[serverName];\n\n const newConfig = {\n ...config,\n mcpServers: newMcpServers,\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 更新指定服务的工具配置\n newConfig.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!newConfig.mcpServerConfig[serverName]) {\n newConfig.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n newConfig.mcpServerConfig[serverName].tools[toolName] = {\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 保存配置到文件\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 格式化 JSON 并保存\n const configPath = this.getConfigFilePath();\n const configJson = JSON.stringify(config, null, 2);\n writeFileSync(configPath, configJson, \"utf8\");\n\n // 更新缓存\n this.config = config;\n } catch (error) {\n throw new Error(\n `保存配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n"],"mappings":"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","names":["spawn","process","fileURLToPath","config","WebSocket","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","__dirname","dirname","fileURLToPath","ConfigManager","_ConfigManager","__name","resolve","configDir","configPath","existsSync","copyFileSync","configData","readFileSync","config","error","configObj","serverName","serverConfig","sc","toolName","endpoint","newConfig","newMcpServers","toolsConfig","enabled","description","configJson","writeFileSync","configManager","config","Logger","__name","name","message","timestamp","logger","INITIAL_BACKOFF","MAX_BACKOFF","reconnectAttempt","backoff","MCPPipe","mcpScript","endpointUrl","resolve","WebSocket","data","code","reason","error","waitTime","spawn","process","signal","ms","setupSignalHandlers","mcpPipe","main","configManager","currentFileUrl","scriptPath","fileURLToPath","argv1Path"]}
1
+ {"version":3,"sources":["../src/mcpPipe.ts","../src/configManager.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * MCP Pipe - JavaScript Implementation\n * Connects to MCP server and pipes input/output to WebSocket endpoint\n * d\n * Version: 0.2.0\n *\n * Usage:\n * export MCP_ENDPOINT=<mcp_endpoint>\n * node mcp_pipe.js <mcp_script>\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport process from \"node:process\";\nimport { fileURLToPath } from \"node:url\";\nimport { config } from \"dotenv\";\nimport WebSocket from \"ws\";\nimport { configManager } from \"./configManager\";\n\n// Load environment variables\nconfig();\n\n// Logger utility\nexport class Logger {\n private name: string;\n\n constructor(name: string) {\n this.name = name;\n }\n\n info(message: string): void {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - ${this.name} - INFO - ${message}`);\n }\n\n error(message: string): void {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - ${this.name} - ERROR - ${message}`);\n }\n\n warning(message: string): void {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - ${this.name} - WARNING - ${message}`);\n }\n\n debug(message: string): void {\n const timestamp = new Date().toISOString();\n console.error(`${timestamp} - ${this.name} - DEBUG - ${message}`);\n }\n}\n\nconst logger = new Logger(\"MCP_PIPE\");\n\n// Reconnection settings - 固定5秒重连间隔\nconst RECONNECT_INTERVAL = 5000; // 固定5秒重连间隔\nconst HEARTBEAT_INTERVAL = 30000; // 心跳检测间隔30秒\nconst HEARTBEAT_TIMEOUT = 10000; // 心跳超时10秒\nlet reconnectAttempt = 0;\n\nexport class MCPPipe {\n private mcpScript: string;\n private endpointUrl: string;\n private process: ChildProcess | null;\n private websocket: WebSocket | null;\n private shouldReconnect: boolean;\n private isConnected: boolean;\n private shutdownResolve?: () => void;\n private heartbeatTimer?: NodeJS.Timeout;\n private heartbeatTimeoutTimer?: NodeJS.Timeout;\n private reconnectTimer?: NodeJS.Timeout;\n private mcpProcessRestartAttempts: number;\n\n constructor(mcpScript: string, endpointUrl: string) {\n this.mcpScript = mcpScript;\n this.endpointUrl = endpointUrl;\n this.process = null;\n this.websocket = null;\n this.shouldReconnect = true;\n this.isConnected = false;\n this.mcpProcessRestartAttempts = 0;\n }\n\n async start() {\n // Start MCP script process\n this.startMCPProcess();\n\n // Start WebSocket connection\n await this.connectToServer();\n\n // Keep the process running\n return new Promise<void>((resolve) => {\n // This promise will only resolve when shutdown is called\n this.shutdownResolve = resolve;\n });\n }\n\n async connectToServer() {\n if (this.isConnected) {\n return;\n }\n\n logger.info(\"Connecting to WebSocket server...\");\n\n this.websocket = new WebSocket(this.endpointUrl);\n\n this.websocket.on(\"open\", () => {\n logger.info(\"Successfully connected to WebSocket server\");\n this.isConnected = true;\n\n // Reset reconnection counter\n reconnectAttempt = 0;\n this.mcpProcessRestartAttempts = 0;\n\n // 启动心跳检测\n this.startHeartbeat();\n });\n\n this.websocket.on(\"message\", (data: WebSocket.Data) => {\n const message = data.toString();\n logger.debug(`<< ${message.substring(0, 120)}...`);\n\n // Write to process stdin\n if (this.process?.stdin && !this.process.stdin.destroyed) {\n this.process.stdin.write(`${message}\\n`);\n }\n });\n\n this.websocket.on(\"close\", (code: number, reason: Buffer) => {\n logger.error(`WebSocket connection closed: ${code} ${reason}`);\n this.isConnected = false;\n this.websocket = null;\n\n // 停止心跳检测\n this.stopHeartbeat();\n\n // Only reconnect if we should and it's not a permanent error\n if (this.shouldReconnect && code !== 4004) {\n this.scheduleReconnect();\n }\n });\n\n this.websocket.on(\"error\", (error: Error) => {\n logger.error(`WebSocket error: ${error.message}`);\n this.isConnected = false;\n\n // 网络错误时停止心跳检测\n this.stopHeartbeat();\n });\n\n // 添加 pong 响应处理\n this.websocket.on(\"pong\", () => {\n // 收到 pong 响应,清除心跳超时定时器\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer);\n this.heartbeatTimeoutTimer = undefined;\n }\n });\n }\n\n scheduleReconnect() {\n if (!this.shouldReconnect) return;\n\n // 清除之前的重连定时器\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n }\n\n reconnectAttempt++;\n\n logger.info(\n `Scheduling reconnection attempt ${reconnectAttempt} in ${(RECONNECT_INTERVAL / 1000).toFixed(2)} seconds...`\n );\n\n this.reconnectTimer = setTimeout(() => {\n if (this.shouldReconnect) {\n // 如果MCP进程不存在,先尝试重启\n if (!this.process || this.process.killed) {\n logger.info(\"MCP process not running, attempting to restart...\");\n this.restartMCPProcess();\n }\n this.connectToServer();\n }\n }, RECONNECT_INTERVAL);\n }\n\n // 心跳检测机制\n private startHeartbeat() {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n }\n\n this.heartbeatTimer = setInterval(() => {\n if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {\n // 发送 ping 并设置超时检测\n this.websocket.ping();\n\n // 设置心跳超时检测\n this.heartbeatTimeoutTimer = setTimeout(() => {\n logger.warning(\"Heartbeat timeout, connection may be lost\");\n // 心跳超时,主动关闭连接触发重连\n if (this.websocket) {\n this.websocket.terminate();\n }\n }, HEARTBEAT_TIMEOUT);\n }\n }, HEARTBEAT_INTERVAL);\n }\n\n private stopHeartbeat() {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = undefined;\n }\n if (this.heartbeatTimeoutTimer) {\n clearTimeout(this.heartbeatTimeoutTimer);\n this.heartbeatTimeoutTimer = undefined;\n }\n }\n\n // MCP进程重启功能\n private restartMCPProcess() {\n if (this.mcpProcessRestartAttempts >= 3) {\n logger.error(\"MCP process restart attempts exceeded, giving up\");\n return;\n }\n\n this.mcpProcessRestartAttempts++;\n logger.info(\n `Attempting to restart MCP process (attempt ${this.mcpProcessRestartAttempts})`\n );\n\n // 清理现有进程\n if (this.process) {\n try {\n this.process.kill(\"SIGTERM\");\n } catch (error) {\n logger.warning(`Error killing existing MCP process: ${error}`);\n }\n this.process = null;\n }\n\n // 重新启动进程\n this.startMCPProcess();\n }\n\n startMCPProcess() {\n if (this.process) {\n logger.info(`${this.mcpScript} process already running`);\n return;\n }\n\n logger.info(`Starting ${this.mcpScript} process`);\n\n this.process = spawn(\"node\", [this.mcpScript], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n // Handle process stdout - send to WebSocket\n this.process.stdout?.on(\"data\", (data: Buffer) => {\n const message = data.toString();\n logger.debug(`>> ${message.substring(0, 120)}...`);\n\n if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {\n this.websocket.send(message);\n }\n });\n\n // Handle process stderr - print to terminal\n this.process.stderr?.on(\"data\", (data: Buffer) => {\n process.stderr.write(data);\n });\n\n // Handle process exit\n this.process.on(\n \"exit\",\n (code: number | null, signal: NodeJS.Signals | null) => {\n logger.warning(\n `${this.mcpScript} process exited with code ${code}, signal ${signal}`\n );\n this.process = null;\n\n // 如果不是主动关闭且应该重连,则尝试重启MCP进程\n if (\n this.shouldReconnect &&\n signal !== \"SIGTERM\" &&\n signal !== \"SIGKILL\"\n ) {\n logger.info(\n \"MCP process unexpectedly exited, will attempt restart on next reconnection\"\n );\n // 不立即重启,而是在下次重连时处理\n }\n }\n );\n\n // Handle process error\n this.process.on(\"error\", (error: Error) => {\n logger.error(`Process error: ${error.message}`);\n this.process = null;\n\n // 进程错误时不停止重连,让重连机制处理\n if (this.shouldReconnect) {\n logger.info(\n \"MCP process error occurred, will attempt restart on next reconnection\"\n );\n }\n });\n }\n\n cleanup() {\n // 停止心跳检测\n this.stopHeartbeat();\n\n // 清除重连定时器\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n if (this.process) {\n logger.info(`Terminating ${this.mcpScript} process`);\n try {\n this.process.kill(\"SIGTERM\");\n\n // Force kill after timeout\n setTimeout(() => {\n if (this.process && !this.process.killed) {\n this.process.kill(\"SIGKILL\");\n }\n }, 5000);\n } catch (error) {\n logger.error(\n `Error terminating process: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n this.process = null;\n }\n\n if (this.websocket) {\n try {\n this.websocket.close();\n } catch (error) {\n logger.warning(`Error closing websocket: ${error}`);\n }\n this.websocket = null;\n }\n\n this.isConnected = false;\n }\n\n sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n shutdown() {\n logger.info(\"Shutting down MCP Pipe...\");\n this.shouldReconnect = false;\n this.cleanup();\n if (this.websocket) {\n this.websocket.close();\n }\n if (this.shutdownResolve) {\n this.shutdownResolve();\n }\n process.exit(0);\n }\n}\n\n// Signal handlers\nexport function setupSignalHandlers(mcpPipe: MCPPipe): void {\n // 检查是否为守护进程模式\n const isDaemon = process.env.XIAOZHI_DAEMON === \"true\";\n\n process.on(\"SIGINT\", () => {\n logger.info(\"Received interrupt signal, shutting down...\");\n mcpPipe.shutdown();\n });\n\n process.on(\"SIGTERM\", () => {\n logger.info(\"Received terminate signal, shutting down...\");\n mcpPipe.shutdown();\n });\n\n // 守护进程模式下的额外信号处理\n if (isDaemon) {\n // 忽略 SIGHUP 信号(终端关闭)\n process.on(\"SIGHUP\", () => {\n logger.info(\n \"Received SIGHUP signal (terminal closed), continuing in daemon mode...\"\n );\n // 守护进程不应该因为终端关闭而退出\n });\n\n // 处理未捕获的异常\n process.on(\"uncaughtException\", (error) => {\n logger.error(`Uncaught exception in daemon mode: ${error.message}`);\n logger.error(error.stack || \"No stack trace available\");\n // 守护进程遇到未捕获的异常时不退出,而是继续运行\n });\n\n // 处理未处理的 Promise 拒绝\n process.on(\"unhandledRejection\", (reason, promise) => {\n logger.error(`Unhandled promise rejection in daemon mode: ${reason}`);\n logger.error(`Promise: ${promise}`);\n // 守护进程遇到未处理的 Promise 拒绝时不退出\n });\n\n logger.info(\"Daemon mode signal handlers initialized\");\n }\n}\n\n// Main execution\nasync function main() {\n // Check command line arguments\n if (process.argv.length < 3) {\n logger.error(\"Usage: node mcp_pipe.js <mcp_script>\");\n process.exit(1);\n }\n\n const mcpScript = process.argv[2];\n\n // Get endpoint URL from config file or environment variable (fallback)\n let endpointUrl: string;\n\n try {\n // 调试信息 - 使用 process.stderr.write 确保能看到\n process.stderr.write(\n `[DEBUG] XIAOZHI_CONFIG_DIR: ${process.env.XIAOZHI_CONFIG_DIR}\\n`\n );\n process.stderr.write(`[DEBUG] process.cwd(): ${process.cwd()}\\n`);\n process.stderr.write(\n `[DEBUG] configManager.getConfigPath(): ${configManager.getConfigPath()}\\n`\n );\n process.stderr.write(\n `[DEBUG] configManager.configExists(): ${configManager.configExists()}\\n`\n );\n\n // 首先尝试从配置文件读取\n if (configManager.configExists()) {\n endpointUrl = configManager.getMcpEndpoint();\n logger.info(\"使用配置文件中的 MCP 端点\");\n } else {\n // 如果配置文件不存在,尝试从环境变量读取(向后兼容)\n endpointUrl = process.env.MCP_ENDPOINT || \"\";\n if (!endpointUrl) {\n logger.error(\"配置文件不存在且未设置 MCP_ENDPOINT 环境变量\");\n logger.error(\n '请运行 \"xiaozhi init\" 初始化配置,或设置 MCP_ENDPOINT 环境变量'\n );\n process.exit(1);\n }\n logger.info(\"使用环境变量中的 MCP 端点(建议使用配置文件)\");\n }\n } catch (error) {\n logger.error(\n `读取配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n\n // 尝试从环境变量读取作为备用方案\n endpointUrl = process.env.MCP_ENDPOINT || \"\";\n if (!endpointUrl) {\n logger.error(\n '请运行 \"xiaozhi init\" 初始化配置,或设置 MCP_ENDPOINT 环境变量'\n );\n process.exit(1);\n }\n logger.info(\"使用环境变量中的 MCP 端点作为备用方案\");\n }\n\n // 验证端点 URL\n if (!endpointUrl || endpointUrl.includes(\"<请填写\")) {\n logger.error(\"MCP 端点未配置或配置无效\");\n logger.error(\n '请运行 \"xiaozhi config mcpEndpoint <your-endpoint-url>\" 设置端点'\n );\n process.exit(1);\n }\n\n // Create MCP Pipe instance\n const mcpPipe = new MCPPipe(mcpScript, endpointUrl);\n\n // Setup signal handlers\n setupSignalHandlers(mcpPipe);\n\n // Start the MCP pipe\n try {\n await mcpPipe.start();\n } catch (error) {\n logger.error(\n `Program execution error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n }\n}\n\n// Run if this file is executed directly\n// Use fileURLToPath to properly handle Windows paths\nconst currentFileUrl = import.meta.url;\nconst scriptPath = fileURLToPath(currentFileUrl);\nconst argv1Path = process.argv[1];\n\nif (scriptPath === argv1Path) {\n main().catch((error) => {\n logger.error(\n `Unhandled error: ${error instanceof Error ? error.message : String(error)}`\n );\n process.exit(1);\n });\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 配置文件接口定义\nexport interface MCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface AppConfig {\n mcpEndpoint: string;\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n\n private constructor() {\n this.defaultConfigPath = resolve(__dirname, \"xiaozhi.config.default.json\");\n }\n\n /**\n * 获取配置文件路径(动态计算)\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n const configPath = this.getConfigFilePath();\n return existsSync(configPath);\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n */\n public initConfig(): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(\"默认配置文件 xiaozhi.config.default.json 不存在\");\n }\n\n if (this.configExists()) {\n throw new Error(\"配置文件 xiaozhi.config.json 已存在,无需重复初始化\");\n }\n\n const configPath = this.getConfigFilePath();\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\n \"配置文件 xiaozhi.config.json 不存在,请先运行 xiaozhi init 初始化配置\"\n );\n }\n\n try {\n const configPath = this.getConfigFilePath();\n const configData = readFileSync(configPath, \"utf8\");\n const config = JSON.parse(configData) as AppConfig;\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (!configObj.mcpEndpoint || typeof configObj.mcpEndpoint !== \"string\") {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n const sc = serverConfig as Record<string, unknown>;\n if (!sc.command || typeof sc.command !== \"string\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.command 无效`\n );\n }\n\n if (!Array.isArray(sc.args)) {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.args 必须是数组`\n );\n }\n\n if (sc.env && typeof sc.env !== \"object\") {\n throw new Error(\n `配置文件格式错误:mcpServers.${serverName}.env 必须是对象`\n );\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取 MCP 端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n return config.mcpEndpoint;\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点\n */\n public updateMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getConfig();\n const newConfig = { ...config, mcpEndpoint: endpoint };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 验证服务配置\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n throw new Error(\"服务配置的 command 字段必须是非空字符串\");\n }\n\n if (!Array.isArray(serverConfig.args)) {\n throw new Error(\"服务配置的 args 字段必须是数组\");\n }\n\n if (serverConfig.env && typeof serverConfig.env !== \"object\") {\n throw new Error(\"服务配置的 env 字段必须是对象\");\n }\n\n const config = this.getConfig();\n const newConfig = {\n ...config,\n mcpServers: {\n ...config.mcpServers,\n [serverName]: serverConfig,\n },\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getConfig();\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n const newMcpServers = { ...config.mcpServers };\n delete newMcpServers[serverName];\n\n const newConfig = {\n ...config,\n mcpServers: newMcpServers,\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 更新指定服务的工具配置\n newConfig.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (!newConfig.mcpServerConfig) {\n newConfig.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!newConfig.mcpServerConfig[serverName]) {\n newConfig.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n newConfig.mcpServerConfig[serverName].tools[toolName] = {\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(newConfig);\n }\n\n /**\n * 保存配置到文件\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 格式化 JSON 并保存\n const configPath = this.getConfigFilePath();\n const configJson = JSON.stringify(config, null, 2);\n writeFileSync(configPath, configJson, \"utf8\");\n\n // 更新缓存\n this.config = config;\n } catch (error) {\n throw new Error(\n `保存配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n"],"mappings":"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","names":["spawn","process","fileURLToPath","config","WebSocket","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","__dirname","dirname","fileURLToPath","ConfigManager","_ConfigManager","__name","resolve","configDir","configPath","existsSync","copyFileSync","configData","readFileSync","config","error","configObj","serverName","serverConfig","sc","toolName","endpoint","newConfig","newMcpServers","toolsConfig","enabled","description","configJson","writeFileSync","configManager","config","Logger","__name","name","message","timestamp","logger","RECONNECT_INTERVAL","HEARTBEAT_INTERVAL","HEARTBEAT_TIMEOUT","reconnectAttempt","MCPPipe","mcpScript","endpointUrl","resolve","WebSocket","data","code","reason","error","spawn","process","signal","ms","setupSignalHandlers","mcpPipe","isDaemon","promise","main","configManager","currentFileUrl","scriptPath","fileURLToPath","argv1Path"]}
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xiaozhi-client",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "小智 AI 客户端 命令行工具",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xiaozhi-client",
3
- "version": "1.0.6",
3
+ "version": "1.0.7-beta.0",
4
4
  "description": "小智 AI 客户端 命令行工具",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",