xiaozhi-client 0.0.1-beta.2 → 0.0.1-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -346,6 +346,83 @@ async function initConfig() {
346
346
  }
347
347
  }
348
348
  __name(initConfig, "initConfig");
349
+ async function createProject(templateName, projectName) {
350
+ const spinner = (0, import_ora.default)("\u68C0\u67E5\u6A21\u677F...").start();
351
+ try {
352
+ const scriptDir = __dirname;
353
+ let templatesDir;
354
+ const possiblePaths = [
355
+ import_path.default.join(scriptDir, "..", "templates"),
356
+ // 开发环境
357
+ import_path.default.join(scriptDir, "templates"),
358
+ // 打包后的环境
359
+ import_path.default.join(scriptDir, "..", "..", "templates")
360
+ // npm 全局安装
361
+ ];
362
+ templatesDir = possiblePaths.find((p) => import_fs.default.existsSync(p)) || "";
363
+ if (!templatesDir || !import_fs.default.existsSync(templatesDir)) {
364
+ spinner.fail("\u627E\u4E0D\u5230 templates \u76EE\u5F55");
365
+ console.log(import_chalk.default.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u786E\u4FDD xiaozhi-client \u6B63\u786E\u5B89\u88C5"));
366
+ return;
367
+ }
368
+ const templatePath = import_path.default.join(templatesDir, templateName);
369
+ if (!import_fs.default.existsSync(templatePath)) {
370
+ spinner.fail(`\u6A21\u677F "${templateName}" \u4E0D\u5B58\u5728`);
371
+ try {
372
+ const availableTemplates = import_fs.default.readdirSync(templatesDir).filter((item) => import_fs.default.statSync(import_path.default.join(templatesDir, item)).isDirectory());
373
+ if (availableTemplates.length > 0) {
374
+ console.log(import_chalk.default.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));
375
+ availableTemplates.forEach((template) => {
376
+ console.log(import_chalk.default.gray(` - ${template}`));
377
+ });
378
+ } else {
379
+ console.log(import_chalk.default.yellow("\u6CA1\u6709\u53EF\u7528\u7684\u6A21\u677F"));
380
+ }
381
+ } catch (error) {
382
+ }
383
+ return;
384
+ }
385
+ const targetName = projectName || templateName;
386
+ const targetPath = import_path.default.join(process.cwd(), targetName);
387
+ if (import_fs.default.existsSync(targetPath)) {
388
+ spinner.fail(`\u76EE\u5F55 "${targetName}" \u5DF2\u5B58\u5728`);
389
+ console.log(import_chalk.default.yellow("\u{1F4A1} \u63D0\u793A: \u8BF7\u9009\u62E9\u4E0D\u540C\u7684\u9879\u76EE\u540D\u79F0\u6216\u5220\u9664\u73B0\u6709\u76EE\u5F55"));
390
+ return;
391
+ }
392
+ spinner.text = `\u521B\u5EFA\u9879\u76EE "${targetName}"...`;
393
+ copyDirectory(templatePath, targetPath, ["node_modules", ".pnpm-debug.log", "pnpm-lock.yaml"]);
394
+ spinner.succeed(`\u9879\u76EE "${targetName}" \u521B\u5EFA\u6210\u529F`);
395
+ console.log(import_chalk.default.green("\u2705 \u9879\u76EE\u521B\u5EFA\u5B8C\u6210!"));
396
+ console.log(import_chalk.default.yellow("\u{1F4DD} \u63A5\u4E0B\u6765\u7684\u6B65\u9AA4:"));
397
+ console.log(import_chalk.default.gray(` cd ${targetName}`));
398
+ console.log(import_chalk.default.gray(" pnpm install # \u5B89\u88C5\u4F9D\u8D56"));
399
+ console.log(import_chalk.default.gray(" # \u7F16\u8F91 xiaozhi.config.json \u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9"));
400
+ console.log(import_chalk.default.gray(" xiaozhi start # \u542F\u52A8\u670D\u52A1"));
401
+ } catch (error) {
402
+ spinner.fail(`\u521B\u5EFA\u9879\u76EE\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
403
+ }
404
+ }
405
+ __name(createProject, "createProject");
406
+ function copyDirectory(src, dest, excludePatterns = []) {
407
+ if (!import_fs.default.existsSync(dest)) {
408
+ import_fs.default.mkdirSync(dest, { recursive: true });
409
+ }
410
+ const items = import_fs.default.readdirSync(src);
411
+ for (const item of items) {
412
+ if (excludePatterns.some((pattern) => item.includes(pattern))) {
413
+ continue;
414
+ }
415
+ const srcPath = import_path.default.join(src, item);
416
+ const destPath = import_path.default.join(dest, item);
417
+ const stat = import_fs.default.statSync(srcPath);
418
+ if (stat.isDirectory()) {
419
+ copyDirectory(srcPath, destPath, excludePatterns);
420
+ } else {
421
+ import_fs.default.copyFileSync(srcPath, destPath);
422
+ }
423
+ }
424
+ }
425
+ __name(copyDirectory, "copyDirectory");
349
426
  async function configCommand(key, value) {
350
427
  const spinner = (0, import_ora.default)("\u66F4\u65B0\u914D\u7F6E...").start();
351
428
  try {
@@ -398,6 +475,7 @@ function showHelp() {
398
475
  console.log(" xiaozhi <command> [options]");
399
476
  console.log();
400
477
  console.log(import_chalk.default.yellow("\u547D\u4EE4:"));
478
+ console.log(" create <template> [name] \u4ECE\u6A21\u677F\u521B\u5EFA\u9879\u76EE");
401
479
  console.log(" init \u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6");
402
480
  console.log(" config <key> [value] \u67E5\u770B\u6216\u8BBE\u7F6E\u914D\u7F6E");
403
481
  console.log(" start [--daemon] \u542F\u52A8\u670D\u52A1 (--daemon \u540E\u53F0\u8FD0\u884C)");
@@ -411,6 +489,10 @@ function showHelp() {
411
489
  console.log(" -V \u663E\u793A\u8BE6\u7EC6\u4FE1\u606F");
412
490
  console.log(" -h, --help \u663E\u793A\u5E2E\u52A9\u4FE1\u606F");
413
491
  console.log();
492
+ console.log(import_chalk.default.yellow("\u9879\u76EE\u793A\u4F8B:"));
493
+ console.log(" xiaozhi create hello-world # \u521B\u5EFA hello-world \u9879\u76EE");
494
+ console.log(" xiaozhi create hello-world my-app # \u521B\u5EFA\u540D\u4E3A my-app \u7684\u9879\u76EE");
495
+ console.log();
414
496
  console.log(import_chalk.default.yellow("\u914D\u7F6E\u793A\u4F8B:"));
415
497
  console.log(" xiaozhi init # \u521D\u59CB\u5316\u914D\u7F6E");
416
498
  console.log(" xiaozhi config mcpEndpoint # \u67E5\u770B MCP \u7AEF\u70B9");
@@ -425,6 +507,9 @@ function showHelp() {
425
507
  }
426
508
  __name(showHelp, "showHelp");
427
509
  program.name("xiaozhi").description("MCP Calculator Service CLI Tool").version(VERSION, "-v, --version", "\u663E\u793A\u7248\u672C\u4FE1\u606F").helpOption("-h, --help", "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");
510
+ program.command("create <template> [name]").description("\u4ECE\u6A21\u677F\u521B\u5EFA\u9879\u76EE").action(async (template, name) => {
511
+ await createProject(template, name);
512
+ });
428
513
  program.command("init").description("\u521D\u59CB\u5316\u914D\u7F6E\u6587\u4EF6").action(async () => {
429
514
  await initConfig();
430
515
  });
package/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { spawn, ChildProcess } from 'child_process';\nimport fs from 'fs';\nimport path from 'path';\nimport os from 'os';\nimport { configManager } from './configManager.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 = parseInt(pidStr);\n\n if (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 = 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 } else if (hours > 0) {\n return `${hours}小时 ${minutes % 60}分钟`;\n } else if (minutes > 0) {\n return `${minutes}分钟 ${seconds % 60}秒`;\n } else {\n return `${seconds}秒`;\n }\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(chalk.yellow('💡 提示: 请运行 \"xiaozhi config mcpEndpoint <your-endpoint-url>\" 设置端点'));\n return false;\n }\n return true;\n } catch (error) {\n console.error(chalk.red(`❌ 错误: 配置文件无效 - ${error instanceof Error ? error.message : String(error)}`));\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 = possiblePaths.find(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: boolean = 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(chalk.red(`\\n服务异常退出 (代码: ${code}, 信号: ${signal})`));\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(`启动服务失败: ${error instanceof Error ? error.message : String(error)}`);\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\n } catch (error) {\n cleanupPidFile();\n spinner.fail(`停止服务失败: ${error instanceof Error ? error.message : String(error)}`);\n }\n } catch (error) {\n spinner.fail(`停止服务失败: ${error instanceof Error ? error.message : String(error)}`);\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(chalk.gray(` 运行模式: ${status.mode === 'daemon' ? '后台模式' : '前台模式'}`));\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(`检查状态失败: ${error instanceof Error ? error.message : String(error)}`);\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('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\n } catch (error) {\n spinner.fail(`连接失败: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * 重启服务\n */\nasync function restartService(daemon: boolean = 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 showVersion(): void {\n console.log(chalk.blue(`xiaozhi v${VERSION}`));\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(chalk.yellow('如需重新初始化,请先删除现有的 xiaozhi.config.json 文件'));\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(chalk.gray(` 配置文件路径: ${configManager.getConfigPath()}`));\n console.log(chalk.yellow('💡 或者使用命令设置:'));\n console.log(chalk.gray(' xiaozhi config mcpEndpoint <your-endpoint-url>'));\n } catch (error) {\n spinner.fail(`初始化配置失败: ${error instanceof Error ? error.message : String(error)}`);\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(config.mcpServers)) {\n console.log(chalk.gray(` ${name}: ${serverConfig.command} ${serverConfig.args.join(' ')}`));\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(`配置操作失败: ${error instanceof Error ? error.message : String(error)}`);\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(' 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();\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}\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// 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// -V 选项 (详细信息)\nprogram\n .option('-V', '显示详细信息')\n .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);"],"mappings":"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","names":["path","os","fs","chalk","ora","spawn"]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { spawn, ChildProcess } from 'child_process';\nimport fs from 'fs';\nimport path from 'path';\nimport os from 'os';\nimport { configManager } from './configManager.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 = parseInt(pidStr);\n\n if (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 = 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 } else if (hours > 0) {\n return `${hours}小时 ${minutes % 60}分钟`;\n } else if (minutes > 0) {\n return `${minutes}分钟 ${seconds % 60}秒`;\n } else {\n return `${seconds}秒`;\n }\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(chalk.yellow('💡 提示: 请运行 \"xiaozhi config mcpEndpoint <your-endpoint-url>\" 设置端点'));\n return false;\n }\n return true;\n } catch (error) {\n console.error(chalk.red(`❌ 错误: 配置文件无效 - ${error instanceof Error ? error.message : String(error)}`));\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 = possiblePaths.find(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: boolean = 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(chalk.red(`\\n服务异常退出 (代码: ${code}, 信号: ${signal})`));\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(`启动服务失败: ${error instanceof Error ? error.message : String(error)}`);\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\n } catch (error) {\n cleanupPidFile();\n spinner.fail(`停止服务失败: ${error instanceof Error ? error.message : String(error)}`);\n }\n } catch (error) {\n spinner.fail(`停止服务失败: ${error instanceof Error ? error.message : String(error)}`);\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(chalk.gray(` 运行模式: ${status.mode === 'daemon' ? '后台模式' : '前台模式'}`));\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(`检查状态失败: ${error instanceof Error ? error.message : String(error)}`);\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('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\n } catch (error) {\n spinner.fail(`连接失败: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * 重启服务\n */\nasync function restartService(daemon: boolean = 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 showVersion(): void {\n console.log(chalk.blue(`xiaozhi v${VERSION}`));\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(chalk.yellow('如需重新初始化,请先删除现有的 xiaozhi.config.json 文件'));\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(chalk.gray(` 配置文件路径: ${configManager.getConfigPath()}`));\n console.log(chalk.yellow('💡 或者使用命令设置:'));\n console.log(chalk.gray(' xiaozhi config mcpEndpoint <your-endpoint-url>'));\n } catch (error) {\n spinner.fail(`初始化配置失败: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * 创建项目命令\n */\nasync function createProject(templateName: string, projectName?: string): Promise<void> {\n const spinner = ora('检查模板...').start();\n\n try {\n // 获取当前脚本所在目录\n const scriptDir = __dirname;\n\n // 查找 templates 目录\n let templatesDir: string;\n const possiblePaths = [\n path.join(scriptDir, '..', 'templates'), // 开发环境\n path.join(scriptDir, 'templates'), // 打包后的环境\n path.join(scriptDir, '..', '..', 'templates'), // npm 全局安装\n ];\n\n templatesDir = possiblePaths.find(p => fs.existsSync(p)) || '';\n\n if (!templatesDir || !fs.existsSync(templatesDir)) {\n spinner.fail('找不到 templates 目录');\n console.log(chalk.yellow('💡 提示: 请确保 xiaozhi-client 正确安装'));\n return;\n }\n\n // 检查模板是否存在\n const templatePath = path.join(templatesDir, templateName);\n if (!fs.existsSync(templatePath)) {\n spinner.fail(`模板 \"${templateName}\" 不存在`);\n\n // 列出可用的模板\n try {\n const availableTemplates = fs.readdirSync(templatesDir)\n .filter(item => fs.statSync(path.join(templatesDir, item)).isDirectory());\n\n if (availableTemplates.length > 0) {\n console.log(chalk.yellow('可用的模板:'));\n availableTemplates.forEach(template => {\n console.log(chalk.gray(` - ${template}`));\n });\n } else {\n console.log(chalk.yellow('没有可用的模板'));\n }\n } catch (error) {\n // 忽略列出模板的错误\n }\n return;\n }\n\n // 确定项目名称和目标目录\n const targetName = projectName || templateName;\n const targetPath = path.join(process.cwd(), targetName);\n\n // 检查目标目录是否已存在\n if (fs.existsSync(targetPath)) {\n spinner.fail(`目录 \"${targetName}\" 已存在`);\n console.log(chalk.yellow('💡 提示: 请选择不同的项目名称或删除现有目录'));\n return;\n }\n\n spinner.text = `创建项目 \"${targetName}\"...`;\n\n // 复制模板到目标目录\n copyDirectory(templatePath, targetPath, ['node_modules', '.pnpm-debug.log', 'pnpm-lock.yaml']);\n\n spinner.succeed(`项目 \"${targetName}\" 创建成功`);\n\n console.log(chalk.green('✅ 项目创建完成!'));\n console.log(chalk.yellow('📝 接下来的步骤:'));\n console.log(chalk.gray(` cd ${targetName}`));\n console.log(chalk.gray(' pnpm install # 安装依赖'));\n console.log(chalk.gray(' # 编辑 xiaozhi.config.json 设置你的 MCP 端点'));\n console.log(chalk.gray(' xiaozhi start # 启动服务'));\n\n } catch (error) {\n spinner.fail(`创建项目失败: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/**\n * 递归复制目录\n */\nfunction copyDirectory(src: string, dest: string, excludePatterns: string[] = []): 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(config.mcpServers)) {\n console.log(chalk.gray(` ${name}: ${serverConfig.command} ${serverConfig.args.join(' ')}`));\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(`配置操作失败: ${error instanceof Error ? error.message : String(error)}`);\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 <template> [name] 从模板创建项目');\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();\n console.log(chalk.yellow('项目示例:'));\n console.log(' xiaozhi create hello-world # 创建 hello-world 项目');\n console.log(' xiaozhi create hello-world my-app # 创建名为 my-app 的项目');\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}\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 <template> [name]')\n .description('从模板创建项目')\n .action(async (template, name) => {\n await createProject(template, name);\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// -V 选项 (详细信息)\nprogram\n .option('-V', '显示详细信息')\n .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);"],"mappings":"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","names":["path","os","fs","chalk","ora","spawn"]}
package/docs/CLI.md ADDED
@@ -0,0 +1,189 @@
1
+ # Xiaozhi CLI 使用文档
2
+
3
+ `xiaozhi` 是小智AI客户端的命令行工具,提供配置管理和服务管理功能。
4
+
5
+ ## 概述
6
+
7
+ 小智的架构比较特别:它将您的个人电脑作为AI服务端,远端的小智服务器实际上是客户端。当您启动小智服务后,您的电脑就成为了AI的"大脑",为远端提供各种工具和能力。
8
+
9
+ ## 安装
10
+
11
+ 在项目根目录下运行:
12
+
13
+ ```bash
14
+ npm install
15
+ ```
16
+
17
+ ## 使用方法
18
+
19
+ ### 基本命令
20
+
21
+ ```bash
22
+ xiaozhi --help # 显示帮助信息
23
+ xiaozhi --version # 显示版本信息
24
+ ```
25
+
26
+ ### 服务管理
27
+
28
+ #### 启动服务
29
+
30
+ ```bash
31
+ xiaozhi start # 在前台启动服务
32
+ xiaozhi start -d # 在后台启动服务(守护进程模式)
33
+ xiaozhi start --daemon # 同上,完整参数形式
34
+ ```
35
+
36
+ **示例:**
37
+
38
+ ```bash
39
+ # 前台启动(按 Ctrl+C 停止)
40
+ xiaozhi start
41
+
42
+ # 后台启动
43
+ xiaozhi start -d
44
+ ```
45
+
46
+ #### 停止服务
47
+
48
+ ```bash
49
+ xiaozhi stop # 停止后台运行的服务
50
+ ```
51
+
52
+ #### 查看服务状态
53
+
54
+ ```bash
55
+ xiaozhi status # 查看服务运行状态和配置信息
56
+ ```
57
+
58
+ #### 重启服务
59
+
60
+ ```bash
61
+ xiaozhi restart # 重启服务(前台模式)
62
+ xiaozhi restart -d # 重启服务(后台模式)
63
+ ```
64
+
65
+ #### 前台/后台切换
66
+
67
+ ```bash
68
+ xiaozhi attach # 将后台服务转到前台运行
69
+ ```
70
+
71
+ **注意:** `attach` 命令会先停止后台服务,然后在前台重新启动。
72
+
73
+ ### 配置管理
74
+
75
+ #### 设置配置项
76
+
77
+ ```bash
78
+ xiaozhi set-config <key>=<value>
79
+ ```
80
+
81
+ **示例:**
82
+
83
+ ```bash
84
+ # 设置小智API端点
85
+ xiaozhi set-config xiaozhi.endpoint=wss://api.xiaozhi.me/mcp
86
+
87
+ # 设置嵌套配置
88
+ xiaozhi set-config mcpServers.myserver.command=node
89
+
90
+ # 包含特殊字符的值需要用引号包围
91
+ xiaozhi set-config "xiaozhi.endpoint=wss://api.xiaozhi.me/mcp/?token=abc123"
92
+ ```
93
+
94
+ #### 获取配置项
95
+
96
+ ```bash
97
+ xiaozhi get-config [key]
98
+ ```
99
+
100
+ **示例:**
101
+
102
+ ```bash
103
+ # 获取特定配置项
104
+ xiaozhi get-config xiaozhi.endpoint
105
+
106
+ # 获取所有配置
107
+ xiaozhi get-config
108
+ ```
109
+
110
+ ## 配置文件
111
+
112
+ 配置文件位于 `.xiaozhi/settings.json`,支持嵌套结构:
113
+
114
+ ```json
115
+ {
116
+ "xiaozhi": {
117
+ "endpoint": "wss://api.xiaozhi.me/mcp/?token=..."
118
+ },
119
+ "mcpServers": {
120
+ "amap-maps": {
121
+ "command": "npx",
122
+ "args": ["-y", "@amap/amap-maps-mcp-server"],
123
+ "env": {
124
+ "AMAP_MAPS_API_KEY": "your-api-key"
125
+ }
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ ## 支持的配置键
132
+
133
+ - `xiaozhi.endpoint` - 小智API WebSocket端点地址
134
+ - `mcpServers.*` - MCP服务器配置
135
+
136
+ ## 服务管理详解
137
+
138
+ ### 前台 vs 后台模式
139
+
140
+ - **前台模式**: 服务在当前终端窗口运行,可以看到实时日志,按 `Ctrl+C` 停止
141
+ - **后台模式**: 服务在后台运行,不占用终端,需要使用 `xiaozhi stop` 停止
142
+
143
+ ### 进程管理
144
+
145
+ 小智使用 PID 文件(`.xiaozhi/xiaozhi.pid`)来跟踪后台进程:
146
+
147
+ - 启动服务时会检查是否已有服务在运行,防止重复启动
148
+ - 停止服务时会清理 PID 文件
149
+ - 如果进程异常退出,下次启动时会自动清理无效的 PID 文件
150
+
151
+ ### 常见使用场景
152
+
153
+ ```bash
154
+ # 开发调试:前台启动,查看实时日志
155
+ xiaozhi start
156
+
157
+ # 生产使用:后台启动,持续运行
158
+ xiaozhi start -d
159
+
160
+ # 检查服务状态
161
+ xiaozhi status
162
+
163
+ # 查看后台日志(需要转到前台)
164
+ xiaozhi attach
165
+
166
+ # 重启服务(比如更新配置后)
167
+ xiaozhi restart -d
168
+ ```
169
+
170
+ ## 注意事项
171
+
172
+ 1. **引号使用**: 当配置值包含特殊字符(如 `?`, `&`, `=` 等)时,需要用引号包围整个参数
173
+ 2. **嵌套键**: 使用点号分隔嵌套键,如 `xiaozhi.endpoint`
174
+ 3. **自动保存**: 配置更改会立即保存到文件
175
+ 4. **错误处理**: 命令会提供清晰的错误信息和使用示例
176
+ 5. **服务检查**: 启动前会检查必要的配置项(endpoint 和 mcpServers)
177
+ 6. **进程安全**: 防止重复启动,确保同时只有一个服务实例运行
178
+
179
+ ## 开发
180
+
181
+ 如果你想在开发环境中直接运行CLI工具:
182
+
183
+ ```bash
184
+ # 直接运行
185
+ node bin/xiaozhi --help
186
+
187
+ # 或者使用src中的文件
188
+ node src/cli.js --help
189
+ ```
@@ -0,0 +1,122 @@
1
+ # SettingManager 使用文档
2
+
3
+ SettingManager 是一个单例配置管理器,用于管理 `.xiaozhi/settings.json` 配置文件。
4
+
5
+ ## 特性
6
+
7
+ - **单例模式**: 确保全局只有一个配置管理实例
8
+ - **只读访问**: 外部只能通过方法获取配置,不能直接修改
9
+ - **方法更新**: 必须通过提供的方法来更新配置
10
+ - **自动保存**: 配置更新后自动保存到文件
11
+ - **嵌套键支持**: 支持使用点号分隔的嵌套键,如 `xiaozhi.endpoint`
12
+
13
+ ## 基本用法
14
+
15
+ ### 获取实例
16
+
17
+ ```javascript
18
+ import SettingManager from './src/settingManager.js';
19
+
20
+ const settings = SettingManager.getInstance();
21
+ ```
22
+
23
+ ### 读取配置
24
+
25
+ ```javascript
26
+ // 读取简单配置
27
+ const endpoint = settings.get('xiaozhi.endpoint');
28
+
29
+ // 读取嵌套配置
30
+ const command = settings.get('mcpServers.amap-maps.command');
31
+
32
+ // 获取所有配置(只读副本)
33
+ const allSettings = settings.getAll();
34
+ ```
35
+
36
+ ### 更新配置
37
+
38
+ ```javascript
39
+ // 更新现有配置
40
+ settings.set('xiaozhi.endpoint', 'wss://new-endpoint.com');
41
+
42
+ // 添加新配置
43
+ settings.set('myApp.newSetting', 'value');
44
+
45
+ // 创建嵌套配置
46
+ settings.set('myApp.nested.deep.setting', 'deep value');
47
+ ```
48
+
49
+ ### 检查配置是否存在
50
+
51
+ ```javascript
52
+ if (settings.has('xiaozhi.endpoint')) {
53
+ console.log('Endpoint is configured');
54
+ }
55
+ ```
56
+
57
+ ### 删除配置
58
+
59
+ ```javascript
60
+ // 删除配置项
61
+ settings.delete('myApp.temporarySetting');
62
+
63
+ // 删除嵌套配置
64
+ settings.delete('myApp.nested.deep.setting');
65
+ ```
66
+
67
+ ### 重新加载配置
68
+
69
+ ```javascript
70
+ // 从文件重新加载配置(如果文件被外部修改)
71
+ settings.reload();
72
+ ```
73
+
74
+ ## 配置文件结构
75
+
76
+ 配置文件位于 `.xiaozhi/settings.json`,典型结构如下:
77
+
78
+ ```json
79
+ {
80
+ "xiaozhi": {
81
+ "endpoint": "wss://api.xiaozhi.me/mcp/?token=..."
82
+ },
83
+ "mcpServers": {
84
+ "amap-maps": {
85
+ "command": "npx",
86
+ "args": ["-y", "@amap/amap-maps-mcp-server"],
87
+ "env": {
88
+ "AMAP_MAPS_API_KEY": "your-api-key"
89
+ }
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ## 在 mcpWebSocketClient.js 中的使用
96
+
97
+ 原来的代码使用环境变量:
98
+
99
+ ```javascript
100
+ const endpointUrl = process.env.MCP_ENDPOINT;
101
+ ```
102
+
103
+ 现在使用 SettingManager:
104
+
105
+ ```javascript
106
+ import SettingManager from './settingManager.js';
107
+
108
+ const settingManager = SettingManager.getInstance();
109
+ const endpointUrl = settingManager.get('xiaozhi.endpoint');
110
+ ```
111
+
112
+ ## 注意事项
113
+
114
+ 1. **单例模式**: 无论在哪里调用 `SettingManager.getInstance()`,都会返回同一个实例
115
+ 2. **自动保存**: 调用 `set()` 或 `delete()` 方法后,配置会立即保存到文件
116
+ 3. **只读访问**: `get()` 和 `getAll()` 返回的是配置的副本,直接修改不会影响实际配置
117
+ 4. **错误处理**: 如果配置文件损坏或无法访问,会抛出相应的错误
118
+ 5. **目录创建**: 如果 `.xiaozhi` 目录不存在,会自动创建
119
+
120
+ ## 示例
121
+
122
+ 查看 `examples/setting_manager_usage.js` 文件获取完整的使用示例。
Binary file
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "xiaozhi-client",
3
- "version": "0.0.1-beta.2",
3
+ "version": "0.0.1-beta.4",
4
4
  "description": "小智 AI 客户端 命令行工具",
5
5
  "main": "dist/cli.cjs",
6
6
  "files": [
7
7
  "dist",
8
+ "docs",
9
+ "templates",
8
10
  "README.md",
9
11
  "LICENSE"
10
12
  ],
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "simple",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "@modelcontextprotocol/sdk": "^1.12.1",
14
+ "zod": "^3.25.64"
15
+ }
16
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "mcpEndpoint": "<请填写你的接入点地址(获取地址在 xiaozhi.me)>",
3
+ "mcpServers": {
4
+ "calculator": {
5
+ "command": "node",
6
+ "args": ["./mcpServers/calculator.js"]
7
+ },
8
+ "datetime": {
9
+ "command": "node",
10
+ "args": ["./mcpServers/datetime.js"]
11
+ }
12
+ }
13
+ }
@@ -1,13 +0,0 @@
1
- {
2
- "mcpEndpoint": "wss://api.xiaozhi.me/mcp/?token=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjMwMjcyMCwiYWdlbnRJZCI6MzAwNzQ1LCJlbmRwb2ludElkIjoiYWdlbnRfMzAwNzQ1IiwicHVycG9zZSI6Im1jcC1lbmRwb2ludCIsImlhdCI6MTc0OTY5ODk5OX0.b-bwXaBG2ozprDruAFbTzZfm4rloGj75I9qHzmyodWTPgz0OHKXguCwIS62ukYLv0VqqhvsD85YZJqDV7r3Fug",
3
- "mcpServers": {
4
- "calculator": {
5
- "command": "node",
6
- "args": ["./mcpServers/calculator.js"]
7
- },
8
- "datetime": {
9
- "command": "node",
10
- "args": ["./mcpServers/datetime.js"]
11
- }
12
- }
13
- }