xiaozhi-client 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,68 +1,82 @@
1
1
  # Xiaozhi Client
2
2
 
3
+ [![npm version](https://badge.fury.io/js/xiaozhi-client.svg)](https://badge.fury.io/js/xiaozhi-client)
4
+ [![codecov](https://codecov.io/gh/shenjingnan/xiaozhi-client/branch/main/graph/badge.svg)](https://codecov.io/gh/shenjingnan/xiaozhi-client)
5
+ [![CI](https://github.com/shenjingnan/xiaozhi-client/workflows/Release/badge.svg)](https://github.com/shenjingnan/xiaozhi-client/actions)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
3
8
  小智 AI 客户端,目前主要用于 MCP 的对接
4
9
 
5
- ![效果图](./docs/images/preview.png)
10
+ ![效果图](https://raw.githubusercontent.com/shenjingnan/xiaozhi-client/main/docs/images/preview.png)
11
+
12
+ ## 功能特性
6
13
 
7
- ## 安装和使用
14
+ - 支持 小智(xiaozhi.me) 官方服务器接入点
15
+ - 支持 自定义 MCP 服务
16
+ - 支持 使用标准 MCP 配置方式多个 MCP Server
17
+ - 支持 聚合多个 MCP Server
18
+ - 支持 动态控制 MCP Server 提供的工具
19
+ - 支持 通过模板创建
20
+ - 支持 后台运行
8
21
 
9
- ### 开发环境
22
+ ## 快速上手
10
23
 
11
- 1. 克隆项目:
24
+ ### 全局安装 xiaozhi-client 命令行工具
12
25
 
13
26
  ```bash
14
- git clone <repository-url>
15
- cd xiaozhi-client
16
- ```
27
+ ## 安装
28
+ npm i -g xiaozhi-client
17
29
 
18
- 2. 安装依赖:
30
+ ## 创建项目
31
+ xiaozhi create my-app --template hello-world
19
32
 
20
- ```bash
33
+ ## 进入项目
34
+ cd my-app
35
+
36
+ ## 安装依赖(主要是示例代码中mcp服务所使用的依赖)
21
37
  pnpm install
22
- ```
23
38
 
24
- 3. 构建项目:
39
+ # 修改 xiaozhi.config.json 中的 mcpEndpoint 为你的接入点地址(需要自行前往xiaozhi.me获取)
40
+ # 小智AI配置MCP接入点使用说明:https://ccnphfhqs21z.feishu.cn/wiki/HiPEwZ37XiitnwktX13cEM5KnSb
25
41
 
26
- ```bash
27
- pnpm run build
42
+ ## 运行
43
+ xiaozhi start
28
44
  ```
29
45
 
30
- 4. 本地安装(用于开发测试):
46
+ ### 通过 npx 直接运行
31
47
 
32
48
  ```bash
33
- npm link
34
- ```
49
+ # 创建项目
50
+ npx -y xiaozhi-client create --template hello-world
35
51
 
36
- 现在你可以在任何地方使用 `xiaozhi` 命令了。
52
+ # 进入项目目录
53
+ cd hello-world
37
54
 
38
- ### 生产环境
39
-
40
- 项目使用 tsup 打包成单个可执行的 JavaScript 文件,所有依赖都被正确处理。
55
+ # 安装依赖
56
+ pnpm install
41
57
 
42
- 构建后的文件位于 `dist/cli.js`,这是一个完整的可执行文件,包含:
58
+ # 修改 xiaozhi.config.json 中的 mcpEndpoint 为你的接入点地址(需要自行前往xiaozhi.me获取)
59
+ # 小智AI配置MCP接入点使用说明:https://ccnphfhqs21z.feishu.cn/wiki/HiPEwZ37XiitnwktX13cEM5KnSb
43
60
 
44
- - 正确的 shebang (`#!/usr/bin/env node`)
45
- - 所有必要的代码(除了外部依赖)
46
- - 可执行权限
61
+ # 启动服务
62
+ npx -y xiaozhi-client start
63
+ ```
47
64
 
48
- ### 可用命令
65
+ ## 可用命令
49
66
 
50
67
  ```bash
51
68
  # 查看帮助
52
69
  xiaozhi --help
53
70
 
54
- # 配置端点
55
- xiaozhi set-config xiaozhi.endpoint=wss://your-endpoint
56
-
57
- # 查看配置
58
- xiaozhi get-config
59
-
60
71
  # 启动服务
61
72
  xiaozhi start
62
73
 
63
74
  # 后台启动服务
64
75
  xiaozhi start --daemon
65
76
 
77
+ # 将后台服务转到前台运行
78
+ xiaozhi attach
79
+
66
80
  # 查看服务状态
67
81
  xiaozhi status
68
82
 
@@ -71,89 +85,16 @@ xiaozhi stop
71
85
 
72
86
  # 重启服务
73
87
  xiaozhi restart
74
- ```
75
-
76
- ## 开发
77
-
78
- ### 构建脚本
79
-
80
- - `pnpm run build` - 使用 tsup 构建项目(推荐)
81
- - `pnpm run build:tsc` - 使用 TypeScript 编译器构建(备用)
82
- - `pnpm run clean` - 清理构建文件
83
- - `pnpm run dev` - 开发模式(监听文件变化)
84
- - `pnpm run type-check` - 仅进行类型检查
85
- - `pnpm run start` - 编译并启动服务
86
-
87
- ### 技术栈
88
88
 
89
- - TypeScript
90
- - tsup (打包工具)
91
- - Commander.js (CLI 框架)
92
- - Chalk (终端颜色)
93
- - Ora (加载动画)
94
- - Biome (代码格式化和检查)
95
- - Vitest (单元测试)
89
+ # 列出所有使用的mcp服务
90
+ xiaozhi mcp list
96
91
 
97
- ### 代码质量
98
-
99
- 项目使用完整的 CI/CD 流程确保代码质量:
100
-
101
- #### 测试
102
-
103
- ```bash
104
- # 运行所有测试
105
- pnpm run test
106
-
107
- # 运行测试并生成覆盖率报告
108
- pnpm run test:coverage
109
-
110
- # 监听模式运行测试
111
- pnpm run test:watch
112
-
113
- # 运行测试UI界面
114
- pnpm run test:ui
115
- ```
116
-
117
- #### 代码检查和格式化
118
-
119
- ```bash
120
- # 运行Biome代码检查(CI模式)
121
- pnpm run ci
122
-
123
- # 格式化代码
124
- pnpm run format
125
-
126
- # 检查格式(不修改文件)
127
- pnpm run format:check
128
-
129
- # 运行lint检查
130
- pnpm run lint:check
131
-
132
- # 运行lint并自动修复
133
- pnpm run lint
134
-
135
- # TypeScript类型检查
136
- pnpm run type-check
92
+ # 列出所有mcp所提供的tools
93
+ xiaozhi mcp --tools
137
94
  ```
138
95
 
139
- #### CI/CD 流程
140
-
141
- 每次向 main 分支提交 PR 时,会自动运行以下检查:
142
-
143
- 1. **TypeScript 类型检查** - 确保没有类型错误
144
- 2. **Biome 代码检查** - 确保代码格式和质量符合规范
145
- 3. **单元测试** - 运行所有测试用例并生成覆盖率报告
146
- 4. **覆盖率检查** - 确保测试覆盖率不低于配置的阈值
147
- 5. **构建验证** - 确保项目能够正确构建
148
- 6. **产物验证** - 验证所有必要的构建产物都已生成
149
- 7. **CLI 可执行性测试** - 确保 CLI 工具可以正常执行
150
-
151
- 只有所有检查都通过,PR 才能被合并到 main 分支。
152
-
153
- ### 打包特性
96
+ ## 路线图
154
97
 
155
- - 使用 tsup 进行快速打包
156
- - 自动处理 shebang 重复问题
157
- - 自动添加可执行权限
158
- - 支持 ES 模块
159
- - 生成 source maps 和类型定义文件
98
+ - 支持 通过 SSE 类型的 MCP Server
99
+ - 支持 直接使用 [modelscope](https://www.modelscope.cn/mcp) 中托管的 MCP 服务
100
+ - 支持 通过使用网页进行 MCP 配置
package/dist/cli.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var G=Object.create;var v=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var R=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var l=(o,e)=>v(o,"name",{value:e,configurable:!0});var V=(o,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of O(e))!A.call(o,s)&&s!==n&&v(o,s,{get:()=>e[s],enumerable:!(i=F(e,s))||i.enumerable});return o};var u=(o,e,n)=>(n=o!=null?G(R(o)):{},V(e||!o||!o.__esModule?v(n,"default",{value:o,enumerable:!0}):n,o));var b=require("node:child_process"),a=u(require("node:fs")),I=u(require("node:os")),g=u(require("node:path")),t=u(require("chalk")),N=require("commander"),f=u(require("ora")),d=require("./configManager.cjs"),h=require("./mcpCommands.cjs");const p=new N.Command,z="0.0.1",E="xiaozhi-mcp-service",y=g.default.join(I.default.tmpdir(),`${E}.pid`),x=g.default.join(I.default.tmpdir(),`${E}.log`);function $(){try{if(!a.default.existsSync(y))return{running:!1};const o=a.default.readFileSync(y,"utf8").trim(),[e,n,i]=o.split("|"),s=Number.parseInt(e);if(Number.isNaN(s))return a.default.unlinkSync(y),{running:!1};try{process.kill(s,0);const c=Number.parseInt(n),r=H(Date.now()-c);return{running:!0,pid:s,uptime:r,mode:i||"foreground"}}catch{return a.default.unlinkSync(y),{running:!1}}}catch{return{running:!1}}}l($,"getServiceStatus");function H(o){const e=Math.floor(o/1e3),n=Math.floor(e/60),i=Math.floor(n/60),s=Math.floor(i/24);return s>0?`${s}\u5929 ${i%24}\u5C0F\u65F6 ${n%60}\u5206\u949F`:i>0?`${i}\u5C0F\u65F6 ${n%60}\u5206\u949F`:n>0?`${n}\u5206\u949F ${e%60}\u79D2`:`${e}\u79D2`}l(H,"formatUptime");function M(o,e){const n=`${o}|${Date.now()}|${e}`;a.default.writeFileSync(y,n)}l(M,"savePidInfo");function P(){try{a.default.existsSync(y)&&a.default.unlinkSync(y)}catch{}}l(P,"cleanupPidFile");function B(){if(!d.configManager.configExists())return console.error(t.default.red("\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728")),console.log(t.default.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E')),!1;try{const o=d.configManager.getMcpEndpoint();return!o||o.includes("<\u8BF7\u586B\u5199")?(console.error(t.default.red("\u274C \u9519\u8BEF: MCP \u7AEF\u70B9\u672A\u914D\u7F6E")),console.log(t.default.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9')),!1):!0}catch(o){return console.error(t.default.red(`\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u65E0\u6548 - ${o instanceof Error?o.message:String(o)}`)),console.log(t.default.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u91CD\u65B0\u521D\u59CB\u5316\u914D\u7F6E')),!1}}l(B,"checkEnvironment");function U(){const o=__dirname;let e;return o.includes("js-demo/dist")?e=o:e=[g.default.join(o,"..","js-demo","dist"),g.default.join(o,"..","..","js-demo","dist"),g.default.join(o,"..","..","..","js-demo","dist"),g.default.join(process.cwd(),"js-demo","dist"),g.default.join(process.cwd(),"dist")].find(i=>a.default.existsSync(g.default.join(i,"mcpPipe.cjs"))&&a.default.existsSync(g.default.join(i,"mcpServerProxy.cjs")))||o,{command:"node",args:["mcpPipe.cjs","mcpServerProxy.cjs"],cwd:e}}l(U,"getServiceCommand");async function T(o=!1){const e=(0,f.default)("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{const n=$();if(n.running){e.fail(`\u670D\u52A1\u5DF2\u7ECF\u5728\u8FD0\u884C (PID: ${n.pid})`);return}if(e.text="\u68C0\u67E5\u73AF\u5883\u914D\u7F6E...",!B()){e.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}const{command:i,args:s,cwd:c}=U();if(e.text=`\u542F\u52A8\u670D\u52A1 (${o?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,o){const r=(0,b.spawn)(i,s,{cwd:c,detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});M(r.pid,"daemon");const m=a.default.createWriteStream(x,{flags:"a"});r.stdout?.pipe(m),r.stderr?.pipe(m),r.unref(),e.succeed(`\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${r.pid})`),console.log(t.default.gray(`\u65E5\u5FD7\u6587\u4EF6: ${x}`)),console.log(t.default.gray("\u4F7F\u7528 'xiaozhi attach' \u53EF\u4EE5\u67E5\u770B\u5B9E\u65F6\u65E5\u5FD7"))}else{e.succeed("\u670D\u52A1\u542F\u52A8\u4E2D...");const r=(0,b.spawn)(i,s,{cwd:c,stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});M(r.pid,"foreground"),r.on("exit",(m,w)=>{P(),console.log(m!==0?t.default.red(`
2
+ "use strict";var O=Object.create;var P=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var V=Object.getPrototypeOf,H=Object.prototype.hasOwnProperty;var g=(o,e)=>P(o,"name",{value:e,configurable:!0});var J=(o,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of A(e))!H.call(o,s)&&s!==n&&P(o,s,{get:()=>e[s],enumerable:!(i=R(e,s))||i.enumerable});return o};var u=(o,e,n)=>(n=o!=null?O(V(o)):{},J(e||!o||!o.__esModule?P(n,"default",{value:o,enumerable:!0}):n,o));const j={};var b=require("node:child_process"),l=u(require("node:fs")),I=u(require("node:os")),c=u(require("node:path")),N=require("node:url"),t=u(require("chalk")),G=require("commander"),f=u(require("ora")),d=require("./configManager.cjs"),h=require("./mcpCommands.cjs");const p=new G.Command,E="xiaozhi-mcp-service";function M(){try{let o;if(typeof j<"u"&&j.url){const n=(0,N.fileURLToPath)(j.url);o=c.default.dirname(n)}else require.main?.filename?o=c.default.dirname(require.main.filename):o=process.cwd();const e=[c.default.join(o,"..","package.json"),c.default.join(o,"..","package.json"),c.default.join(o,"..","..","package.json"),c.default.join(o,"package.json")];for(const n of e)if(l.default.existsSync(n)){const i=JSON.parse(l.default.readFileSync(n,"utf8"));if(i.version)return i.version}return"unknown"}catch(o){return console.warn("Warning: Could not read version from package.json:",o),"unknown"}}g(M,"getVersion");const y=c.default.join(I.default.tmpdir(),`${E}.pid`),x=c.default.join(I.default.tmpdir(),`${E}.log`);function v(){try{if(!l.default.existsSync(y))return{running:!1};const o=l.default.readFileSync(y,"utf8").trim(),[e,n,i]=o.split("|"),s=Number.parseInt(e);if(Number.isNaN(s))return l.default.unlinkSync(y),{running:!1};try{process.kill(s,0);const a=Number.parseInt(n),r=U(Date.now()-a);return{running:!0,pid:s,uptime:r,mode:i||"foreground"}}catch{return l.default.unlinkSync(y),{running:!1}}}catch{return{running:!1}}}g(v,"getServiceStatus");function U(o){const e=Math.floor(o/1e3),n=Math.floor(e/60),i=Math.floor(n/60),s=Math.floor(i/24);return s>0?`${s}\u5929 ${i%24}\u5C0F\u65F6 ${n%60}\u5206\u949F`:i>0?`${i}\u5C0F\u65F6 ${n%60}\u5206\u949F`:n>0?`${n}\u5206\u949F ${e%60}\u79D2`:`${e}\u79D2`}g(U,"formatUptime");function k(o,e){const n=`${o}|${Date.now()}|${e}`;l.default.writeFileSync(y,n)}g(k,"savePidInfo");function $(){try{l.default.existsSync(y)&&l.default.unlinkSync(y)}catch{}}g($,"cleanupPidFile");function q(){if(!d.configManager.configExists())return console.error(t.default.red("\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728")),console.log(t.default.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E')),!1;try{const o=d.configManager.getMcpEndpoint();return!o||o.includes("<\u8BF7\u586B\u5199")?(console.error(t.default.red("\u274C \u9519\u8BEF: MCP \u7AEF\u70B9\u672A\u914D\u7F6E")),console.log(t.default.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi config mcpEndpoint <your-endpoint-url>" \u8BBE\u7F6E\u7AEF\u70B9')),!1):!0}catch(o){return console.error(t.default.red(`\u274C \u9519\u8BEF: \u914D\u7F6E\u6587\u4EF6\u65E0\u6548 - ${o instanceof Error?o.message:String(o)}`)),console.log(t.default.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u8FD0\u884C "xiaozhi init" \u91CD\u65B0\u521D\u59CB\u5316\u914D\u7F6E')),!1}}g(q,"checkEnvironment");function B(){const o=__dirname;let e;return o.includes("js-demo/dist")?e=o:e=[c.default.join(o,"..","js-demo","dist"),c.default.join(o,"..","..","js-demo","dist"),c.default.join(o,"..","..","..","js-demo","dist"),c.default.join(process.cwd(),"js-demo","dist"),c.default.join(process.cwd(),"dist")].find(i=>l.default.existsSync(c.default.join(i,"mcpPipe.cjs"))&&l.default.existsSync(c.default.join(i,"mcpServerProxy.cjs")))||o,{command:"node",args:["mcpPipe.cjs","mcpServerProxy.cjs"],cwd:e}}g(B,"getServiceCommand");async function T(o=!1){const e=(0,f.default)("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{const n=v();if(n.running){e.fail(`\u670D\u52A1\u5DF2\u7ECF\u5728\u8FD0\u884C (PID: ${n.pid})`);return}if(e.text="\u68C0\u67E5\u73AF\u5883\u914D\u7F6E...",!q()){e.fail("\u73AF\u5883\u914D\u7F6E\u68C0\u67E5\u5931\u8D25");return}const{command:i,args:s,cwd:a}=B();if(e.text=`\u542F\u52A8\u670D\u52A1 (${o?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"})...`,o){const r=(0,b.spawn)(i,s,{cwd:a,detached:!0,stdio:["ignore","pipe","pipe"],env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});k(r.pid,"daemon");const m=l.default.createWriteStream(x,{flags:"a"});r.stdout?.pipe(m),r.stderr?.pipe(m),r.unref(),e.succeed(`\u670D\u52A1\u5DF2\u5728\u540E\u53F0\u542F\u52A8 (PID: ${r.pid})`),console.log(t.default.gray(`\u65E5\u5FD7\u6587\u4EF6: ${x}`)),console.log(t.default.gray("\u4F7F\u7528 'xiaozhi attach' \u53EF\u4EE5\u67E5\u770B\u5B9E\u65F6\u65E5\u5FD7"))}else{e.succeed("\u670D\u52A1\u542F\u52A8\u4E2D...");const r=(0,b.spawn)(i,s,{cwd:a,stdio:"inherit",env:{...process.env,XIAOZHI_CONFIG_DIR:process.cwd()}});k(r.pid,"foreground"),r.on("exit",(m,w)=>{$(),console.log(m!==0?t.default.red(`
3
3
  \u670D\u52A1\u5F02\u5E38\u9000\u51FA (\u4EE3\u7801: ${m}, \u4FE1\u53F7: ${w})`):t.default.green(`
4
4
  \u670D\u52A1\u5DF2\u505C\u6B62`))}),process.on("SIGINT",()=>{console.log(t.default.yellow(`
5
- \u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),r.kill("SIGTERM")}),process.on("SIGTERM",()=>{r.kill("SIGTERM")})}}catch(n){e.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}l(T,"startService");async function k(){const o=(0,f.default)("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{const e=$();if(!e.running){o.warn("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}o.text=`\u505C\u6B62\u670D\u52A1 (PID: ${e.pid})...`;try{process.kill(e.pid,"SIGTERM");let n=0;const i=30;for(;n<i;){await new Promise(s=>setTimeout(s,100));try{process.kill(e.pid,0),n++}catch{break}}try{process.kill(e.pid,0),o.text="\u5F3A\u5236\u505C\u6B62\u670D\u52A1...",process.kill(e.pid,"SIGKILL"),await new Promise(s=>setTimeout(s,500))}catch{}P(),o.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(n){P(),o.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}catch(e){o.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(k,"stopService");async function X(){const o=(0,f.default)("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{const e=$();e.running?(o.succeed("\u670D\u52A1\u72B6\u6001"),console.log(t.default.green("\u2705 \u670D\u52A1\u6B63\u5728\u8FD0\u884C")),console.log(t.default.gray(` PID: ${e.pid}`)),console.log(t.default.gray(` \u8FD0\u884C\u65F6\u95F4: ${e.uptime}`)),console.log(t.default.gray(` \u8FD0\u884C\u6A21\u5F0F: ${e.mode==="daemon"?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"}`)),e.mode==="daemon"&&console.log(t.default.gray(` \u65E5\u5FD7\u6587\u4EF6: ${x}`))):(o.succeed("\u670D\u52A1\u72B6\u6001"),console.log(t.default.red("\u274C \u670D\u52A1\u672A\u8FD0\u884C")))}catch(e){o.fail(`\u68C0\u67E5\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(X,"checkStatus");async function Z(){const o=(0,f.default)("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{const e=$();if(!e.running){o.fail("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}if(e.mode!=="daemon"){o.fail("\u670D\u52A1\u4E0D\u662F\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C");return}if(o.succeed("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1..."),console.log(t.default.green(`\u5DF2\u8FDE\u63A5\u5230\u670D\u52A1 (PID: ${e.pid})`)),console.log(t.default.gray("\u6309 Ctrl+C \u53EF\u4EE5\u65AD\u5F00\u8FDE\u63A5\uFF08\u4E0D\u4F1A\u505C\u6B62\u670D\u52A1\uFF09")),console.log(t.default.gray("=".repeat(50))),a.default.existsSync(x)){const{spawn:n}=await import("node:child_process"),i=n("tail",["-f",x],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(t.default.yellow(`
6
- \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),i.kill(),process.exit(0)}),i.on("exit",()=>{process.exit(0)})}else console.log(t.default.yellow("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728"))}catch(e){o.fail(`\u8FDE\u63A5\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(Z,"attachService");async function J(o=!1){console.log(t.default.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await k(),await new Promise(e=>setTimeout(e,1e3)),await T(o)}l(J,"restartService");function K(){console.log(t.default.blue(`xiaozhi v${z}`)),console.log(t.default.gray("MCP Calculator Service CLI Tool")),console.log(t.default.gray("Built with Node.js and TypeScript")),console.log(t.default.gray(`Node.js: ${process.version}`)),console.log(t.default.gray(`Platform: ${process.platform} ${process.arch}`))}l(K,"showDetailedInfo");async function W(){const o=(0,f.default)("\u521D\u59CB\u5316\u914D\u7F6E...").start();try{if(d.configManager.configExists()){o.warn("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728"),console.log(t.default.yellow("\u5982\u9700\u91CD\u65B0\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u5220\u9664\u73B0\u6709\u7684 xiaozhi.config.json \u6587\u4EF6"));return}d.configManager.initConfig(),o.succeed("\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u6210\u529F"),console.log(t.default.green("\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u521B\u5EFA: xiaozhi.config.json")),console.log(t.default.yellow("\u{1F4DD} \u8BF7\u7F16\u8F91\u914D\u7F6E\u6587\u4EF6\u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9:")),console.log(t.default.gray(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${d.configManager.getConfigPath()}`)),console.log(t.default.yellow("\u{1F4A1} \u6216\u8005\u4F7F\u7528\u547D\u4EE4\u8BBE\u7F6E:")),console.log(t.default.gray(" xiaozhi config mcpEndpoint <your-endpoint-url>"))}catch(e){o.fail(`\u521D\u59CB\u5316\u914D\u7F6E\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}l(W,"initConfig");function Y(){const o=__dirname,n=[g.default.join(o,"..","templates"),g.default.join(o,"templates"),g.default.join(o,"..","..","templates")].find(i=>a.default.existsSync(i));return n?a.default.readdirSync(n).filter(i=>{const s=g.default.join(n,i);return a.default.statSync(s).isDirectory()}):[]}l(Y,"getAvailableTemplates");function D(o,e){const n=o.length,i=e.length,s=Array(n+1).fill(null).map(()=>Array(i+1).fill(0));for(let r=0;r<=n;r++)s[r][0]=r;for(let r=0;r<=i;r++)s[0][r]=r;for(let r=1;r<=n;r++)for(let m=1;m<=i;m++)o[r-1]===e[m-1]?s[r][m]=s[r-1][m-1]:s[r][m]=Math.min(s[r-1][m]+1,s[r][m-1]+1,s[r-1][m-1]+1);const c=Math.max(n,i);return c===0?1:(c-s[n][i])/c}l(D,"calculateSimilarity");function q(o,e){if(e.length===0)return null;let n=e[0],i=D(o.toLowerCase(),n.toLowerCase());for(const s of e.slice(1)){const c=D(o.toLowerCase(),s.toLowerCase());c>i&&(i=c,n=s)}return i>.5?n:null}l(q,"findSimilarTemplate");async function Q(o){if(!process.stdin.isTTY)return console.log("n (\u975E\u4EA4\u4E92\u5F0F\u73AF\u5883)"),!1;const e=await import("node:readline");return new Promise(n=>{process.stdout.write(o);const i=e.createInterface({input:process.stdin,output:process.stdout}),s=l(c=>{const r=c.trim().toLowerCase();r==="y"||r==="yes"?(i.close(),n(!0)):r==="n"||r==="no"||r===""?(i.close(),n(!1)):process.stdout.write("\u8BF7\u8F93\u5165 y \u6216 n: ")},"handleInput");i.on("line",s),i.on("SIGINT",()=>{i.close(),n(!1)})})}l(Q,"askUserConfirmation");function oo(o){const e={mcpEndpoint:"<\u8BF7\u586B\u5199\u4F60\u7684\u63A5\u5165\u70B9\u5730\u5740\uFF08\u83B7\u53D6\u5730\u5740\u5728 xiaozhi.me\uFF09>",mcpServers:{}},n=g.default.join(o,"xiaozhi.config.json");a.default.writeFileSync(n,JSON.stringify(e,null,2),"utf8")}l(oo,"createBasicConfig");async function eo(o,e){const n=(0,f.default)("\u521D\u59CB\u5316\u9879\u76EE...").start();try{const i=g.default.join(process.cwd(),o);if(a.default.existsSync(i)){n.fail(`\u76EE\u5F55 "${o}" \u5DF2\u5B58\u5728`),console.log(t.default.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u9009\u62E9\u4E0D\u540C\u7684\u9879\u76EE\u540D\u79F0\u6216\u5220\u9664\u73B0\u6709\u76EE\u5F55"));return}if(e.template){n.text="\u68C0\u67E5\u6A21\u677F...";const s=Y();if(s.length===0){n.fail("\u627E\u4E0D\u5230 templates \u76EE\u5F55"),console.log(t.default.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u786E\u4FDD xiaozhi-client \u6B63\u786E\u5B89\u88C5"));return}if(!s.includes(e.template)){n.fail(`\u6A21\u677F "${e.template}" \u4E0D\u5B58\u5728`);const S=q(e.template,s);if(S)if(console.log(t.default.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${S}" \u5417\uFF1F`)),await Q(t.default.cyan("\u786E\u8BA4\u4F7F\u7528\u6B64\u6A21\u677F\uFF1F(y/n): ")))e.template=S;else{console.log(t.default.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(const _ of s)console.log(t.default.gray(` - ${_}`));return}else{console.log(t.default.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(const j of s)console.log(t.default.gray(` - ${j}`));return}}const c=__dirname,m=[g.default.join(c,"..","templates"),g.default.join(c,"templates"),g.default.join(c,"..","..","templates")].find(S=>a.default.existsSync(S)),w=g.default.join(m,e.template);n.text=`\u4ECE\u6A21\u677F "${e.template}" \u521B\u5EFA\u9879\u76EE "${o}"...`,L(w,i,["node_modules",".pnpm-debug.log","pnpm-lock.yaml"]),n.succeed(`\u9879\u76EE "${o}" \u521B\u5EFA\u6210\u529F`),console.log(t.default.green("\u2705 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(t.default.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(t.default.gray(` cd ${o}`)),console.log(t.default.gray(" pnpm install # \u5B89\u88C5\u4F9D\u8D56")),console.log(t.default.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9")),console.log(t.default.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1"))}else n.text=`\u521B\u5EFA\u57FA\u672C\u9879\u76EE "${o}"...`,a.default.mkdirSync(i,{recursive:!0}),oo(i),n.succeed(`\u9879\u76EE "${o}" \u521B\u5EFA\u6210\u529F`),console.log(t.default.green("\u2705 \u57FA\u672C\u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(t.default.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(t.default.gray(` cd ${o}`)),console.log(t.default.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9\u548C\u670D\u52A1")),console.log(t.default.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1")),console.log(t.default.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 --template \u9009\u9879\u53EF\u4EE5\u4ECE\u6A21\u677F\u521B\u5EFA\u9879\u76EE"))}catch(i){n.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${i instanceof Error?i.message:String(i)}`)}}l(eo,"createProject");function L(o,e,n=[]){a.default.existsSync(e)||a.default.mkdirSync(e,{recursive:!0});const i=a.default.readdirSync(o);for(const s of i){if(n.some(w=>s.includes(w)))continue;const c=g.default.join(o,s),r=g.default.join(e,s);a.default.statSync(c).isDirectory()?L(c,r,n):a.default.copyFileSync(c,r)}}l(L,"copyDirectory");async function no(o,e){const n=(0,f.default)("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!d.configManager.configExists()){n.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(t.default.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}if(e)switch(o){case"mcpEndpoint":d.configManager.updateMcpEndpoint(e),n.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${e}`);break;default:n.fail(`\u914D\u7F6E\u9879 ${o} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(t.default.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint"));return}else{n.text="\u8BFB\u53D6\u914D\u7F6E...";const i=d.configManager.getConfig();switch(o){case"mcpEndpoint":n.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(t.default.green(`MCP \u7AEF\u70B9: ${i.mcpEndpoint}`));break;case"mcpServers":n.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(t.default.green("MCP \u670D\u52A1:"));for(const[s,c]of Object.entries(i.mcpServers))console.log(t.default.gray(` ${s}: ${c.command} ${c.args.join(" ")}`));break;default:n.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${o}`),console.log(t.default.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers"));return}}}catch(i){n.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${i instanceof Error?i.message:String(i)}`)}}l(no,"configCommand");function to(){console.log(t.default.blue.bold("xiaozhi - MCP Calculator Service CLI")),console.log(),console.log(t.default.yellow("\u4F7F\u7528\u65B9\u6CD5:")),console.log(" xiaozhi <command> [options]"),console.log(),console.log(t.default.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(),console.log(t.default.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(t.default.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(t.default.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(t.default.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(t.default.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")}l(to,"showHelp"),p.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"),p.command("create <projectName>").description("\u521B\u5EFA\u9879\u76EE").option("-t, --template <templateName>","\u4F7F\u7528\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u9879\u76EE").action(async(o,e)=>{await eo(o,e)}),p.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").action(async()=>{await W()}),p.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(o,e)=>{await no(o,e)}),p.command("start").description("\u542F\u52A8\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").action(async o=>{await T(o.daemon)}),p.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await k()}),p.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await X()}),p.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await Z()}),p.command("restart").description("\u91CD\u542F\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").action(async o=>{await J(o.daemon)});const C=p.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");C.command("list").description("\u5217\u51FA MCP \u670D\u52A1").option("--tools","\u663E\u793A\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868").action(async o=>{await(0,h.listMcpServers)(o)}),C.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async o=>{await(0,h.listServerTools)(o)}),C.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(o,e,n)=>{n!=="enable"&&n!=="disable"&&(console.error(t.default.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await(0,h.setToolEnabled)(o,e,n==="enable")}),p.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(o=>{o.V&&(K(),process.exit(0))}),process.argv.length<=2&&(to(),process.exit(0)),p.parse(process.argv);
5
+ \u6B63\u5728\u505C\u6B62\u670D\u52A1...`)),r.kill("SIGTERM")}),process.on("SIGTERM",()=>{r.kill("SIGTERM")})}}catch(n){e.fail(`\u542F\u52A8\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}g(T,"startService");async function D(){const o=(0,f.default)("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{const e=v();if(!e.running){o.warn("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}o.text=`\u505C\u6B62\u670D\u52A1 (PID: ${e.pid})...`;try{process.kill(e.pid,"SIGTERM");let n=0;const i=30;for(;n<i;){await new Promise(s=>setTimeout(s,100));try{process.kill(e.pid,0),n++}catch{break}}try{process.kill(e.pid,0),o.text="\u5F3A\u5236\u505C\u6B62\u670D\u52A1...",process.kill(e.pid,"SIGKILL"),await new Promise(s=>setTimeout(s,500))}catch{}$(),o.succeed("\u670D\u52A1\u5DF2\u505C\u6B62")}catch(n){$(),o.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`)}}catch(e){o.fail(`\u505C\u6B62\u670D\u52A1\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}g(D,"stopService");async function W(){const o=(0,f.default)("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{const e=v();e.running?(o.succeed("\u670D\u52A1\u72B6\u6001"),console.log(t.default.green("\u2705 \u670D\u52A1\u6B63\u5728\u8FD0\u884C")),console.log(t.default.gray(` PID: ${e.pid}`)),console.log(t.default.gray(` \u8FD0\u884C\u65F6\u95F4: ${e.uptime}`)),console.log(t.default.gray(` \u8FD0\u884C\u6A21\u5F0F: ${e.mode==="daemon"?"\u540E\u53F0\u6A21\u5F0F":"\u524D\u53F0\u6A21\u5F0F"}`)),e.mode==="daemon"&&console.log(t.default.gray(` \u65E5\u5FD7\u6587\u4EF6: ${x}`))):(o.succeed("\u670D\u52A1\u72B6\u6001"),console.log(t.default.red("\u274C \u670D\u52A1\u672A\u8FD0\u884C")))}catch(e){o.fail(`\u68C0\u67E5\u72B6\u6001\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}g(W,"checkStatus");async function X(){const o=(0,f.default)("\u68C0\u67E5\u670D\u52A1\u72B6\u6001...").start();try{const e=v();if(!e.running){o.fail("\u670D\u52A1\u672A\u5728\u8FD0\u884C");return}if(e.mode!=="daemon"){o.fail("\u670D\u52A1\u4E0D\u662F\u5728\u540E\u53F0\u6A21\u5F0F\u8FD0\u884C");return}if(o.succeed("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1..."),console.log(t.default.green(`\u5DF2\u8FDE\u63A5\u5230\u670D\u52A1 (PID: ${e.pid})`)),console.log(t.default.gray("\u6309 Ctrl+C \u53EF\u4EE5\u65AD\u5F00\u8FDE\u63A5\uFF08\u4E0D\u4F1A\u505C\u6B62\u670D\u52A1\uFF09")),console.log(t.default.gray("=".repeat(50))),l.default.existsSync(x)){const{spawn:n}=await import("node:child_process"),i=n("tail",["-f",x],{stdio:"inherit"});process.on("SIGINT",()=>{console.log(t.default.yellow(`
6
+ \u65AD\u5F00\u8FDE\u63A5\uFF0C\u670D\u52A1\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C`)),i.kill(),process.exit(0)}),i.on("exit",()=>{process.exit(0)})}else console.log(t.default.yellow("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728"))}catch(e){o.fail(`\u8FDE\u63A5\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}g(X,"attachService");async function Z(o=!1){console.log(t.default.blue("\u{1F504} \u91CD\u542F\u670D\u52A1...")),await D(),await new Promise(e=>setTimeout(e,1e3)),await T(o)}g(Z,"restartService");function K(){const o=M();console.log(t.default.blue(`xiaozhi v${o}`)),console.log(t.default.gray("MCP Calculator Service CLI Tool")),console.log(t.default.gray("Built with Node.js and TypeScript")),console.log(t.default.gray(`Node.js: ${process.version}`)),console.log(t.default.gray(`Platform: ${process.platform} ${process.arch}`))}g(K,"showDetailedInfo");async function Y(){const o=(0,f.default)("\u521D\u59CB\u5316\u914D\u7F6E...").start();try{if(d.configManager.configExists()){o.warn("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728"),console.log(t.default.yellow("\u5982\u9700\u91CD\u65B0\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u5220\u9664\u73B0\u6709\u7684 xiaozhi.config.json \u6587\u4EF6"));return}d.configManager.initConfig(),o.succeed("\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u6210\u529F"),console.log(t.default.green("\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u521B\u5EFA: xiaozhi.config.json")),console.log(t.default.yellow("\u{1F4DD} \u8BF7\u7F16\u8F91\u914D\u7F6E\u6587\u4EF6\u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9:")),console.log(t.default.gray(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${d.configManager.getConfigPath()}`)),console.log(t.default.yellow("\u{1F4A1} \u6216\u8005\u4F7F\u7528\u547D\u4EE4\u8BBE\u7F6E:")),console.log(t.default.gray(" xiaozhi config mcpEndpoint <your-endpoint-url>"))}catch(e){o.fail(`\u521D\u59CB\u5316\u914D\u7F6E\u5931\u8D25: ${e instanceof Error?e.message:String(e)}`)}}g(Y,"initConfig");function Q(){const o=__dirname,n=[c.default.join(o,"..","templates"),c.default.join(o,"templates"),c.default.join(o,"..","..","templates")].find(i=>l.default.existsSync(i));return n?l.default.readdirSync(n).filter(i=>{const s=c.default.join(n,i);return l.default.statSync(s).isDirectory()}):[]}g(Q,"getAvailableTemplates");function _(o,e){const n=o.length,i=e.length,s=Array(n+1).fill(null).map(()=>Array(i+1).fill(0));for(let r=0;r<=n;r++)s[r][0]=r;for(let r=0;r<=i;r++)s[0][r]=r;for(let r=1;r<=n;r++)for(let m=1;m<=i;m++)o[r-1]===e[m-1]?s[r][m]=s[r-1][m-1]:s[r][m]=Math.min(s[r-1][m]+1,s[r][m-1]+1,s[r-1][m-1]+1);const a=Math.max(n,i);return a===0?1:(a-s[n][i])/a}g(_,"calculateSimilarity");function oo(o,e){if(e.length===0)return null;let n=e[0],i=_(o.toLowerCase(),n.toLowerCase());for(const s of e.slice(1)){const a=_(o.toLowerCase(),s.toLowerCase());a>i&&(i=a,n=s)}return i>.5?n:null}g(oo,"findSimilarTemplate");async function eo(o){if(!process.stdin.isTTY)return console.log("n (\u975E\u4EA4\u4E92\u5F0F\u73AF\u5883)"),!1;const e=await import("node:readline");return new Promise(n=>{process.stdout.write(o);const i=e.createInterface({input:process.stdin,output:process.stdout}),s=g(a=>{const r=a.trim().toLowerCase();r==="y"||r==="yes"?(i.close(),n(!0)):r==="n"||r==="no"||r===""?(i.close(),n(!1)):process.stdout.write("\u8BF7\u8F93\u5165 y \u6216 n: ")},"handleInput");i.on("line",s),i.on("SIGINT",()=>{i.close(),n(!1)})})}g(eo,"askUserConfirmation");function no(o){const e={mcpEndpoint:"<\u8BF7\u586B\u5199\u4F60\u7684\u63A5\u5165\u70B9\u5730\u5740\uFF08\u83B7\u53D6\u5730\u5740\u5728 xiaozhi.me\uFF09>",mcpServers:{}},n=c.default.join(o,"xiaozhi.config.json");l.default.writeFileSync(n,JSON.stringify(e,null,2),"utf8")}g(no,"createBasicConfig");async function to(o,e){const n=(0,f.default)("\u521D\u59CB\u5316\u9879\u76EE...").start();try{const i=c.default.join(process.cwd(),o);if(l.default.existsSync(i)){n.fail(`\u76EE\u5F55 "${o}" \u5DF2\u5B58\u5728`),console.log(t.default.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u9009\u62E9\u4E0D\u540C\u7684\u9879\u76EE\u540D\u79F0\u6216\u5220\u9664\u73B0\u6709\u76EE\u5F55"));return}if(e.template){n.text="\u68C0\u67E5\u6A21\u677F...";const s=Q();if(s.length===0){n.fail("\u627E\u4E0D\u5230 templates \u76EE\u5F55"),console.log(t.default.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u786E\u4FDD xiaozhi-client \u6B63\u786E\u5B89\u88C5"));return}if(!s.includes(e.template)){n.fail(`\u6A21\u677F "${e.template}" \u4E0D\u5B58\u5728`);const S=oo(e.template,s);if(S)if(console.log(t.default.yellow(`\u{1F4A1} \u4F60\u662F\u60F3\u4F7F\u7528\u6A21\u677F "${S}" \u5417\uFF1F`)),await eo(t.default.cyan("\u786E\u8BA4\u4F7F\u7528\u6B64\u6A21\u677F\uFF1F(y/n): ")))e.template=S;else{console.log(t.default.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(const F of s)console.log(t.default.gray(` - ${F}`));return}else{console.log(t.default.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));for(const z of s)console.log(t.default.gray(` - ${z}`));return}}const a=__dirname,m=[c.default.join(a,"..","templates"),c.default.join(a,"templates"),c.default.join(a,"..","..","templates")].find(S=>l.default.existsSync(S)),w=c.default.join(m,e.template);n.text=`\u4ECE\u6A21\u677F "${e.template}" \u521B\u5EFA\u9879\u76EE "${o}"...`,L(w,i,["node_modules",".pnpm-debug.log","pnpm-lock.yaml"]),n.succeed(`\u9879\u76EE "${o}" \u521B\u5EFA\u6210\u529F`),console.log(t.default.green("\u2705 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(t.default.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(t.default.gray(` cd ${o}`)),console.log(t.default.gray(" pnpm install # \u5B89\u88C5\u4F9D\u8D56")),console.log(t.default.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9")),console.log(t.default.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1"))}else n.text=`\u521B\u5EFA\u57FA\u672C\u9879\u76EE "${o}"...`,l.default.mkdirSync(i,{recursive:!0}),no(i),n.succeed(`\u9879\u76EE "${o}" \u521B\u5EFA\u6210\u529F`),console.log(t.default.green("\u2705 \u57FA\u672C\u9879\u76EE\u521B\u5EFA\u5B8C\u6210!")),console.log(t.default.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:")),console.log(t.default.gray(` cd ${o}`)),console.log(t.default.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9\u548C\u670D\u52A1")),console.log(t.default.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1")),console.log(t.default.yellow("\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 --template \u9009\u9879\u53EF\u4EE5\u4ECE\u6A21\u677F\u521B\u5EFA\u9879\u76EE"))}catch(i){n.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${i instanceof Error?i.message:String(i)}`)}}g(to,"createProject");function L(o,e,n=[]){l.default.existsSync(e)||l.default.mkdirSync(e,{recursive:!0});const i=l.default.readdirSync(o);for(const s of i){if(n.some(w=>s.includes(w)))continue;const a=c.default.join(o,s),r=c.default.join(e,s);l.default.statSync(a).isDirectory()?L(a,r,n):l.default.copyFileSync(a,r)}}g(L,"copyDirectory");async function io(o,e){const n=(0,f.default)("\u66F4\u65B0\u914D\u7F6E...").start();try{if(!d.configManager.configExists()){n.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728"),console.log(t.default.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi init" \u521D\u59CB\u5316\u914D\u7F6E'));return}if(e)switch(o){case"mcpEndpoint":d.configManager.updateMcpEndpoint(e),n.succeed(`MCP \u7AEF\u70B9\u5DF2\u66F4\u65B0\u4E3A: ${e}`);break;default:n.fail(`\u914D\u7F6E\u9879 ${o} \u4E0D\u652F\u6301\u901A\u8FC7\u547D\u4EE4\u884C\u8BBE\u7F6E`),console.log(t.default.yellow("\u652F\u6301\u8BBE\u7F6E\u7684\u914D\u7F6E\u9879: mcpEndpoint"));return}else{n.text="\u8BFB\u53D6\u914D\u7F6E...";const i=d.configManager.getConfig();switch(o){case"mcpEndpoint":n.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(t.default.green(`MCP \u7AEF\u70B9: ${i.mcpEndpoint}`));break;case"mcpServers":n.succeed("\u914D\u7F6E\u4FE1\u606F"),console.log(t.default.green("MCP \u670D\u52A1:"));for(const[s,a]of Object.entries(i.mcpServers))console.log(t.default.gray(` ${s}: ${a.command} ${a.args.join(" ")}`));break;default:n.fail(`\u672A\u77E5\u7684\u914D\u7F6E\u9879: ${o}`),console.log(t.default.yellow("\u652F\u6301\u7684\u914D\u7F6E\u9879: mcpEndpoint, mcpServers"));return}}}catch(i){n.fail(`\u914D\u7F6E\u64CD\u4F5C\u5931\u8D25: ${i instanceof Error?i.message:String(i)}`)}}g(io,"configCommand");function so(){console.log(t.default.blue.bold("xiaozhi - MCP Calculator Service CLI")),console.log(),console.log(t.default.yellow("\u4F7F\u7528\u65B9\u6CD5:")),console.log(" xiaozhi <command> [options]"),console.log(),console.log(t.default.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(),console.log(t.default.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(t.default.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(t.default.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(t.default.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(t.default.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")}g(so,"showHelp"),p.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(M(),"-v, --version","\u663E\u793A\u7248\u672C\u4FE1\u606F").helpOption("-h, --help","\u663E\u793A\u5E2E\u52A9\u4FE1\u606F"),p.command("create <projectName>").description("\u521B\u5EFA\u9879\u76EE").option("-t, --template <templateName>","\u4F7F\u7528\u6307\u5B9A\u6A21\u677F\u521B\u5EFA\u9879\u76EE").action(async(o,e)=>{await to(o,e)}),p.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").action(async()=>{await Y()}),p.command("config <key> [value]").description("\u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E").action(async(o,e)=>{await io(o,e)}),p.command("start").description("\u542F\u52A8\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").action(async o=>{await T(o.daemon)}),p.command("stop").description("\u505C\u6B62\u670D\u52A1").action(async()=>{await D()}),p.command("status").description("\u68C0\u67E5\u670D\u52A1\u72B6\u6001").action(async()=>{await W()}),p.command("attach").description("\u8FDE\u63A5\u5230\u540E\u53F0\u670D\u52A1\u67E5\u770B\u65E5\u5FD7").action(async()=>{await X()}),p.command("restart").description("\u91CD\u542F\u670D\u52A1").option("-d, --daemon","\u5728\u540E\u53F0\u8FD0\u884C\u670D\u52A1").action(async o=>{await Z(o.daemon)});const C=p.command("mcp").description("MCP \u670D\u52A1\u548C\u5DE5\u5177\u7BA1\u7406");C.command("list").description("\u5217\u51FA MCP \u670D\u52A1").option("--tools","\u663E\u793A\u6240\u6709\u670D\u52A1\u7684\u5DE5\u5177\u5217\u8868").action(async o=>{await(0,h.listMcpServers)(o)}),C.command("server <serverName>").description("\u7BA1\u7406\u6307\u5B9A\u7684 MCP \u670D\u52A1").action(async o=>{await(0,h.listServerTools)(o)}),C.command("tool <serverName> <toolName> <action>").description("\u542F\u7528\u6216\u7981\u7528\u6307\u5B9A\u670D\u52A1\u7684\u5DE5\u5177").action(async(o,e,n)=>{n!=="enable"&&n!=="disable"&&(console.error(t.default.red("\u9519\u8BEF: \u64CD\u4F5C\u5FC5\u987B\u662F 'enable' \u6216 'disable'")),process.exit(1)),await(0,h.setToolEnabled)(o,e,n==="enable")}),p.option("-V","\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(o=>{o.V&&(K(),process.exit(0))}),process.argv.length<=2&&(so(),process.exit(0)),p.parse(process.argv);
7
7
  //# sourceMappingURL=cli.cjs.map
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.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 chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\nimport { configManager } from \"./configManager.js\";\nimport {\n listMcpServers,\n listServerTools,\n setToolEnabled,\n} from \"./mcpCommands.js\";\n\nconst program = new Command();\nconst VERSION = \"0.0.1\";\nconst SERVICE_NAME = \"xiaozhi-mcp-service\";\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 */\nfunction 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 */\nfunction 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 */\nfunction 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 `❌ 错误: 配置文件无效 - ${error instanceof Error ? error.message : String(error)}`\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 = __dirname;\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.cjs\")) &&\n fs.existsSync(path.join(p, \"mcpServerProxy.cjs\"))\n ) || scriptDir;\n }\n\n return {\n command: \"node\",\n args: [\"mcpPipe.cjs\", \"mcpServerProxy.cjs\"],\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 `停止服务失败: ${error instanceof Error ? error.message : String(error)}`\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 // 显示最后100行日志\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 } 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 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 `初始化配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 获取可用模板列表\n */\nfunction getAvailableTemplates(): string[] {\n const scriptDir = __dirname;\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 */\nfunction 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 // 获取模板路径\n const scriptDir = __dirname;\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 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();\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}\n\n// 配置 Commander 程序\nprogram\n .name(\"xiaozhi\")\n .description(\"MCP Calculator Service CLI Tool\")\n .version(VERSION, \"-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// -V 选项 (详细信息)\nprogram.option(\"-V\", \"显示详细信息\").action((options) => {\n if (options.V) {\n showDetailedInfo();\n process.exit(0);\n }\n});\n\n// 处理无参数情况,显示帮助\nif (process.argv.length <= 2) {\n showHelp();\n process.exit(0);\n}\n\n// 解析命令行参数\nprogram.parse(process.argv);\n"],"mappings":"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","names":["import_node_child_process","import_node_fs","import_node_os","import_node_path","import_chalk","import_commander","import_ora","import_configManager","import_mcpCommands","program","VERSION","SERVICE_NAME","PID_FILE","path","os","LOG_FILE","getServiceStatus","fs","pidContent","pidStr","startTime","mode","pid","start","uptime","formatUptime","__name","ms","seconds","minutes","hours","days","savePidInfo","pidInfo","cleanupPidFile","checkEnvironment","chalk","endpoint","error","getServiceCommand","scriptDir","distDir","p","startService","daemon","spinner","ora","status","command","args","cwd","child","logStream","code","signal","stopService","attempts","maxAttempts","resolve","checkStatus","attachService","spawn","tail","restartService","showDetailedInfo","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","serverName","toolName","action"]}
1
+ {"version":3,"sources":["../src/cli.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 { configManager } from \"./configManager.js\";\nimport {\n listMcpServers,\n listServerTools,\n setToolEnabled,\n} from \"./mcpCommands.js\";\n\nconst program = new Command();\nconst SERVICE_NAME = \"xiaozhi-mcp-service\";\n\n/**\n * 获取版本号\n */\nfunction getVersion(): string {\n try {\n let currentDir: string;\n\n // 检查是否在 ES 模块环境中\n if (typeof import.meta !== \"undefined\" && import.meta.url) {\n // ES 模块环境\n const __filename = fileURLToPath(import.meta.url);\n currentDir = path.dirname(__filename);\n } else {\n // CommonJS 环境,使用 require.main 或 process.cwd()\n if (require.main?.filename) {\n currentDir = path.dirname(require.main.filename);\n } else {\n currentDir = process.cwd();\n }\n }\n\n // 尝试多个可能的 package.json 路径\n const possiblePaths = [\n // 开发环境:src/cli.ts -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 构建后环境:dist/cli.cjs -> 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 */\nfunction 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 */\nfunction 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 */\nfunction 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 `❌ 错误: 配置文件无效 - ${error instanceof Error ? error.message : String(error)}`\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 = __dirname;\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.cjs\")) &&\n fs.existsSync(path.join(p, \"mcpServerProxy.cjs\"))\n ) || scriptDir;\n }\n\n return {\n command: \"node\",\n args: [\"mcpPipe.cjs\", \"mcpServerProxy.cjs\"],\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 `停止服务失败: ${error instanceof Error ? error.message : String(error)}`\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 // 显示最后100行日志\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 } 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 `初始化配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 获取可用模板列表\n */\nfunction getAvailableTemplates(): string[] {\n const scriptDir = __dirname;\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 */\nfunction 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 // 获取模板路径\n const scriptDir = __dirname;\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 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();\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}\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// -V 选项 (详细信息)\nprogram.option(\"-V\", \"显示详细信息\").action((options) => {\n if (options.V) {\n showDetailedInfo();\n process.exit(0);\n }\n});\n\n// 处理无参数情况,显示帮助\nif (process.argv.length <= 2) {\n showHelp();\n process.exit(0);\n}\n\n// 解析命令行参数\nprogram.parse(process.argv);\n"],"mappings":";2gBAAA,MAAAA,EAAA,GAEA,IAAAC,EAAsB,8BACtBC,EAAe,sBACfC,EAAe,sBACfC,EAAiB,wBACjBC,EAA8B,oBAC9BC,EAAkB,oBAClBC,EAAwB,qBACxBC,EAAgB,kBAChBC,EAA8B,8BAC9BC,EAIO,4BAEP,MAAMC,EAAU,IAAI,UACdC,EAAe,sBAKrB,SAASC,GAAqB,CAC5B,GAAI,CACF,IAAIC,EAGJ,GAAI,OAAOC,EAAgB,KAAeA,EAAY,IAAK,CAEzD,MAAMC,KAAa,iBAAcD,EAAY,GAAG,EAChDD,EAAa,EAAAG,QAAK,QAAQD,CAAU,CACtC,MAEM,QAAQ,MAAM,SAChBF,EAAa,EAAAG,QAAK,QAAQ,QAAQ,KAAK,QAAQ,EAE/CH,EAAa,QAAQ,IAAI,EAK7B,MAAMI,EAAgB,CAEpB,EAAAD,QAAK,KAAKH,EAAY,KAAM,cAAc,EAE1C,EAAAG,QAAK,KAAKH,EAAY,KAAM,cAAc,EAE1C,EAAAG,QAAK,KAAKH,EAAY,KAAM,KAAM,cAAc,EAEhD,EAAAG,QAAK,KAAKH,EAAY,cAAc,CACtC,EAEA,UAAWK,KAAeD,EACxB,GAAI,EAAAE,QAAG,WAAWD,CAAW,EAAG,CAC9B,MAAME,EAAc,KAAK,MAAM,EAAAD,QAAG,aAAaD,EAAa,MAAM,CAAC,EACnE,GAAIE,EAAY,QACd,OAAOA,EAAY,OAEvB,CAIF,MAAO,SACT,OAASC,EAAO,CACd,eAAQ,KAAK,qDAAsDA,CAAK,EACjE,SACT,CACF,CA7CSC,EAAAV,EAAA,cAgDT,MAAMW,EAAW,EAAAP,QAAK,KAAK,EAAAQ,QAAG,OAAO,EAAG,GAAGb,CAAY,MAAM,EACvDc,EAAW,EAAAT,QAAK,KAAK,EAAAQ,QAAG,OAAO,EAAG,GAAGb,CAAY,MAAM,EAY7D,SAASe,GAAkC,CACzC,GAAI,CACF,GAAI,CAAC,EAAAP,QAAG,WAAWI,CAAQ,EACzB,MAAO,CAAE,QAAS,EAAM,EAG1B,MAAMI,EAAa,EAAAR,QAAG,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,SAAAZ,QAAG,WAAWI,CAAQ,EACf,CAAE,QAAS,EAAM,EAI1B,GAAI,CACF,QAAQ,KAAKQ,EAAK,CAAC,EAGnB,MAAMC,EAAQ,OAAO,SAASH,CAAS,EACjCI,EAASC,EAAa,KAAK,IAAI,EAAIF,CAAK,EAE9C,MAAO,CACL,QAAS,GACT,IAAAD,EACA,OAAAE,EACA,KAAOH,GAAoC,YAC7C,CACF,MAAgB,CAEd,SAAAX,QAAG,WAAWI,CAAQ,EACf,CAAE,QAAS,EAAM,CAC1B,CACF,MAAgB,CACd,MAAO,CAAE,QAAS,EAAM,CAC1B,CACF,CAtCSD,EAAAI,EAAA,oBA2CT,SAASQ,EAAaC,EAAoB,CACxC,MAAMC,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,CAhBSd,EAAAY,EAAA,gBAqBT,SAASM,EAAYT,EAAaD,EAA+B,CAC/D,MAAMW,EAAU,GAAGV,CAAG,IAAI,KAAK,IAAI,CAAC,IAAID,CAAI,GAC5C,EAAAX,QAAG,cAAcI,EAAUkB,CAAO,CACpC,CAHSnB,EAAAkB,EAAA,eAQT,SAASE,GAAiB,CACxB,GAAI,CACE,EAAAvB,QAAG,WAAWI,CAAQ,GACxB,EAAAJ,QAAG,WAAWI,CAAQ,CAE1B,MAAgB,CAEhB,CACF,CARSD,EAAAoB,EAAA,kBAaT,SAASC,GAA4B,CAEnC,GAAI,CAAC,gBAAc,aAAa,EAC9B,eAAQ,MAAM,EAAAC,QAAM,IAAI,iEAAe,CAAC,EACxC,QAAQ,IAAI,EAAAA,QAAM,OAAO,0FAAiC,CAAC,EACpD,GAGT,GAAI,CAEF,MAAMC,EAAW,gBAAc,eAAe,EAC9C,MAAI,CAACA,GAAYA,EAAS,SAAS,qBAAM,GACvC,QAAQ,MAAM,EAAAD,QAAM,IAAI,yDAAiB,CAAC,EAC1C,QAAQ,IACN,EAAAA,QAAM,OACJ,sHACF,CACF,EACO,IAEF,EACT,OAASvB,EAAO,CACd,eAAQ,MACN,EAAAuB,QAAM,IACJ,+DAAkBvB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EAC1E,CACF,EACA,QAAQ,IAAI,EAAAuB,QAAM,OAAO,sGAAmC,CAAC,EACtD,EACT,CACF,CA9BStB,EAAAqB,EAAA,oBAmCT,SAASG,GAAsE,CAE7E,MAAMC,EAAY,UAGlB,IAAIC,EACJ,OAAID,EAAU,SAAS,cAAc,EAEnCC,EAAUD,EAaVC,EARsB,CACpB,EAAAhC,QAAK,KAAK+B,EAAW,KAAM,UAAW,MAAM,EAC5C,EAAA/B,QAAK,KAAK+B,EAAW,KAAM,KAAM,UAAW,MAAM,EAClD,EAAA/B,QAAK,KAAK+B,EAAW,KAAM,KAAM,KAAM,UAAW,MAAM,EACxD,EAAA/B,QAAK,KAAK,QAAQ,IAAI,EAAG,UAAW,MAAM,EAC1C,EAAAA,QAAK,KAAK,QAAQ,IAAI,EAAG,MAAM,CACjC,EAGgB,KACXiC,GACC,EAAA9B,QAAG,WAAW,EAAAH,QAAK,KAAKiC,EAAG,aAAa,CAAC,GACzC,EAAA9B,QAAG,WAAW,EAAAH,QAAK,KAAKiC,EAAG,oBAAoB,CAAC,CACpD,GAAKF,EAGF,CACL,QAAS,OACT,KAAM,CAAC,cAAe,oBAAoB,EAC1C,IAAKC,CACP,CACF,CAlCS1B,EAAAwB,EAAA,qBAuCT,eAAeI,EAAaC,EAAS,GAAsB,CACzD,MAAMC,KAAU,EAAAC,SAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CAEF,MAAMC,EAAS5B,EAAiB,EAChC,GAAI4B,EAAO,QAAS,CAClBF,EAAQ,KAAK,oDAAiBE,EAAO,GAAG,GAAG,EAC3C,MACF,CAIA,GADAF,EAAQ,KAAO,0CACX,CAACT,EAAiB,EAAG,CACvBS,EAAQ,KAAK,kDAAU,EACvB,MACF,CAGA,KAAM,CAAE,QAAAG,EAAS,KAAAC,EAAM,IAAAC,CAAI,EAAIX,EAAkB,EAIjD,GAFAM,EAAQ,KAAO,6BAASD,EAAS,2BAAS,0BAAM,OAE5CA,EAAQ,CAEV,MAAMO,KAAQ,SAAMH,EAASC,EAAM,CACjC,IAAAC,EACA,SAAU,GACV,MAAO,CAAC,SAAU,OAAQ,MAAM,EAChC,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,CAClC,CACF,CAAC,EAGDjB,EAAYkB,EAAM,IAAM,QAAQ,EAGhC,MAAMC,EAAY,EAAAxC,QAAG,kBAAkBM,EAAU,CAAE,MAAO,GAAI,CAAC,EAC/DiC,EAAM,QAAQ,KAAKC,CAAS,EAC5BD,EAAM,QAAQ,KAAKC,CAAS,EAG5BD,EAAM,MAAM,EAEZN,EAAQ,QAAQ,0DAAkBM,EAAM,GAAG,GAAG,EAC9C,QAAQ,IAAI,EAAAd,QAAM,KAAK,6BAASnB,CAAQ,EAAE,CAAC,EAC3C,QAAQ,IAAI,EAAAmB,QAAM,KAAK,gFAA8B,CAAC,CACxD,KAAO,CAELQ,EAAQ,QAAQ,mCAAU,EAE1B,MAAMM,KAAQ,SAAMH,EAASC,EAAM,CACjC,IAAAC,EACA,MAAO,UACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,CAClC,CACF,CAAC,EAGDjB,EAAYkB,EAAM,IAAM,YAAY,EAGpCA,EAAM,GAAG,OAAQ,CAACE,EAAMC,IAAW,CACjCnB,EAAe,EAEb,QAAQ,IADNkB,IAAS,EAET,EAAAhB,QAAM,IAAI;AAAA,sDAAiBgB,CAAI,mBAASC,CAAM,GAAG,EAGvC,EAAAjB,QAAM,MAAM;AAAA,+BAAS,CAFjC,CAIJ,CAAC,EAGD,QAAQ,GAAG,SAAU,IAAM,CACzB,QAAQ,IAAI,EAAAA,QAAM,OAAO;AAAA,wCAAa,CAAC,EACvCc,EAAM,KAAK,SAAS,CACtB,CAAC,EAED,QAAQ,GAAG,UAAW,IAAM,CAC1BA,EAAM,KAAK,SAAS,CACtB,CAAC,CACH,CACF,OAASrC,EAAO,CACd+B,EAAQ,KACN,yCAAW/B,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CA5FeC,EAAA4B,EAAA,gBAiGf,eAAeY,GAA6B,CAC1C,MAAMV,KAAU,EAAAC,SAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CACF,MAAMC,EAAS5B,EAAiB,EAEhC,GAAI,CAAC4B,EAAO,QAAS,CACnBF,EAAQ,KAAK,sCAAQ,EACrB,MACF,CAEAA,EAAQ,KAAO,kCAAcE,EAAO,GAAG,OAEvC,GAAI,CAEF,QAAQ,KAAKA,EAAO,IAAM,SAAS,EAGnC,IAAIS,EAAW,EACf,MAAMC,EAAc,GAEpB,KAAOD,EAAWC,GAAa,CAC7B,MAAM,IAAI,QAASC,GAAY,WAAWA,EAAS,GAAG,CAAC,EAEvD,GAAI,CACF,QAAQ,KAAKX,EAAO,IAAM,CAAC,EAC3BS,GACF,MAAQ,CAEN,KACF,CACF,CAGA,GAAI,CACF,QAAQ,KAAKT,EAAO,IAAM,CAAC,EAE3BF,EAAQ,KAAO,0CACf,QAAQ,KAAKE,EAAO,IAAM,SAAS,EACnC,MAAM,IAAI,QAASW,GAAY,WAAWA,EAAS,GAAG,CAAC,CACzD,MAAQ,CAER,CAEAvB,EAAe,EACfU,EAAQ,QAAQ,gCAAO,CACzB,OAAS/B,EAAO,CACdqB,EAAe,EACfU,EAAQ,KACN,yCAAW/B,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,OAASA,EAAO,CACd+B,EAAQ,KACN,yCAAW/B,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAzDeC,EAAAwC,EAAA,eA8Df,eAAeI,GAA6B,CAC1C,MAAMd,KAAU,EAAAC,SAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CACF,MAAMC,EAAS5B,EAAiB,EAE5B4B,EAAO,SACTF,EAAQ,QAAQ,0BAAM,EACtB,QAAQ,IAAI,EAAAR,QAAM,MAAM,6CAAU,CAAC,EACnC,QAAQ,IAAI,EAAAA,QAAM,KAAK,WAAWU,EAAO,GAAG,EAAE,CAAC,EAC/C,QAAQ,IAAI,EAAAV,QAAM,KAAK,gCAAYU,EAAO,MAAM,EAAE,CAAC,EACnD,QAAQ,IACN,EAAAV,QAAM,KACJ,gCAAYU,EAAO,OAAS,SAAW,2BAAS,0BAAM,EACxD,CACF,EAEIA,EAAO,OAAS,UAClB,QAAQ,IAAI,EAAAV,QAAM,KAAK,gCAAYnB,CAAQ,EAAE,CAAC,IAGhD2B,EAAQ,QAAQ,0BAAM,EACtB,QAAQ,IAAI,EAAAR,QAAM,IAAI,uCAAS,CAAC,EAEpC,OAASvB,EAAO,CACd+B,EAAQ,KACN,yCAAW/B,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CA7BeC,EAAA4C,EAAA,eAkCf,eAAeC,GAA+B,CAC5C,MAAMf,KAAU,EAAAC,SAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CACF,MAAMC,EAAS5B,EAAiB,EAEhC,GAAI,CAAC4B,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,IAAI,EAAAR,QAAM,MAAM,8CAAgBU,EAAO,GAAG,GAAG,CAAC,EACtD,QAAQ,IAAI,EAAAV,QAAM,KAAK,oGAAyB,CAAC,EACjD,QAAQ,IAAI,EAAAA,QAAM,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC,EAGlC,EAAAzB,QAAG,WAAWM,CAAQ,EAAG,CAE3B,KAAM,CAAE,MAAA2C,CAAM,EAAI,KAAM,QAAO,oBAAoB,EAC7CC,EAAOD,EAAM,OAAQ,CAAC,KAAM3C,CAAQ,EAAG,CAAE,MAAO,SAAU,CAAC,EAGjE,QAAQ,GAAG,SAAU,IAAM,CACzB,QAAQ,IAAI,EAAAmB,QAAM,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,MACE,QAAQ,IAAI,EAAAzB,QAAM,OAAO,4CAAS,CAAC,CAEvC,OAASvB,EAAO,CACd+B,EAAQ,KACN,6BAAS/B,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACjE,CACF,CACF,CA7CeC,EAAA6C,EAAA,iBAkDf,eAAeG,EAAenB,EAAS,GAAsB,CAC3D,QAAQ,IAAI,EAAAP,QAAM,KAAK,uCAAY,CAAC,EAGpC,MAAMkB,EAAY,EAGlB,MAAM,IAAI,QAASG,GAAY,WAAWA,EAAS,GAAI,CAAC,EAGxD,MAAMf,EAAaC,CAAM,CAC3B,CAXe7B,EAAAgD,EAAA,kBAgBf,SAASC,GAAyB,CAChC,MAAMC,EAAU5D,EAAW,EAC3B,QAAQ,IAAI,EAAAgC,QAAM,KAAK,YAAY4B,CAAO,EAAE,CAAC,EAC7C,QAAQ,IAAI,EAAA5B,QAAM,KAAK,iCAAiC,CAAC,EACzD,QAAQ,IAAI,EAAAA,QAAM,KAAK,mCAAmC,CAAC,EAC3D,QAAQ,IAAI,EAAAA,QAAM,KAAK,YAAY,QAAQ,OAAO,EAAE,CAAC,EACrD,QAAQ,IAAI,EAAAA,QAAM,KAAK,aAAa,QAAQ,QAAQ,IAAI,QAAQ,IAAI,EAAE,CAAC,CACzE,CAPStB,EAAAiD,EAAA,oBAYT,eAAeE,GAA4B,CACzC,MAAMrB,KAAU,EAAAC,SAAI,mCAAU,EAAE,MAAM,EAEtC,GAAI,CACF,GAAI,gBAAc,aAAa,EAAG,CAChCD,EAAQ,KAAK,4CAAS,EACtB,QAAQ,IACN,EAAAR,QAAM,OAAO,6HAAwC,CACvD,EACA,MACF,CAEA,gBAAc,WAAW,EACzBQ,EAAQ,QAAQ,wDAAW,EAE3B,QAAQ,IAAI,EAAAR,QAAM,MAAM,wEAAgC,CAAC,EACzD,QAAQ,IAAI,EAAAA,QAAM,OAAO,gGAAwB,CAAC,EAClD,QAAQ,IACN,EAAAA,QAAM,KAAK,4CAAc,gBAAc,cAAc,CAAC,EAAE,CAC1D,EACA,QAAQ,IAAI,EAAAA,QAAM,OAAO,6DAAc,CAAC,EACxC,QAAQ,IACN,EAAAA,QAAM,KAAK,mDAAmD,CAChE,CACF,OAASvB,EAAO,CACd+B,EAAQ,KACN,+CAAY/B,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACpE,CACF,CACF,CA7BeC,EAAAmD,EAAA,cAkCf,SAASC,GAAkC,CACzC,MAAM3B,EAAY,UAOZ4B,EANgB,CACpB,EAAA3D,QAAK,KAAK+B,EAAW,KAAM,WAAW,EACtC,EAAA/B,QAAK,KAAK+B,EAAW,WAAW,EAChC,EAAA/B,QAAK,KAAK+B,EAAW,KAAM,KAAM,WAAW,CAC9C,EAEmC,KAAME,GAAM,EAAA9B,QAAG,WAAW8B,CAAC,CAAC,EAC/D,OAAK0B,EAIE,EAAAxD,QAAG,YAAYwD,CAAY,EAAE,OAAQC,GAAS,CACnD,MAAMC,EAAW,EAAA7D,QAAK,KAAK2D,EAAcC,CAAI,EAC7C,OAAO,EAAAzD,QAAG,SAAS0D,CAAQ,EAAE,YAAY,CAC3C,CAAC,EANQ,CAAC,CAOZ,CAjBSvD,EAAAoD,EAAA,yBAsBT,SAASI,EAAoBC,EAAcC,EAAsB,CAC/D,MAAMC,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,MAAMC,EAAS,KAAK,IAAIL,EAAMC,CAAI,EAClC,OAAOI,IAAW,EAAI,GAAKA,EAASH,EAAOF,CAAI,EAAEC,CAAI,GAAKI,CAC5D,CA1BShE,EAAAwD,EAAA,uBA+BT,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,UAAWE,KAAYH,EAAU,MAAM,CAAC,EAAG,CACzC,MAAMI,EAAaf,EACjBU,EAAM,YAAY,EAClBI,EAAS,YAAY,CACvB,EACIC,EAAaF,IACfA,EAAiBE,EACjBH,EAAYE,EAEhB,CAGA,OAAOD,EAAiB,GAAMD,EAAY,IAC5C,CAzBSpE,EAAAiE,GAAA,uBA8BT,eAAeO,GAAoBC,EAAoC,CAErE,GAAI,CAAC,QAAQ,MAAM,MAEjB,eAAQ,IAAI,0CAAY,EACjB,GAIT,MAAMC,EAAW,KAAM,QAAO,eAAe,EAE7C,OAAO,IAAI,QAAS/B,GAAY,CAC9B,QAAQ,OAAO,MAAM8B,CAAQ,EAE7B,MAAME,EAAKD,EAAS,gBAAgB,CAClC,MAAO,QAAQ,MACf,OAAQ,QAAQ,MAClB,CAAC,EAEKE,EAAc5E,EAACkE,GAAkB,CACrC,MAAMW,EAAOX,EAAM,KAAK,EAAE,YAAY,EAClCW,IAAS,KAAOA,IAAS,OAC3BF,EAAG,MAAM,EACThC,EAAQ,EAAI,GACHkC,IAAS,KAAOA,IAAS,MAAQA,IAAS,IACnDF,EAAG,MAAM,EACThC,EAAQ,EAAK,GAGb,QAAQ,OAAO,MAAM,iCAAa,CAEtC,EAZoB,eAcpBgC,EAAG,GAAG,OAAQC,CAAW,EACzBD,EAAG,GAAG,SAAU,IAAM,CACpBA,EAAG,MAAM,EACThC,EAAQ,EAAK,CACf,CAAC,CACH,CAAC,CACH,CAvCe3C,EAAAwE,GAAA,uBA4Cf,SAASM,GAAkBC,EAA2B,CACpD,MAAMC,EAAgB,CACpB,YAAa,sHACb,WAAY,CAAC,CACf,EAEMC,EAAa,EAAAvF,QAAK,KAAKqF,EAAa,qBAAqB,EAC/D,EAAAlF,QAAG,cAAcoF,EAAY,KAAK,UAAUD,EAAe,KAAM,CAAC,EAAG,MAAM,CAC7E,CARShF,EAAA8E,GAAA,qBAaT,eAAeI,GACbC,EACAC,EACe,CACf,MAAMtD,KAAU,EAAAC,SAAI,mCAAU,EAAE,MAAM,EAEtC,GAAI,CAEF,MAAMsD,EAAa,EAAA3F,QAAK,KAAK,QAAQ,IAAI,EAAGyF,CAAW,EAGvD,GAAI,EAAAtF,QAAG,WAAWwF,CAAU,EAAG,CAC7BvD,EAAQ,KAAK,iBAAOqD,CAAW,sBAAO,EACtC,QAAQ,IAAI,EAAA7D,QAAM,OAAO,gIAA0B,CAAC,EACpD,MACF,CAEA,GAAI8D,EAAQ,SAAU,CAEpBtD,EAAQ,KAAO,8BAGf,MAAMwD,EAAqBlC,EAAsB,EAEjD,GAAIkC,EAAmB,SAAW,EAAG,CACnCxD,EAAQ,KAAK,2CAAkB,EAC/B,QAAQ,IAAI,EAAAR,QAAM,OAAO,oFAAgC,CAAC,EAC1D,MACF,CAGA,GAAI,CAACgE,EAAmB,SAASF,EAAQ,QAAQ,EAAG,CAClDtD,EAAQ,KAAK,iBAAOsD,EAAQ,QAAQ,sBAAO,EAG3C,MAAMG,EAAkBtB,GACtBmB,EAAQ,SACRE,CACF,EAEA,GAAIC,EAQF,GAPA,QAAQ,IACN,EAAAjE,QAAM,OAAO,yDAAeiE,CAAe,gBAAM,CACnD,EACkB,MAAMf,GACtB,EAAAlD,QAAM,KAAK,yDAAiB,CAC9B,EAGE8D,EAAQ,SAAWG,MACd,CACL,QAAQ,IAAI,EAAAjE,QAAM,OAAO,iCAAQ,CAAC,EAClC,UAAWgD,KAAYgB,EACrB,QAAQ,IAAI,EAAAhE,QAAM,KAAK,OAAOgD,CAAQ,EAAE,CAAC,EAE3C,MACF,KACK,CACL,QAAQ,IAAI,EAAAhD,QAAM,OAAO,iCAAQ,CAAC,EAClC,UAAWgD,KAAYgB,EACrB,QAAQ,IAAI,EAAAhE,QAAM,KAAK,OAAOgD,CAAQ,EAAE,CAAC,EAE3C,MACF,CACF,CAGA,MAAM7C,EAAY,UAMZ4B,EALgB,CACpB,EAAA3D,QAAK,KAAK+B,EAAW,KAAM,WAAW,EACtC,EAAA/B,QAAK,KAAK+B,EAAW,WAAW,EAChC,EAAA/B,QAAK,KAAK+B,EAAW,KAAM,KAAM,WAAW,CAC9C,EACmC,KAAME,GAAM,EAAA9B,QAAG,WAAW8B,CAAC,CAAC,EACzD6D,EAAe,EAAA9F,QAAK,KAAK2D,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,IAAI,EAAA7D,QAAM,MAAM,8CAAW,CAAC,EACpC,QAAQ,IAAI,EAAAA,QAAM,OAAO,iDAAY,CAAC,EACtC,QAAQ,IAAI,EAAAA,QAAM,KAAK,SAAS6D,CAAW,EAAE,CAAC,EAC9C,QAAQ,IAAI,EAAA7D,QAAM,KAAK,6CAAyB,CAAC,EACjD,QAAQ,IACN,EAAAA,QAAM,KAAK,iFAAyC,CACtD,EACA,QAAQ,IAAI,EAAAA,QAAM,KAAK,8CAA0B,CAAC,CACpD,MAEEQ,EAAQ,KAAO,yCAAWqD,CAAW,OAGrC,EAAAtF,QAAG,UAAUwF,EAAY,CAAE,UAAW,EAAK,CAAC,EAG5CP,GAAkBO,CAAU,EAE5BvD,EAAQ,QAAQ,iBAAOqD,CAAW,4BAAQ,EAE1C,QAAQ,IAAI,EAAA7D,QAAM,MAAM,0DAAa,CAAC,EACtC,QAAQ,IAAI,EAAAA,QAAM,OAAO,iDAAY,CAAC,EACtC,QAAQ,IAAI,EAAAA,QAAM,KAAK,SAAS6D,CAAW,EAAE,CAAC,EAC9C,QAAQ,IACN,EAAA7D,QAAM,KAAK,mGAA4C,CACzD,EACA,QAAQ,IAAI,EAAAA,QAAM,KAAK,8CAA0B,CAAC,EAClD,QAAQ,IACN,EAAAA,QAAM,OAAO,oHAAkC,CACjD,CAEJ,OAASvB,EAAO,CACd+B,EAAQ,KACN,yCAAW/B,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CA3HeC,EAAAkF,GAAA,iBAgIf,SAASO,EACPC,EACAC,EACAC,EAA4B,CAAC,EACvB,CAED,EAAA/F,QAAG,WAAW8F,CAAI,GACrB,EAAA9F,QAAG,UAAU8F,EAAM,CAAE,UAAW,EAAK,CAAC,EAGxC,MAAME,EAAQ,EAAAhG,QAAG,YAAY6F,CAAG,EAEhC,UAAWpC,KAAQuC,EAAO,CAExB,GAAID,EAAgB,KAAME,GAAYxC,EAAK,SAASwC,CAAO,CAAC,EAC1D,SAGF,MAAMC,EAAU,EAAArG,QAAK,KAAKgG,EAAKpC,CAAI,EAC7B0C,EAAW,EAAAtG,QAAK,KAAKiG,EAAMrC,CAAI,EACxB,EAAAzD,QAAG,SAASkG,CAAO,EAEvB,YAAY,EACnBN,EAAcM,EAASC,EAAUJ,CAAe,EAEhD,EAAA/F,QAAG,aAAakG,EAASC,CAAQ,CAErC,CACF,CA5BShG,EAAAyF,EAAA,iBAiCT,eAAeQ,GAAcC,EAAaC,EAA+B,CACvE,MAAMrE,KAAU,EAAAC,SAAI,6BAAS,EAAE,MAAM,EAErC,GAAI,CACF,GAAI,CAAC,gBAAc,aAAa,EAAG,CACjCD,EAAQ,KAAK,4CAAS,EACtB,QAAQ,IAAI,EAAAR,QAAM,OAAO,gGAAkC,CAAC,EAC5D,MACF,CAEA,GAAK6E,EA8BH,OAAQD,EAAK,CACX,IAAK,cACH,gBAAc,kBAAkBC,CAAK,EACrCrE,EAAQ,QAAQ,6CAAeqE,CAAK,EAAE,EACtC,MACF,QACErE,EAAQ,KAAK,sBAAOoE,CAAG,+DAAa,EACpC,QAAQ,IAAI,EAAA5E,QAAM,OAAO,+DAAuB,CAAC,EACjD,MACJ,KAvCU,CAEVQ,EAAQ,KAAO,8BACf,MAAMsE,EAAS,gBAAc,UAAU,EAEvC,OAAQF,EAAK,CACX,IAAK,cACHpE,EAAQ,QAAQ,0BAAM,EACtB,QAAQ,IAAI,EAAAR,QAAM,MAAM,qBAAW8E,EAAO,WAAW,EAAE,CAAC,EACxD,MACF,IAAK,aACHtE,EAAQ,QAAQ,0BAAM,EACtB,QAAQ,IAAI,EAAAR,QAAM,MAAM,mBAAS,CAAC,EAClC,SAAW,CAAC+E,EAAMC,CAAY,IAAK,OAAO,QACxCF,EAAO,UACT,EACE,QAAQ,IACN,EAAA9E,QAAM,KACJ,KAAK+E,CAAI,KAAKC,EAAa,OAAO,IAAIA,EAAa,KAAK,KAAK,GAAG,CAAC,EACnE,CACF,EAEF,MACF,QACExE,EAAQ,KAAK,yCAAWoE,CAAG,EAAE,EAC7B,QAAQ,IAAI,EAAA5E,QAAM,OAAO,+DAAiC,CAAC,EAC3D,MACJ,CACF,CAaF,OAASvB,EAAO,CACd+B,EAAQ,KACN,yCAAW/B,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAxDeC,EAAAiG,GAAA,iBA6Df,SAASM,IAAiB,CACxB,QAAQ,IAAI,EAAAjF,QAAM,KAAK,KAAK,sCAAsC,CAAC,EACnE,QAAQ,IAAI,EACZ,QAAQ,IAAI,EAAAA,QAAM,OAAO,2BAAO,CAAC,EACjC,QAAQ,IAAI,+BAA+B,EAC3C,QAAQ,IAAI,EACZ,QAAQ,IAAI,EAAAA,QAAM,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,EACZ,QAAQ,IAAI,EAAAA,QAAM,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,IAAI,EAAAA,QAAM,OAAO,2BAAO,CAAC,EACjC,QAAQ,IAAI,mFAAqD,EACjE,QAAQ,IACN,oFACF,EACA,QAAQ,IACN,oGACF,EACA,QAAQ,IAAI,EACZ,QAAQ,IAAI,EAAAA,QAAM,OAAO,2BAAO,CAAC,EACjC,QAAQ,IAAI,0EAAiD,EAC7D,QAAQ,IAAI,0EAAsD,EAClE,QAAQ,IAAI,0EAAsD,EAClE,QAAQ,IAAI,EACZ,QAAQ,IAAI,EAAAA,QAAM,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,IAAI,EAAAA,QAAM,OAAO,+BAAW,CAAC,EACrC,QAAQ,IAAI,4EAA8C,EAC1D,QAAQ,IAAI,yFAA4C,EACxD,QAAQ,IAAI,yFAA4C,EACxD,QAAQ,IAAI,wEAAoD,EAChE,QAAQ,IAAI,wEAAoD,CAClE,CAjDStB,EAAAuG,GAAA,YAoDTnH,EACG,KAAK,SAAS,EACd,YAAY,iCAAiC,EAC7C,QAAQE,EAAW,EAAG,gBAAiB,sCAAQ,EAC/C,WAAW,aAAc,sCAAQ,EAGpCF,EACG,QAAQ,sBAAsB,EAC9B,YAAY,0BAAM,EAClB,OAAO,gCAAiC,8DAAY,EACpD,OAAO,MAAO+F,EAAaC,IAAY,CACtC,MAAMF,GAAcC,EAAaC,CAAO,CAC1C,CAAC,EAGHhG,EACG,QAAQ,MAAM,EACd,YAAY,4CAAS,EACrB,OAAO,SAAY,CAClB,MAAM+D,EAAW,CACnB,CAAC,EAGH/D,EACG,QAAQ,sBAAsB,EAC9B,YAAY,4CAAS,EACrB,OAAO,MAAO8G,EAAKC,IAAU,CAC5B,MAAMF,GAAcC,EAAKC,CAAK,CAChC,CAAC,EAGH/G,EACG,QAAQ,OAAO,EACf,YAAY,0BAAM,EAClB,OAAO,eAAgB,4CAAS,EAChC,OAAO,MAAOgG,GAAY,CACzB,MAAMxD,EAAawD,EAAQ,MAAM,CACnC,CAAC,EAGHhG,EACG,QAAQ,MAAM,EACd,YAAY,0BAAM,EAClB,OAAO,SAAY,CAClB,MAAMoD,EAAY,CACpB,CAAC,EAGHpD,EACG,QAAQ,QAAQ,EAChB,YAAY,sCAAQ,EACpB,OAAO,SAAY,CAClB,MAAMwD,EAAY,CACpB,CAAC,EAGHxD,EACG,QAAQ,QAAQ,EAChB,YAAY,oEAAa,EACzB,OAAO,SAAY,CAClB,MAAMyD,EAAc,CACtB,CAAC,EAGHzD,EACG,QAAQ,SAAS,EACjB,YAAY,0BAAM,EAClB,OAAO,eAAgB,4CAAS,EAChC,OAAO,MAAOgG,GAAY,CACzB,MAAMpC,EAAeoC,EAAQ,MAAM,CACrC,CAAC,EAGH,MAAMoB,EAAapH,EAAQ,QAAQ,KAAK,EAAE,YAAY,gDAAa,EAGnEoH,EACG,QAAQ,MAAM,EACd,YAAY,+BAAW,EACvB,OAAO,UAAW,oEAAa,EAC/B,OAAO,MAAOpB,GAAY,CACzB,QAAM,kBAAeA,CAAO,CAC9B,CAAC,EAGHoB,EACG,QAAQ,qBAAqB,EAC7B,YAAY,iDAAc,EAC1B,OAAO,MAAOC,GAAe,CAC5B,QAAM,mBAAgBA,CAAU,CAClC,CAAC,EAGHD,EACG,QAAQ,uCAAuC,EAC/C,YAAY,0EAAc,EAC1B,OAAO,MAAOC,EAAYC,EAAUC,IAAW,CAC1CA,IAAW,UAAYA,IAAW,YACpC,QAAQ,MAAM,EAAArF,QAAM,IAAI,wEAAgC,CAAC,EACzD,QAAQ,KAAK,CAAC,GAIhB,QAAM,kBAAemF,EAAYC,EADjBC,IAAW,QACuB,CACpD,CAAC,EAGHvH,EAAQ,OAAO,KAAM,sCAAQ,EAAE,OAAQgG,GAAY,CAC7CA,EAAQ,IACVnC,EAAiB,EACjB,QAAQ,KAAK,CAAC,EAElB,CAAC,EAGG,QAAQ,KAAK,QAAU,IACzBsD,GAAS,EACT,QAAQ,KAAK,CAAC,GAIhBnH,EAAQ,MAAM,QAAQ,IAAI","names":["import_meta","import_node_child_process","import_node_fs","import_node_os","import_node_path","import_node_url","import_chalk","import_commander","import_ora","import_configManager","import_mcpCommands","program","SERVICE_NAME","getVersion","currentDir","import_meta","__filename","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","chalk","endpoint","getServiceCommand","scriptDir","distDir","p","startService","daemon","spinner","ora","status","command","args","cwd","child","logStream","code","signal","stopService","attempts","maxAttempts","resolve","checkStatus","attachService","spawn","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","serverName","toolName","action"]}
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "xiaozhi-client",
3
+ "version": "1.1.0-next.5",
4
+ "description": "小智 AI 客户端 命令行工具",
5
+ "main": "dist/cli.cjs",
6
+ "files": [
7
+ "dist",
8
+ "docs",
9
+ "templates",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "registry": "https://registry.npmjs.org"
16
+ },
17
+ "bin": {
18
+ "xiaozhi": "./dist/cli.cjs",
19
+ "xiaozhi-client": "./dist/cli.cjs"
20
+ },
21
+ "scripts": {
22
+ "build": "tsup && node scripts/postbuild.js",
23
+ "dev": "tsup --watch && node scripts/postbuild.js",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "test:coverage": "vitest run --coverage",
27
+ "test:ui": "vitest --ui",
28
+ "format": "biome format --write .",
29
+ "lint": "biome lint --write .",
30
+ "type:check": "tsc --noEmit",
31
+ "check": "biome check .",
32
+ "check:write": "biome check --write .",
33
+ "release": "semantic-release"
34
+ },
35
+ "keywords": [
36
+ "xiaozhi",
37
+ "mcp",
38
+ "websocket",
39
+ "ai"
40
+ ],
41
+ "author": "shenjingnan(sjn.code@gmail.com)",
42
+ "license": "MIT",
43
+ "dependencies": {
44
+ "@modelcontextprotocol/sdk": "^1.12.1",
45
+ "chalk": "^5.4.1",
46
+ "commander": "^14.0.0",
47
+ "dotenv": "^16.3.1",
48
+ "ora": "^8.2.0",
49
+ "ws": "^8.14.2",
50
+ "zod": "^3.25.62"
51
+ },
52
+ "devDependencies": {
53
+ "@biomejs/biome": "1.9.4",
54
+ "@codecov/vite-plugin": "^1.9.1",
55
+ "@semantic-release/changelog": "^6.0.3",
56
+ "@semantic-release/commit-analyzer": "^13.0.1",
57
+ "@semantic-release/git": "^10.0.1",
58
+ "@semantic-release/github": "^11.0.3",
59
+ "@semantic-release/npm": "^12.0.1",
60
+ "@semantic-release/release-notes-generator": "^14.0.3",
61
+ "@types/node": "^24.0.1",
62
+ "@types/ws": "^8.18.1",
63
+ "@vitest/coverage-v8": "^3.2.3",
64
+ "codecov": "^3.8.3",
65
+ "conventional-changelog-conventionalcommits": "^9.0.0",
66
+ "esbuild": "^0.25.5",
67
+ "glob": "^11.0.3",
68
+ "semantic-release": "^24.2.5",
69
+ "semver": "^7.7.2",
70
+ "tsup": "^8.5.0",
71
+ "typescript": "^5.8.3",
72
+ "vitest": "^3.2.3"
73
+ }
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xiaozhi-client",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "小智 AI 客户端 命令行工具",
5
5
  "main": "dist/cli.cjs",
6
6
  "files": [
@@ -51,6 +51,7 @@
51
51
  },
52
52
  "devDependencies": {
53
53
  "@biomejs/biome": "1.9.4",
54
+ "@codecov/vite-plugin": "^1.9.1",
54
55
  "@semantic-release/changelog": "^6.0.3",
55
56
  "@semantic-release/commit-analyzer": "^13.0.1",
56
57
  "@semantic-release/git": "^10.0.1",
@@ -60,6 +61,8 @@
60
61
  "@types/node": "^24.0.1",
61
62
  "@types/ws": "^8.18.1",
62
63
  "@vitest/coverage-v8": "^3.2.3",
64
+ "codecov": "^3.8.3",
65
+ "conventional-changelog-conventionalcommits": "^9.0.0",
63
66
  "esbuild": "^0.25.5",
64
67
  "glob": "^11.0.3",
65
68
  "semantic-release": "^24.2.5",