@ai-config-plaza/acp-cli 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 +6 -6
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,13 +20,13 @@ ACP CLI 是一个专为简化 AI 编程工具配置而设计的命令行工具
|
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
# 使用 npm
|
|
23
|
-
npm install -g acp-cli
|
|
23
|
+
npm install -g @ai-config-plaza/acp-cli
|
|
24
24
|
|
|
25
25
|
# 使用 pnpm
|
|
26
|
-
pnpm add -g acp-cli
|
|
26
|
+
pnpm add -g @ai-config-plaza/acp-cli
|
|
27
27
|
|
|
28
28
|
# 使用 yarn
|
|
29
|
-
yarn global add acp-cli
|
|
29
|
+
yarn global add @ai-config-plaza/acp-cli
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
### 本地开发
|
|
@@ -94,9 +94,9 @@ acp apply --ide cursor --dir ~/projects/my-app
|
|
|
94
94
|
| IDE | Prompts 路径 | Agents 文件 | MCP 配置 |
|
|
95
95
|
| ----------- | -------------------- | ------------- | ----------------------- |
|
|
96
96
|
| VS Code | `.github/prompts/` | `AGENTS.md` | `.vscode/mcp.json` |
|
|
97
|
-
| Cursor | `.cursor/
|
|
98
|
-
| Codex |
|
|
99
|
-
| Claude Code | `.claude/
|
|
97
|
+
| Cursor | `.cursor/commands/` | `AGENTS.md` | `.cursor/mcp.json` |
|
|
98
|
+
| Codex | `~/.codex/prompts/` | `AGENTS.md` | `.codex/config.toml` |
|
|
99
|
+
| Claude Code | `.claude/commands/` | `AGENTS.md` | `.mcp.json` |
|
|
100
100
|
|
|
101
101
|
### 文件格式
|
|
102
102
|
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import path from "path";
|
|
|
15
15
|
import os from "os";
|
|
16
16
|
var TOKEN_ENV_KEY = "ACP_CLI_TOKEN";
|
|
17
17
|
var BASE_URL_ENV_KEY = "ACP_CLI_BASE_URL";
|
|
18
|
-
var DEFAULT_BASE_URL = "https://
|
|
18
|
+
var DEFAULT_BASE_URL = "https://api.ai-config-plaza.com";
|
|
19
19
|
var CONFIG_DIR = path.join(os.homedir(), ".acp");
|
|
20
20
|
var TOKEN_FILE = path.join(CONFIG_DIR, "token");
|
|
21
21
|
var BASE_URL_FILE = path.join(CONFIG_DIR, "base-url");
|
|
@@ -387,17 +387,17 @@ var IDE_PATH_MAPPINGS = {
|
|
|
387
387
|
mcp: ".vscode/mcp.json"
|
|
388
388
|
},
|
|
389
389
|
cursor: {
|
|
390
|
-
prompts: ".cursor/
|
|
390
|
+
prompts: ".cursor/commands",
|
|
391
391
|
agents: "AGENTS.md",
|
|
392
392
|
mcp: ".cursor/mcp.json"
|
|
393
393
|
},
|
|
394
394
|
codex: {
|
|
395
|
-
prompts: "
|
|
395
|
+
prompts: "~/.codex/prompts",
|
|
396
396
|
agents: "AGENTS.md",
|
|
397
397
|
mcp: ".codex/config.toml"
|
|
398
398
|
},
|
|
399
399
|
"claude-code": {
|
|
400
|
-
prompts: ".claude/
|
|
400
|
+
prompts: ".claude/commands",
|
|
401
401
|
agents: "AGENTS.md",
|
|
402
402
|
mcp: ".mcp.json"
|
|
403
403
|
}
|
|
@@ -718,10 +718,11 @@ async function selectIde() {
|
|
|
718
718
|
}
|
|
719
719
|
|
|
720
720
|
// src/index.ts
|
|
721
|
+
var version = true ? "1.0.3" : "0.0.0-dev";
|
|
721
722
|
var program = new Command3();
|
|
722
723
|
program.name("acp").description(
|
|
723
724
|
chalk5.gray("AI-Config-Plaza CLI - \u7EDF\u4E00 AI \u7F16\u7A0B\u5DE5\u5177\u914D\u7F6E\u7BA1\u7406")
|
|
724
|
-
).version(
|
|
725
|
+
).version(version, "-v, --version", "\u663E\u793A\u7248\u672C\u53F7").helpOption("-h, --help", "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");
|
|
725
726
|
program.addCommand(loginCommand);
|
|
726
727
|
program.addCommand(applyCommand);
|
|
727
728
|
program.on("--help", () => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/config/token.ts","../src/utils/logger.ts","../src/commands/apply.ts","../src/api/client.ts","../src/utils/pagination.ts","../src/apply/writer.ts","../src/utils/ide-mapper.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport { loginCommand } from './commands/login.js'\r\nimport { applyCommand } from './commands/apply.js'\r\nimport { handleError } from './utils/logger.js'\r\n\r\n/**\r\n * ACP CLI 主入口\r\n */\r\n\r\nconst program = new Command()\r\n\r\nprogram\r\n .name('acp')\r\n .description(\r\n chalk.gray('AI-Config-Plaza CLI - 统一 AI 编程工具配置管理')\r\n )\r\n .version('1.0.0', '-v, --version', '显示版本号')\r\n .helpOption('-h, --help', '显示帮助信息')\r\n\r\n// 注册命令\r\nprogram.addCommand(loginCommand)\r\nprogram.addCommand(applyCommand)\r\n\r\n// 自定义帮助显示\r\nprogram.on('--help', () => {\r\n console.log(chalk.bold('\\n示例:\\n'))\r\n console.log(chalk.gray(' $ acp login'))\r\n console.log(chalk.gray(' $ acp apply'))\r\n console.log(chalk.gray(' $ acp apply --ide vscode --dir ./my-project'))\r\n console.log()\r\n})\r\n\r\n// 解析命令\r\ntry {\r\n await program.parseAsync(process.argv)\r\n} catch (error) {\r\n handleError(error)\r\n process.exit(1)\r\n}\r\n","import { Command } from 'commander'\r\nimport inquirer from 'inquirer'\r\nimport chalk from 'chalk'\r\nimport { saveToken, getToken, initDefaultConfig } from '../config/token.js'\r\nimport { logger } from '../utils/logger.js'\r\n\r\n/**\r\n * acp login 命令\r\n * 提示用户输入 CLI Token 并保存\r\n */\r\n\r\nexport const loginCommand = new Command('login')\r\n .description('登录 ACP CLI,保存访问令牌')\r\n .action(async () => {\r\n try {\r\n logger.title('🔐 ACP CLI 登录')\r\n\r\n // 初始化默认配置(首次使用时)\r\n await initDefaultConfig()\r\n\r\n // 检查是否已有 token\r\n const existingToken = await getToken()\r\n if (existingToken) {\r\n const { overwrite } = await inquirer.prompt([\r\n {\r\n type: 'confirm',\r\n name: 'overwrite',\r\n message: '检测到已登录,是否重新登录?',\r\n default: false\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.info('已取消登录')\r\n return\r\n }\r\n }\r\n\r\n // 提示输入 token\r\n const { token } = await inquirer.prompt([\r\n {\r\n type: 'password',\r\n name: 'token',\r\n message: '请输入 CLI Token:',\r\n validate: (input: string) => {\r\n if (!input.trim()) {\r\n return 'Token 不能为空'\r\n }\r\n if (input.trim().length < 10) {\r\n return 'Token 格式不正确(至少 10 个字符)'\r\n }\r\n return true\r\n },\r\n mask: '*'\r\n }\r\n ])\r\n\r\n // 保存 token\r\n await saveToken(token)\r\n\r\n logger.success('登录成功!Token 已保存到 ~/.acp/token')\r\n console.log(chalk.gray('\\n提示: 现在可以使用 acp apply 命令拉取配置\\n'))\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n logger.error(`登录失败: ${error.message}`)\r\n }\r\n process.exit(1)\r\n }\r\n })\r\n","import fs from 'fs-extra'\r\nimport path from 'path'\r\nimport os from 'os'\r\n\r\n/**\r\n * Token 和 BASE_URL 配置管理\r\n * 优先级: 环境变量 > ~/.acp/ 配置文件\r\n */\r\n\r\nconst TOKEN_ENV_KEY = 'ACP_CLI_TOKEN'\r\nconst BASE_URL_ENV_KEY = 'ACP_CLI_BASE_URL'\r\nconst DEFAULT_BASE_URL = 'https://acp-hkbpdeenf8dudmfw.eastasia-01.azurewebsites.net'\r\n\r\nconst CONFIG_DIR = path.join(os.homedir(), '.acp')\r\nconst TOKEN_FILE = path.join(CONFIG_DIR, 'token')\r\nconst BASE_URL_FILE = path.join(CONFIG_DIR, 'base-url')\r\n\r\n/**\r\n * 读取 CLI Token\r\n */\r\nexport async function getToken(): Promise<string | null> {\r\n // 1. 优先读取环境变量\r\n const envToken = process.env[TOKEN_ENV_KEY]\r\n if (envToken?.trim()) {\r\n return envToken.trim()\r\n }\r\n\r\n // 2. 读取本地配置文件\r\n try {\r\n if (await fs.pathExists(TOKEN_FILE)) {\r\n const token = await fs.readFile(TOKEN_FILE, 'utf-8')\r\n return token.trim() || null\r\n }\r\n } catch (error) {\r\n // 读取失败返回 null\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * 保存 CLI Token 到本地配置文件\r\n */\r\nexport async function saveToken(token: string): Promise<void> {\r\n if (!token?.trim()) {\r\n throw new Error('Token 不能为空')\r\n }\r\n\r\n // 确保配置目录存在\r\n await fs.ensureDir(CONFIG_DIR)\r\n\r\n // 写入 token 文件\r\n await fs.writeFile(TOKEN_FILE, token.trim(), 'utf-8')\r\n}\r\n\r\n/**\r\n * 删除本地 Token\r\n */\r\nexport async function removeToken(): Promise<void> {\r\n if (await fs.pathExists(TOKEN_FILE)) {\r\n await fs.remove(TOKEN_FILE)\r\n }\r\n}\r\n\r\n/**\r\n * 检查是否已登录\r\n */\r\nexport async function isLoggedIn(): Promise<boolean> {\r\n const token = await getToken()\r\n return token !== null && token.length > 0\r\n}\r\n\r\n/**\r\n * 读取 BASE_URL\r\n */\r\nexport async function getBaseUrl(): Promise<string> {\r\n // 1. 优先读取环境变量\r\n const envBaseUrl = process.env[BASE_URL_ENV_KEY]\r\n if (envBaseUrl?.trim()) {\r\n return envBaseUrl.trim()\r\n }\r\n\r\n // 2. 读取本地配置文件\r\n try {\r\n if (await fs.pathExists(BASE_URL_FILE)) {\r\n const baseUrl = await fs.readFile(BASE_URL_FILE, 'utf-8')\r\n if (baseUrl.trim()) {\r\n return baseUrl.trim()\r\n }\r\n }\r\n } catch (error) {\r\n // 读取失败,使用默认值\r\n }\r\n\r\n // 3. 返回默认值\r\n return DEFAULT_BASE_URL\r\n}\r\n\r\n/**\r\n * 保存 BASE_URL 到本地配置文件\r\n */\r\nexport async function saveBaseUrl(baseUrl: string): Promise<void> {\r\n if (!baseUrl?.trim()) {\r\n throw new Error('BASE_URL 不能为空')\r\n }\r\n\r\n // 验证 URL 格式\r\n try {\r\n new URL(baseUrl.trim())\r\n } catch {\r\n throw new Error('BASE_URL 格式不正确,请输入有效的 URL')\r\n }\r\n\r\n // 确保配置目录存在\r\n await fs.ensureDir(CONFIG_DIR)\r\n\r\n // 写入 base-url 文件\r\n await fs.writeFile(BASE_URL_FILE, baseUrl.trim(), 'utf-8')\r\n}\r\n\r\n/**\r\n * 删除本地 BASE_URL\r\n */\r\nexport async function removeBaseUrl(): Promise<void> {\r\n if (await fs.pathExists(BASE_URL_FILE)) {\r\n await fs.remove(BASE_URL_FILE)\r\n }\r\n}\r\n\r\n/**\r\n * 初始化默认配置(首次使用时)\r\n */\r\nexport async function initDefaultConfig(): Promise<void> {\r\n await fs.ensureDir(CONFIG_DIR)\r\n\r\n // 如果 BASE_URL 不存在,初始化默认值\r\n if (!(await fs.pathExists(BASE_URL_FILE))) {\r\n await saveBaseUrl(DEFAULT_BASE_URL)\r\n }\r\n}\r\n","import chalk from 'chalk'\r\n\r\n/**\r\n * 日志工具 - 提供统一的终端输出格式\r\n */\r\n\r\n// 使用 Unicode 符号代替 figures\r\nconst symbols = {\r\n info: 'ℹ',\r\n tick: '✓',\r\n warning: '⚠',\r\n cross: '✖',\r\n arrowRight: '→'\r\n}\r\n\r\nexport const logger = {\r\n /**\r\n * 普通信息\r\n */\r\n info: (message: string) => {\r\n console.log(chalk.blue(symbols.info) + ' ' + message)\r\n },\r\n\r\n /**\r\n * 成功信息\r\n */\r\n success: (message: string) => {\r\n console.log(chalk.green(symbols.tick) + ' ' + chalk.green(message))\r\n },\r\n\r\n /**\r\n * 警告信息\r\n */\r\n warning: (message: string) => {\r\n console.log(chalk.yellow(symbols.warning) + ' ' + chalk.yellow(message))\r\n },\r\n\r\n /**\r\n * 错误信息\r\n */\r\n error: (message: string) => {\r\n console.error(chalk.red(symbols.cross) + ' ' + chalk.red(message))\r\n },\r\n\r\n /**\r\n * 步骤信息\r\n */\r\n step: (message: string) => {\r\n console.log(chalk.cyan(symbols.arrowRight) + ' ' + chalk.gray(message))\r\n },\r\n\r\n /**\r\n * 标题\r\n */\r\n title: (message: string) => {\r\n console.log('\\n' + chalk.bold.underline(message) + '\\n')\r\n },\r\n\r\n /**\r\n * 普通文本(无图标)\r\n */\r\n log: (message: string) => {\r\n console.log(message)\r\n }\r\n}\r\n\r\n/**\r\n * 自定义 CLI 错误类\r\n */\r\nexport class CLIError extends Error {\r\n constructor(\r\n message: string,\r\n public code?: string,\r\n public suggestions?: string[]\r\n ) {\r\n super(message)\r\n this.name = 'CLIError'\r\n }\r\n}\r\n\r\n/**\r\n * 错误处理函数\r\n */\r\nexport function handleError(error: unknown): void {\r\n console.error()\r\n\r\n if (error instanceof CLIError) {\r\n logger.error(error.message)\r\n\r\n if (error.code) {\r\n console.log(chalk.gray(`错误代码: ${error.code}`))\r\n }\r\n\r\n if (error.suggestions?.length) {\r\n console.log(chalk.yellow.bold('\\n💡 建议:\\n'))\r\n error.suggestions.forEach((suggestion, index) => {\r\n console.log(chalk.gray(` ${index + 1}. ${suggestion}`))\r\n })\r\n }\r\n } else if (error instanceof Error) {\r\n logger.error(error.message)\r\n\r\n if (process.env.DEBUG) {\r\n console.log(chalk.gray('\\n' + error.stack))\r\n }\r\n } else {\r\n logger.error('未知错误')\r\n }\r\n\r\n console.log(\r\n chalk.gray('\\n需要帮助? 访问: ') +\r\n chalk.blue.underline('https://github.com/AIConfigPlaza/acp-cli')\r\n )\r\n console.log()\r\n}\r\n","import { Command } from 'commander'\r\nimport inquirer from 'inquirer'\r\nimport chalk from 'chalk'\r\nimport ora from 'ora'\r\nimport { apiClient } from '../api/client.js'\r\nimport { logger, CLIError } from '../utils/logger.js'\r\nimport { isLoggedIn } from '../config/token.js'\r\nimport { type AiIdeType } from '../utils/ide-mapper.js'\r\nimport { searchByName, paginate } from '../utils/pagination.js'\r\nimport { applySolution } from '../apply/writer.js'\r\nimport type { Solution } from '../types/index.js'\r\n\r\n/**\r\n * acp apply 命令\r\n * 拉取并应用配置到本地项目\r\n */\r\n\r\ntype ResourceType = 'solution' | 'agent' | 'prompt' | 'mcp'\r\n\r\nexport const applyCommand = new Command('apply')\r\n .description('拉取并应用配置到本地项目')\r\n .option('-t, --type <type>', '资源类型 (solution|agent|prompt|mcp)', 'solution')\r\n .option('-i, --ide <ide>', 'AI IDE 类型 (vscode|cursor|codex|claude-code)')\r\n .option('-d, --dir <path>', '目标目录', process.cwd())\r\n .action(async (options) => {\r\n try {\r\n // 检查登录状态\r\n if (!(await isLoggedIn())) {\r\n throw new CLIError(\r\n '未登录,请先执行 acp login',\r\n 'NOT_LOGGED_IN',\r\n ['运行 acp login 命令登录']\r\n )\r\n }\r\n\r\n logger.title('🚀 ACP 配置应用')\r\n\r\n // 1. 选择资源类型\r\n const resourceType = await selectResourceType(options.type)\r\n\r\n // 2. 根据类型拉取并选择资源\r\n let selectedSolution: Solution | null = null\r\n\r\n if (resourceType === 'solution') {\r\n selectedSolution = await fetchAndSelectSolution()\r\n } else {\r\n throw new CLIError('暂不支持独立应用 agent/prompt/mcp,请使用 solution 类型')\r\n }\r\n\r\n if (!selectedSolution) {\r\n logger.info('未选择任何配置')\r\n return\r\n }\r\n\r\n // 3. 选择 IDE 类型\r\n const ide = options.ide || (await selectIde())\r\n\r\n // 4. 应用配置\r\n await applySolution(selectedSolution, {\r\n ide: ide as AiIdeType,\r\n targetDir: options.dir\r\n })\r\n\r\n console.log(chalk.gray(`\\n配置已应用到: ${chalk.cyan(options.dir)}\\n`))\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n logger.error(error.message)\r\n }\r\n process.exit(1)\r\n }\r\n })\r\n\r\n/**\r\n * 选择资源类型\r\n */\r\nasync function selectResourceType(defaultType?: string): Promise<ResourceType> {\r\n if (defaultType && ['solution', 'agent', 'prompt', 'mcp'].includes(defaultType)) {\r\n return defaultType as ResourceType\r\n }\r\n\r\n const { type } = await inquirer.prompt([\r\n {\r\n type: 'list',\r\n name: 'type',\r\n message: '请选择资源类型:',\r\n choices: [\r\n { name: chalk.cyan('解决方案 (Solution)'), value: 'solution' },\r\n { name: chalk.gray('Agent 配置 (暂不支持)'), value: 'agent', disabled: true },\r\n { name: chalk.gray('Prompt (暂不支持)'), value: 'prompt', disabled: true },\r\n { name: chalk.gray('MCP 配置 (暂不支持)'), value: 'mcp', disabled: true }\r\n ],\r\n default: 'solution'\r\n }\r\n ])\r\n\r\n return type\r\n}\r\n\r\n/**\r\n * 拉取并选择解决方案\r\n */\r\nasync function fetchAndSelectSolution(): Promise<Solution | null> {\r\n const spinner = ora('正在获取解决方案列表...').start()\r\n\r\n try {\r\n // 1. 拉取解决方案列表\r\n const response = await apiClient.getSolutions()\r\n spinner.stop()\r\n\r\n if (!response.data || response.data.length === 0) {\r\n logger.warning('暂无可用的解决方案')\r\n return null\r\n }\r\n\r\n logger.success(`获取到 ${response.data.length} 个解决方案`)\r\n\r\n // 2. 搜索过滤\r\n const { searchQuery } = await inquirer.prompt([\r\n {\r\n type: 'input',\r\n name: 'searchQuery',\r\n message: '搜索解决方案 (按名称搜索,留空显示全部):',\r\n default: ''\r\n }\r\n ])\r\n\r\n let filteredSolutions = searchByName(response.data, searchQuery)\r\n\r\n if (filteredSolutions.length === 0) {\r\n logger.warning('未找到匹配的解决方案')\r\n return null\r\n }\r\n\r\n // 3. 分页显示\r\n const PAGE_SIZE = 20\r\n let currentPage = 1\r\n let selectedSolution: Solution | null = null\r\n\r\n while (!selectedSolution) {\r\n const paginatedResult = paginate(filteredSolutions, {\r\n page: currentPage,\r\n pageSize: PAGE_SIZE\r\n })\r\n\r\n // 构建选择列表\r\n const choices = paginatedResult.items.map((solution) => ({\r\n name: `${chalk.cyan(solution.name)} - ${chalk.gray(solution.description)}`,\r\n value: solution.id,\r\n short: solution.name\r\n }))\r\n\r\n // 添加分页控制选项\r\n if (paginatedResult.hasNext) {\r\n choices.push({\r\n name: chalk.yellow('>>> 下一页'),\r\n value: '__NEXT_PAGE__',\r\n short: '下一页'\r\n })\r\n }\r\n\r\n if (paginatedResult.hasPrev) {\r\n choices.unshift({\r\n name: chalk.yellow('<<< 上一页'),\r\n value: '__PREV_PAGE__',\r\n short: '上一页'\r\n })\r\n }\r\n\r\n choices.push({\r\n name: chalk.red('取消'),\r\n value: '__CANCEL__',\r\n short: '取消'\r\n })\r\n\r\n const { selected } = await inquirer.prompt([\r\n {\r\n type: 'list',\r\n name: 'selected',\r\n message: `选择解决方案 (第 ${currentPage}/${paginatedResult.totalPages} 页):`,\r\n choices,\r\n pageSize: 15\r\n }\r\n ])\r\n\r\n if (selected === '__CANCEL__') {\r\n return null\r\n } else if (selected === '__NEXT_PAGE__') {\r\n currentPage++\r\n } else if (selected === '__PREV_PAGE__') {\r\n currentPage--\r\n } else {\r\n // 获取详情\r\n const detailSpinner = ora('正在获取解决方案详情...').start()\r\n const detailResponse = await apiClient.getSolutionById(selected)\r\n detailSpinner.stop()\r\n\r\n selectedSolution = detailResponse.data\r\n }\r\n }\r\n\r\n return selectedSolution\r\n } catch (error) {\r\n spinner.fail('获取解决方案失败')\r\n throw error\r\n }\r\n}\r\n\r\n/**\r\n * 选择 IDE 类型\r\n */\r\nasync function selectIde(): Promise<AiIdeType> {\r\n const { ide } = await inquirer.prompt([\r\n {\r\n type: 'list',\r\n name: 'ide',\r\n message: '请选择 AI IDE 类型:',\r\n choices: [\r\n { name: chalk.cyan('VS Code'), value: 'vscode' },\r\n { name: chalk.cyan('Cursor'), value: 'cursor' },\r\n { name: chalk.cyan('Codex'), value: 'codex' },\r\n { name: chalk.cyan('Claude Code'), value: 'claude-code' }\r\n ],\r\n default: 'vscode'\r\n }\r\n ])\r\n\r\n return ide\r\n}\r\n","import axios, { AxiosInstance, AxiosError } from 'axios'\r\nimport { getToken, getBaseUrl } from '../config/token.js'\r\nimport type {\r\n ApiResponse,\r\n Solution,\r\n AgentConfig,\r\n Prompt,\r\n McpConfig\r\n} from '../types/index.js'\r\n\r\n/**\r\n * API 客户端封装\r\n */\r\n\r\nclass ApiClient {\r\n private client: AxiosInstance\r\n private baseUrlPromise: Promise<string>\r\n\r\n constructor() {\r\n // 异步获取 BASE_URL\r\n this.baseUrlPromise = getBaseUrl()\r\n\r\n this.client = axios.create({\r\n timeout: 30000,\r\n headers: {\r\n 'Content-Type': 'application/json'\r\n }\r\n })\r\n\r\n // 请求拦截器:自动添加 token 和 baseURL\r\n this.client.interceptors.request.use(async (config) => {\r\n // 设置 baseURL\r\n if (!config.baseURL) {\r\n config.baseURL = await this.baseUrlPromise\r\n }\r\n\r\n // 添加 token\r\n const token = await getToken()\r\n if (token) {\r\n config.headers['X-CLI-TOKEN'] = token\r\n }\r\n return config\r\n })\r\n\r\n // 响应拦截器:统一错误处理\r\n this.client.interceptors.response.use(\r\n (response) => response,\r\n (error: AxiosError) => {\r\n if (error.response) {\r\n const status = error.response.status\r\n const message = (error.response.data as any)?.message || error.message\r\n\r\n if (status === 401) {\r\n throw new Error('认证失败,请先执行 acp login 登录')\r\n } else if (status === 403) {\r\n throw new Error('权限不足,请检查 token 是否有效')\r\n } else if (status === 404) {\r\n throw new Error('请求的资源不存在')\r\n } else if (status >= 500) {\r\n throw new Error(`服务器错误 (${status}): ${message}`)\r\n } else {\r\n throw new Error(`请求失败 (${status}): ${message}`)\r\n }\r\n } else if (error.request) {\r\n throw new Error('网络错误,请检查网络连接')\r\n } else {\r\n throw new Error(`请求配置错误: ${error.message}`)\r\n }\r\n }\r\n )\r\n }\r\n\r\n /**\r\n * 获取解决方案列表\r\n */\r\n async getSolutions(aiTool?: string): Promise<ApiResponse<Solution[]>> {\r\n const params = aiTool ? { aiTool } : {}\r\n const response = await this.client.get<ApiResponse<Solution[]>>(\r\n '/api/cli/solutions',\r\n { params }\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取解决方案详情\r\n */\r\n async getSolutionById(id: string): Promise<ApiResponse<Solution>> {\r\n const response = await this.client.get<ApiResponse<Solution>>(\r\n `/api/cli/solutions/${id}`\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 Agent 配置列表\r\n */\r\n async getAgents(): Promise<ApiResponse<AgentConfig[]>> {\r\n const response = await this.client.get<ApiResponse<AgentConfig[]>>(\r\n '/api/cli/agents'\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 Agent 配置详情\r\n */\r\n async getAgentById(id: string): Promise<ApiResponse<AgentConfig>> {\r\n const response = await this.client.get<ApiResponse<AgentConfig>>(\r\n `/api/cli/agents/${id}`\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 Prompt 列表\r\n */\r\n async getPrompts(): Promise<ApiResponse<Prompt[]>> {\r\n const response = await this.client.get<ApiResponse<Prompt[]>>(\r\n '/api/cli/prompts'\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 Prompt 详情\r\n */\r\n async getPromptById(id: string): Promise<ApiResponse<Prompt>> {\r\n const response = await this.client.get<ApiResponse<Prompt>>(\r\n `/api/cli/prompts/${id}`\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 MCP 配置列表\r\n */\r\n async getMcps(): Promise<ApiResponse<McpConfig[]>> {\r\n const response = await this.client.get<ApiResponse<McpConfig[]>>(\r\n '/api/cli/mcps'\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 MCP 配置详情\r\n */\r\n async getMcpById(id: string): Promise<ApiResponse<McpConfig>> {\r\n const response = await this.client.get<ApiResponse<McpConfig>>(\r\n `/api/cli/mcps/${id}`\r\n )\r\n return response.data\r\n }\r\n}\r\n\r\n// 导出单例\r\nexport const apiClient = new ApiClient()\r\n","/**\r\n * 分页工具函数\r\n */\r\n\r\nexport interface PaginationOptions {\r\n page: number\r\n pageSize: number\r\n}\r\n\r\nexport interface PaginationResult<T> {\r\n items: T[]\r\n total: number\r\n page: number\r\n pageSize: number\r\n totalPages: number\r\n hasNext: boolean\r\n hasPrev: boolean\r\n}\r\n\r\n/**\r\n * 对数组进行分页\r\n */\r\nexport function paginate<T>(\r\n items: T[],\r\n options: PaginationOptions\r\n): PaginationResult<T> {\r\n const { page, pageSize } = options\r\n const total = items.length\r\n const totalPages = Math.ceil(total / pageSize)\r\n const startIndex = (page - 1) * pageSize\r\n const endIndex = startIndex + pageSize\r\n\r\n return {\r\n items: items.slice(startIndex, endIndex),\r\n total,\r\n page,\r\n pageSize,\r\n totalPages,\r\n hasNext: page < totalPages,\r\n hasPrev: page > 1\r\n }\r\n}\r\n\r\n/**\r\n * 按名称搜索(不区分大小写)\r\n */\r\nexport function searchByName<T extends { name: string }>(\r\n items: T[],\r\n query: string\r\n): T[] {\r\n if (!query.trim()) {\r\n return items\r\n }\r\n\r\n const lowerQuery = query.toLowerCase().trim()\r\n return items.filter((item) =>\r\n item.name.toLowerCase().includes(lowerQuery)\r\n )\r\n}\r\n","import fs from 'fs-extra'\r\nimport path from 'path'\r\nimport chalk from 'chalk'\r\nimport inquirer from 'inquirer'\r\nimport { logger } from '../utils/logger.js'\r\nimport { getIdePathMapping, type AiIdeType } from '../utils/ide-mapper.js'\r\nimport type { Solution, Prompt, McpConfig } from '../types/index.js'\r\n\r\n/**\r\n * 配置应用模块 - 将远程配置写入本地文件\r\n */\r\n\r\nexport interface ApplyOptions {\r\n ide: AiIdeType\r\n targetDir: string\r\n}\r\n\r\n/**\r\n * 应用解决方案配置\r\n */\r\nexport async function applySolution(\r\n solution: Solution,\r\n options: ApplyOptions\r\n): Promise<void> {\r\n const { ide, targetDir } = options\r\n const pathMapping = getIdePathMapping(ide)\r\n\r\n logger.title(`📦 应用解决方案: ${chalk.cyan(solution.name)}`)\r\n\r\n // 1. 应用 Agent 配置\r\n if (solution.agentConfig) {\r\n await applyAgentConfig(\r\n solution.agentConfig.content,\r\n pathMapping.agents,\r\n targetDir\r\n )\r\n }\r\n\r\n // 2. 应用 Prompts\r\n if (solution.customPrompts?.length) {\r\n await applyPrompts(\r\n solution.customPrompts,\r\n pathMapping.prompts,\r\n targetDir\r\n )\r\n }\r\n\r\n // 3. 应用 MCP 配置\r\n if (solution.mcpConfigs?.length) {\r\n await applyMcpConfigs(\r\n solution.mcpConfigs,\r\n pathMapping.mcp,\r\n targetDir\r\n )\r\n }\r\n\r\n logger.success(`\\n✨ 解决方案 ${chalk.cyan(solution.name)} 应用成功!`)\r\n}\r\n\r\n/**\r\n * 应用 Agent 配置\r\n */\r\nexport async function applyAgentConfig(\r\n content: string,\r\n relativePath: string,\r\n targetDir: string\r\n): Promise<void> {\r\n const filePath = path.join(targetDir, relativePath)\r\n\r\n logger.step(`写入 Agent 配置: ${chalk.gray(relativePath)}`)\r\n\r\n // 检查文件是否存在\r\n const exists = await fs.pathExists(filePath)\r\n if (exists) {\r\n const { overwrite } = await inquirer.prompt([\r\n {\r\n type: 'confirm',\r\n name: 'overwrite',\r\n message: `文件 ${chalk.cyan(relativePath)} 已存在,是否覆盖?`,\r\n default: true\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.warning(`跳过: ${relativePath}`)\r\n return\r\n }\r\n }\r\n\r\n // 写入文件\r\n await fs.ensureDir(path.dirname(filePath))\r\n await fs.writeFile(filePath, content, 'utf-8')\r\n\r\n logger.success(`已写入: ${relativePath}`)\r\n}\r\n\r\n/**\r\n * 应用 Prompts\r\n */\r\nexport async function applyPrompts(\r\n prompts: Prompt[],\r\n promptsDir: string,\r\n targetDir: string\r\n): Promise<void> {\r\n const fullPromptsDir = path.join(targetDir, promptsDir)\r\n\r\n logger.step(`写入 ${prompts.length} 个 Prompt 配置到: ${chalk.gray(promptsDir)}`)\r\n\r\n // 确保目录存在\r\n await fs.ensureDir(fullPromptsDir)\r\n\r\n for (const prompt of prompts) {\r\n // 生成文件名(清理特殊字符)\r\n const fileName = sanitizeFileName(prompt.name) + '.prompt.md'\r\n const filePath = path.join(fullPromptsDir, fileName)\r\n\r\n // 检查是否存在\r\n const exists = await fs.pathExists(filePath)\r\n if (exists) {\r\n const { overwrite } = await inquirer.prompt([\r\n {\r\n type: 'confirm',\r\n name: 'overwrite',\r\n message: `Prompt ${chalk.cyan(fileName)} 已存在,是否覆盖?`,\r\n default: true\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.warning(`跳过: ${fileName}`)\r\n continue\r\n }\r\n }\r\n\r\n // 写入内容\r\n await fs.writeFile(filePath, prompt.content, 'utf-8')\r\n logger.success(`已写入: ${path.join(promptsDir, fileName)}`)\r\n }\r\n}\r\n\r\n/**\r\n * 应用 MCP 配置\r\n */\r\nexport async function applyMcpConfigs(\r\n mcpConfigs: McpConfig[],\r\n mcpFile: string,\r\n targetDir: string\r\n): Promise<void> {\r\n const filePath = path.join(targetDir, mcpFile)\r\n\r\n logger.step(`写入 MCP 配置: ${chalk.gray(mcpFile)}`)\r\n\r\n // 构造 mcpServers 结构\r\n const mcpServers: Record<string, any> = {}\r\n\r\n for (const mcpConfig of mcpConfigs) {\r\n try {\r\n const config = JSON.parse(mcpConfig.configJson)\r\n // 使用 MCP 配置的名称作为 key\r\n mcpServers[mcpConfig.name] = config\r\n } catch (error) {\r\n logger.warning(`MCP 配置 ${mcpConfig.name} 格式错误,已跳过`)\r\n }\r\n }\r\n\r\n // 检查文件是否存在\r\n const exists = await fs.pathExists(filePath)\r\n if (exists) {\r\n const { overwrite } = await inquirer.prompt([\r\n {\r\n type: 'confirm',\r\n name: 'overwrite',\r\n message: `文件 ${chalk.cyan(mcpFile)} 已存在,是否覆盖?`,\r\n default: true\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.warning(`跳过: ${mcpFile}`)\r\n return\r\n }\r\n }\r\n\r\n // 写入文件\r\n await fs.ensureDir(path.dirname(filePath))\r\n\r\n // 根据文件扩展名和路径决定输出格式\r\n if (mcpFile.endsWith('.toml')) {\r\n // Codex 使用 TOML 格式\r\n const tomlContent = convertMcpToToml(mcpServers)\r\n await fs.writeFile(filePath, tomlContent, 'utf-8')\r\n } else {\r\n // JSON 格式\r\n let mergedConfig: Record<string, any>\r\n \r\n // VS Code 使用 \"servers\",其他 IDE 使用 \"mcpServers\"\r\n if (mcpFile.includes('.vscode')) {\r\n mergedConfig = {\r\n servers: mcpServers\r\n }\r\n } else {\r\n mergedConfig = {\r\n mcpServers\r\n }\r\n }\r\n \r\n await fs.writeFile(filePath, JSON.stringify(mergedConfig, null, 2), 'utf-8')\r\n }\r\n\r\n logger.success(`已写入: ${mcpFile}`)\r\n}\r\n\r\n/**\r\n * 将 MCP 配置转换为 TOML 格式(用于 Codex)\r\n */\r\nfunction convertMcpToToml(mcpServers: Record<string, any>): string {\r\n let tomlContent = ''\r\n\r\n for (const [serverName, config] of Object.entries(mcpServers)) {\r\n tomlContent += `[mcp_servers.${serverName}]\\n`\r\n \r\n // 写入 command\r\n if (config.command) {\r\n tomlContent += `command = ${JSON.stringify(config.command)}\\n`\r\n }\r\n\r\n // 写入 args\r\n if (config.args && Array.isArray(config.args)) {\r\n const argsStr = config.args.map((arg: string) => JSON.stringify(arg)).join(', ')\r\n tomlContent += `args = [${argsStr}]\\n`\r\n }\r\n\r\n // 写入 env\r\n if (config.env && typeof config.env === 'object') {\r\n const envEntries = Object.entries(config.env)\r\n if (envEntries.length > 0) {\r\n const envStr = envEntries\r\n .map(([key, value]) => `${key} = ${JSON.stringify(value)}`)\r\n .join(', ')\r\n tomlContent += `env = { ${envStr} }\\n`\r\n }\r\n }\r\n\r\n tomlContent += '\\n'\r\n }\r\n\r\n return tomlContent\r\n}\r\n\r\n/**\r\n * 清理文件名中的特殊字符\r\n */\r\nfunction sanitizeFileName(name: string): string {\r\n return name\r\n .replace(/[<>:\"/\\\\|?*]/g, '-') // 替换非法字符\r\n .replace(/\\s+/g, '-') // 空格转连字符\r\n .replace(/-+/g, '-') // 多个连字符合并\r\n .toLowerCase()\r\n}\r\n","import type { AiIdeType, IdePathMapping } from '../types/index.js'\r\n\r\n// 重新导出类型\r\nexport type { AiIdeType, IdePathMapping }\r\n\r\n/**\r\n * AI IDE 路径映射配置\r\n * 定义不同 IDE 的配置文件输出路径\r\n */\r\n\r\nexport const IDE_PATH_MAPPINGS: Record<AiIdeType, IdePathMapping> = {\r\n vscode: {\r\n prompts: '.github/prompts',\r\n agents: 'AGENTS.md',\r\n mcp: '.vscode/mcp.json'\r\n },\r\n cursor: {\r\n prompts: '.cursor/prompts',\r\n agents: 'AGENTS.md',\r\n mcp: '.cursor/mcp.json'\r\n },\r\n codex: {\r\n prompts: '.codex/prompts',\r\n agents: 'AGENTS.md',\r\n mcp: '.codex/config.toml'\r\n },\r\n 'claude-code': {\r\n prompts: '.claude/prompts',\r\n agents: 'AGENTS.md',\r\n mcp: '.mcp.json'\r\n }\r\n}\r\n\r\n/**\r\n * 获取 IDE 路径映射\r\n */\r\nexport function getIdePathMapping(ide: AiIdeType): IdePathMapping {\r\n return IDE_PATH_MAPPINGS[ide]\r\n}\r\n\r\n/**\r\n * 获取所有支持的 IDE 列表\r\n */\r\nexport function getSupportedIdes(): AiIdeType[] {\r\n return Object.keys(IDE_PATH_MAPPINGS) as AiIdeType[]\r\n}\r\n\r\n/**\r\n * 验证 IDE 类型是否支持\r\n */\r\nexport function isValidIde(ide: string): ide is AiIdeType {\r\n return ide in IDE_PATH_MAPPINGS\r\n}\r\n"],"mappings":"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","names":["Command","chalk","chalk","chalk","Command","inquirer","chalk","fs","path","chalk","inquirer","chalk","path","fs","inquirer","Command","chalk","inquirer","Command","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/config/token.ts","../src/utils/logger.ts","../src/commands/apply.ts","../src/api/client.ts","../src/utils/pagination.ts","../src/apply/writer.ts","../src/utils/ide-mapper.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport { loginCommand } from './commands/login.js'\r\nimport { applyCommand } from './commands/apply.js'\r\nimport { handleError } from './utils/logger.js'\r\n\r\n/**\r\n * ACP CLI 主入口\r\n */\r\n\r\n// 版本号在构建时注入\r\n// @ts-ignore - 构建时通过 tsup define 注入\r\nconst version = typeof __VERSION__ !== 'undefined' ? __VERSION__ : '0.0.0-dev'\r\n\r\nconst program = new Command()\r\n\r\nprogram\r\n .name('acp')\r\n .description(\r\n chalk.gray('AI-Config-Plaza CLI - 统一 AI 编程工具配置管理')\r\n )\r\n .version(version, '-v, --version', '显示版本号')\r\n .helpOption('-h, --help', '显示帮助信息')\r\n\r\n// 注册命令\r\nprogram.addCommand(loginCommand)\r\nprogram.addCommand(applyCommand)\r\n\r\n// 自定义帮助显示\r\nprogram.on('--help', () => {\r\n console.log(chalk.bold('\\n示例:\\n'))\r\n console.log(chalk.gray(' $ acp login'))\r\n console.log(chalk.gray(' $ acp apply'))\r\n console.log(chalk.gray(' $ acp apply --ide vscode --dir ./my-project'))\r\n console.log()\r\n})\r\n\r\n// 解析命令\r\ntry {\r\n await program.parseAsync(process.argv)\r\n} catch (error) {\r\n handleError(error)\r\n process.exit(1)\r\n}\r\n","import { Command } from 'commander'\r\nimport inquirer from 'inquirer'\r\nimport chalk from 'chalk'\r\nimport { saveToken, getToken, initDefaultConfig } from '../config/token.js'\r\nimport { logger } from '../utils/logger.js'\r\n\r\n/**\r\n * acp login 命令\r\n * 提示用户输入 CLI Token 并保存\r\n */\r\n\r\nexport const loginCommand = new Command('login')\r\n .description('登录 ACP CLI,保存访问令牌')\r\n .action(async () => {\r\n try {\r\n logger.title('🔐 ACP CLI 登录')\r\n\r\n // 初始化默认配置(首次使用时)\r\n await initDefaultConfig()\r\n\r\n // 检查是否已有 token\r\n const existingToken = await getToken()\r\n if (existingToken) {\r\n const { overwrite } = await inquirer.prompt([\r\n {\r\n type: 'confirm',\r\n name: 'overwrite',\r\n message: '检测到已登录,是否重新登录?',\r\n default: false\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.info('已取消登录')\r\n return\r\n }\r\n }\r\n\r\n // 提示输入 token\r\n const { token } = await inquirer.prompt([\r\n {\r\n type: 'password',\r\n name: 'token',\r\n message: '请输入 CLI Token:',\r\n validate: (input: string) => {\r\n if (!input.trim()) {\r\n return 'Token 不能为空'\r\n }\r\n if (input.trim().length < 10) {\r\n return 'Token 格式不正确(至少 10 个字符)'\r\n }\r\n return true\r\n },\r\n mask: '*'\r\n }\r\n ])\r\n\r\n // 保存 token\r\n await saveToken(token)\r\n\r\n logger.success('登录成功!Token 已保存到 ~/.acp/token')\r\n console.log(chalk.gray('\\n提示: 现在可以使用 acp apply 命令拉取配置\\n'))\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n logger.error(`登录失败: ${error.message}`)\r\n }\r\n process.exit(1)\r\n }\r\n })\r\n","import fs from 'fs-extra'\r\nimport path from 'path'\r\nimport os from 'os'\r\n\r\n/**\r\n * Token 和 BASE_URL 配置管理\r\n * 优先级: 环境变量 > ~/.acp/ 配置文件\r\n */\r\n\r\nconst TOKEN_ENV_KEY = 'ACP_CLI_TOKEN'\r\nconst BASE_URL_ENV_KEY = 'ACP_CLI_BASE_URL'\r\nconst DEFAULT_BASE_URL = 'https://api.ai-config-plaza.com'\r\n\r\nconst CONFIG_DIR = path.join(os.homedir(), '.acp')\r\nconst TOKEN_FILE = path.join(CONFIG_DIR, 'token')\r\nconst BASE_URL_FILE = path.join(CONFIG_DIR, 'base-url')\r\n\r\n/**\r\n * 读取 CLI Token\r\n */\r\nexport async function getToken(): Promise<string | null> {\r\n // 1. 优先读取环境变量\r\n const envToken = process.env[TOKEN_ENV_KEY]\r\n if (envToken?.trim()) {\r\n return envToken.trim()\r\n }\r\n\r\n // 2. 读取本地配置文件\r\n try {\r\n if (await fs.pathExists(TOKEN_FILE)) {\r\n const token = await fs.readFile(TOKEN_FILE, 'utf-8')\r\n return token.trim() || null\r\n }\r\n } catch (error) {\r\n // 读取失败返回 null\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * 保存 CLI Token 到本地配置文件\r\n */\r\nexport async function saveToken(token: string): Promise<void> {\r\n if (!token?.trim()) {\r\n throw new Error('Token 不能为空')\r\n }\r\n\r\n // 确保配置目录存在\r\n await fs.ensureDir(CONFIG_DIR)\r\n\r\n // 写入 token 文件\r\n await fs.writeFile(TOKEN_FILE, token.trim(), 'utf-8')\r\n}\r\n\r\n/**\r\n * 删除本地 Token\r\n */\r\nexport async function removeToken(): Promise<void> {\r\n if (await fs.pathExists(TOKEN_FILE)) {\r\n await fs.remove(TOKEN_FILE)\r\n }\r\n}\r\n\r\n/**\r\n * 检查是否已登录\r\n */\r\nexport async function isLoggedIn(): Promise<boolean> {\r\n const token = await getToken()\r\n return token !== null && token.length > 0\r\n}\r\n\r\n/**\r\n * 读取 BASE_URL\r\n */\r\nexport async function getBaseUrl(): Promise<string> {\r\n // 1. 优先读取环境变量\r\n const envBaseUrl = process.env[BASE_URL_ENV_KEY]\r\n if (envBaseUrl?.trim()) {\r\n return envBaseUrl.trim()\r\n }\r\n\r\n // 2. 读取本地配置文件\r\n try {\r\n if (await fs.pathExists(BASE_URL_FILE)) {\r\n const baseUrl = await fs.readFile(BASE_URL_FILE, 'utf-8')\r\n if (baseUrl.trim()) {\r\n return baseUrl.trim()\r\n }\r\n }\r\n } catch (error) {\r\n // 读取失败,使用默认值\r\n }\r\n\r\n // 3. 返回默认值\r\n return DEFAULT_BASE_URL\r\n}\r\n\r\n/**\r\n * 保存 BASE_URL 到本地配置文件\r\n */\r\nexport async function saveBaseUrl(baseUrl: string): Promise<void> {\r\n if (!baseUrl?.trim()) {\r\n throw new Error('BASE_URL 不能为空')\r\n }\r\n\r\n // 验证 URL 格式\r\n try {\r\n new URL(baseUrl.trim())\r\n } catch {\r\n throw new Error('BASE_URL 格式不正确,请输入有效的 URL')\r\n }\r\n\r\n // 确保配置目录存在\r\n await fs.ensureDir(CONFIG_DIR)\r\n\r\n // 写入 base-url 文件\r\n await fs.writeFile(BASE_URL_FILE, baseUrl.trim(), 'utf-8')\r\n}\r\n\r\n/**\r\n * 删除本地 BASE_URL\r\n */\r\nexport async function removeBaseUrl(): Promise<void> {\r\n if (await fs.pathExists(BASE_URL_FILE)) {\r\n await fs.remove(BASE_URL_FILE)\r\n }\r\n}\r\n\r\n/**\r\n * 初始化默认配置(首次使用时)\r\n */\r\nexport async function initDefaultConfig(): Promise<void> {\r\n await fs.ensureDir(CONFIG_DIR)\r\n\r\n // 如果 BASE_URL 不存在,初始化默认值\r\n if (!(await fs.pathExists(BASE_URL_FILE))) {\r\n await saveBaseUrl(DEFAULT_BASE_URL)\r\n }\r\n}\r\n","import chalk from 'chalk'\r\n\r\n/**\r\n * 日志工具 - 提供统一的终端输出格式\r\n */\r\n\r\n// 使用 Unicode 符号代替 figures\r\nconst symbols = {\r\n info: 'ℹ',\r\n tick: '✓',\r\n warning: '⚠',\r\n cross: '✖',\r\n arrowRight: '→'\r\n}\r\n\r\nexport const logger = {\r\n /**\r\n * 普通信息\r\n */\r\n info: (message: string) => {\r\n console.log(chalk.blue(symbols.info) + ' ' + message)\r\n },\r\n\r\n /**\r\n * 成功信息\r\n */\r\n success: (message: string) => {\r\n console.log(chalk.green(symbols.tick) + ' ' + chalk.green(message))\r\n },\r\n\r\n /**\r\n * 警告信息\r\n */\r\n warning: (message: string) => {\r\n console.log(chalk.yellow(symbols.warning) + ' ' + chalk.yellow(message))\r\n },\r\n\r\n /**\r\n * 错误信息\r\n */\r\n error: (message: string) => {\r\n console.error(chalk.red(symbols.cross) + ' ' + chalk.red(message))\r\n },\r\n\r\n /**\r\n * 步骤信息\r\n */\r\n step: (message: string) => {\r\n console.log(chalk.cyan(symbols.arrowRight) + ' ' + chalk.gray(message))\r\n },\r\n\r\n /**\r\n * 标题\r\n */\r\n title: (message: string) => {\r\n console.log('\\n' + chalk.bold.underline(message) + '\\n')\r\n },\r\n\r\n /**\r\n * 普通文本(无图标)\r\n */\r\n log: (message: string) => {\r\n console.log(message)\r\n }\r\n}\r\n\r\n/**\r\n * 自定义 CLI 错误类\r\n */\r\nexport class CLIError extends Error {\r\n constructor(\r\n message: string,\r\n public code?: string,\r\n public suggestions?: string[]\r\n ) {\r\n super(message)\r\n this.name = 'CLIError'\r\n }\r\n}\r\n\r\n/**\r\n * 错误处理函数\r\n */\r\nexport function handleError(error: unknown): void {\r\n console.error()\r\n\r\n if (error instanceof CLIError) {\r\n logger.error(error.message)\r\n\r\n if (error.code) {\r\n console.log(chalk.gray(`错误代码: ${error.code}`))\r\n }\r\n\r\n if (error.suggestions?.length) {\r\n console.log(chalk.yellow.bold('\\n💡 建议:\\n'))\r\n error.suggestions.forEach((suggestion, index) => {\r\n console.log(chalk.gray(` ${index + 1}. ${suggestion}`))\r\n })\r\n }\r\n } else if (error instanceof Error) {\r\n logger.error(error.message)\r\n\r\n if (process.env.DEBUG) {\r\n console.log(chalk.gray('\\n' + error.stack))\r\n }\r\n } else {\r\n logger.error('未知错误')\r\n }\r\n\r\n console.log(\r\n chalk.gray('\\n需要帮助? 访问: ') +\r\n chalk.blue.underline('https://github.com/AIConfigPlaza/acp-cli')\r\n )\r\n console.log()\r\n}\r\n","import { Command } from 'commander'\r\nimport inquirer from 'inquirer'\r\nimport chalk from 'chalk'\r\nimport ora from 'ora'\r\nimport { apiClient } from '../api/client.js'\r\nimport { logger, CLIError } from '../utils/logger.js'\r\nimport { isLoggedIn } from '../config/token.js'\r\nimport { type AiIdeType } from '../utils/ide-mapper.js'\r\nimport { searchByName, paginate } from '../utils/pagination.js'\r\nimport { applySolution } from '../apply/writer.js'\r\nimport type { Solution } from '../types/index.js'\r\n\r\n/**\r\n * acp apply 命令\r\n * 拉取并应用配置到本地项目\r\n */\r\n\r\ntype ResourceType = 'solution' | 'agent' | 'prompt' | 'mcp'\r\n\r\nexport const applyCommand = new Command('apply')\r\n .description('拉取并应用配置到本地项目')\r\n .option('-t, --type <type>', '资源类型 (solution|agent|prompt|mcp)', 'solution')\r\n .option('-i, --ide <ide>', 'AI IDE 类型 (vscode|cursor|codex|claude-code)')\r\n .option('-d, --dir <path>', '目标目录', process.cwd())\r\n .action(async (options) => {\r\n try {\r\n // 检查登录状态\r\n if (!(await isLoggedIn())) {\r\n throw new CLIError(\r\n '未登录,请先执行 acp login',\r\n 'NOT_LOGGED_IN',\r\n ['运行 acp login 命令登录']\r\n )\r\n }\r\n\r\n logger.title('🚀 ACP 配置应用')\r\n\r\n // 1. 选择资源类型\r\n const resourceType = await selectResourceType(options.type)\r\n\r\n // 2. 根据类型拉取并选择资源\r\n let selectedSolution: Solution | null = null\r\n\r\n if (resourceType === 'solution') {\r\n selectedSolution = await fetchAndSelectSolution()\r\n } else {\r\n throw new CLIError('暂不支持独立应用 agent/prompt/mcp,请使用 solution 类型')\r\n }\r\n\r\n if (!selectedSolution) {\r\n logger.info('未选择任何配置')\r\n return\r\n }\r\n\r\n // 3. 选择 IDE 类型\r\n const ide = options.ide || (await selectIde())\r\n\r\n // 4. 应用配置\r\n await applySolution(selectedSolution, {\r\n ide: ide as AiIdeType,\r\n targetDir: options.dir\r\n })\r\n\r\n console.log(chalk.gray(`\\n配置已应用到: ${chalk.cyan(options.dir)}\\n`))\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n logger.error(error.message)\r\n }\r\n process.exit(1)\r\n }\r\n })\r\n\r\n/**\r\n * 选择资源类型\r\n */\r\nasync function selectResourceType(defaultType?: string): Promise<ResourceType> {\r\n if (defaultType && ['solution', 'agent', 'prompt', 'mcp'].includes(defaultType)) {\r\n return defaultType as ResourceType\r\n }\r\n\r\n const { type } = await inquirer.prompt([\r\n {\r\n type: 'list',\r\n name: 'type',\r\n message: '请选择资源类型:',\r\n choices: [\r\n { name: chalk.cyan('解决方案 (Solution)'), value: 'solution' },\r\n { name: chalk.gray('Agent 配置 (暂不支持)'), value: 'agent', disabled: true },\r\n { name: chalk.gray('Prompt (暂不支持)'), value: 'prompt', disabled: true },\r\n { name: chalk.gray('MCP 配置 (暂不支持)'), value: 'mcp', disabled: true }\r\n ],\r\n default: 'solution'\r\n }\r\n ])\r\n\r\n return type\r\n}\r\n\r\n/**\r\n * 拉取并选择解决方案\r\n */\r\nasync function fetchAndSelectSolution(): Promise<Solution | null> {\r\n const spinner = ora('正在获取解决方案列表...').start()\r\n\r\n try {\r\n // 1. 拉取解决方案列表\r\n const response = await apiClient.getSolutions()\r\n spinner.stop()\r\n\r\n if (!response.data || response.data.length === 0) {\r\n logger.warning('暂无可用的解决方案')\r\n return null\r\n }\r\n\r\n logger.success(`获取到 ${response.data.length} 个解决方案`)\r\n\r\n // 2. 搜索过滤\r\n const { searchQuery } = await inquirer.prompt([\r\n {\r\n type: 'input',\r\n name: 'searchQuery',\r\n message: '搜索解决方案 (按名称搜索,留空显示全部):',\r\n default: ''\r\n }\r\n ])\r\n\r\n let filteredSolutions = searchByName(response.data, searchQuery)\r\n\r\n if (filteredSolutions.length === 0) {\r\n logger.warning('未找到匹配的解决方案')\r\n return null\r\n }\r\n\r\n // 3. 分页显示\r\n const PAGE_SIZE = 20\r\n let currentPage = 1\r\n let selectedSolution: Solution | null = null\r\n\r\n while (!selectedSolution) {\r\n const paginatedResult = paginate(filteredSolutions, {\r\n page: currentPage,\r\n pageSize: PAGE_SIZE\r\n })\r\n\r\n // 构建选择列表\r\n const choices = paginatedResult.items.map((solution) => ({\r\n name: `${chalk.cyan(solution.name)} - ${chalk.gray(solution.description)}`,\r\n value: solution.id,\r\n short: solution.name\r\n }))\r\n\r\n // 添加分页控制选项\r\n if (paginatedResult.hasNext) {\r\n choices.push({\r\n name: chalk.yellow('>>> 下一页'),\r\n value: '__NEXT_PAGE__',\r\n short: '下一页'\r\n })\r\n }\r\n\r\n if (paginatedResult.hasPrev) {\r\n choices.unshift({\r\n name: chalk.yellow('<<< 上一页'),\r\n value: '__PREV_PAGE__',\r\n short: '上一页'\r\n })\r\n }\r\n\r\n choices.push({\r\n name: chalk.red('取消'),\r\n value: '__CANCEL__',\r\n short: '取消'\r\n })\r\n\r\n const { selected } = await inquirer.prompt([\r\n {\r\n type: 'list',\r\n name: 'selected',\r\n message: `选择解决方案 (第 ${currentPage}/${paginatedResult.totalPages} 页):`,\r\n choices,\r\n pageSize: 15\r\n }\r\n ])\r\n\r\n if (selected === '__CANCEL__') {\r\n return null\r\n } else if (selected === '__NEXT_PAGE__') {\r\n currentPage++\r\n } else if (selected === '__PREV_PAGE__') {\r\n currentPage--\r\n } else {\r\n // 获取详情\r\n const detailSpinner = ora('正在获取解决方案详情...').start()\r\n const detailResponse = await apiClient.getSolutionById(selected)\r\n detailSpinner.stop()\r\n\r\n selectedSolution = detailResponse.data\r\n }\r\n }\r\n\r\n return selectedSolution\r\n } catch (error) {\r\n spinner.fail('获取解决方案失败')\r\n throw error\r\n }\r\n}\r\n\r\n/**\r\n * 选择 IDE 类型\r\n */\r\nasync function selectIde(): Promise<AiIdeType> {\r\n const { ide } = await inquirer.prompt([\r\n {\r\n type: 'list',\r\n name: 'ide',\r\n message: '请选择 AI IDE 类型:',\r\n choices: [\r\n { name: chalk.cyan('VS Code'), value: 'vscode' },\r\n { name: chalk.cyan('Cursor'), value: 'cursor' },\r\n { name: chalk.cyan('Codex'), value: 'codex' },\r\n { name: chalk.cyan('Claude Code'), value: 'claude-code' }\r\n ],\r\n default: 'vscode'\r\n }\r\n ])\r\n\r\n return ide\r\n}\r\n","import axios, { AxiosInstance, AxiosError } from 'axios'\r\nimport { getToken, getBaseUrl } from '../config/token.js'\r\nimport type {\r\n ApiResponse,\r\n Solution,\r\n AgentConfig,\r\n Prompt,\r\n McpConfig\r\n} from '../types/index.js'\r\n\r\n/**\r\n * API 客户端封装\r\n */\r\n\r\nclass ApiClient {\r\n private client: AxiosInstance\r\n private baseUrlPromise: Promise<string>\r\n\r\n constructor() {\r\n // 异步获取 BASE_URL\r\n this.baseUrlPromise = getBaseUrl()\r\n\r\n this.client = axios.create({\r\n timeout: 30000,\r\n headers: {\r\n 'Content-Type': 'application/json'\r\n }\r\n })\r\n\r\n // 请求拦截器:自动添加 token 和 baseURL\r\n this.client.interceptors.request.use(async (config) => {\r\n // 设置 baseURL\r\n if (!config.baseURL) {\r\n config.baseURL = await this.baseUrlPromise\r\n }\r\n\r\n // 添加 token\r\n const token = await getToken()\r\n if (token) {\r\n config.headers['X-CLI-TOKEN'] = token\r\n }\r\n return config\r\n })\r\n\r\n // 响应拦截器:统一错误处理\r\n this.client.interceptors.response.use(\r\n (response) => response,\r\n (error: AxiosError) => {\r\n if (error.response) {\r\n const status = error.response.status\r\n const message = (error.response.data as any)?.message || error.message\r\n\r\n if (status === 401) {\r\n throw new Error('认证失败,请先执行 acp login 登录')\r\n } else if (status === 403) {\r\n throw new Error('权限不足,请检查 token 是否有效')\r\n } else if (status === 404) {\r\n throw new Error('请求的资源不存在')\r\n } else if (status >= 500) {\r\n throw new Error(`服务器错误 (${status}): ${message}`)\r\n } else {\r\n throw new Error(`请求失败 (${status}): ${message}`)\r\n }\r\n } else if (error.request) {\r\n throw new Error('网络错误,请检查网络连接')\r\n } else {\r\n throw new Error(`请求配置错误: ${error.message}`)\r\n }\r\n }\r\n )\r\n }\r\n\r\n /**\r\n * 获取解决方案列表\r\n */\r\n async getSolutions(aiTool?: string): Promise<ApiResponse<Solution[]>> {\r\n const params = aiTool ? { aiTool } : {}\r\n const response = await this.client.get<ApiResponse<Solution[]>>(\r\n '/api/cli/solutions',\r\n { params }\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取解决方案详情\r\n */\r\n async getSolutionById(id: string): Promise<ApiResponse<Solution>> {\r\n const response = await this.client.get<ApiResponse<Solution>>(\r\n `/api/cli/solutions/${id}`\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 Agent 配置列表\r\n */\r\n async getAgents(): Promise<ApiResponse<AgentConfig[]>> {\r\n const response = await this.client.get<ApiResponse<AgentConfig[]>>(\r\n '/api/cli/agents'\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 Agent 配置详情\r\n */\r\n async getAgentById(id: string): Promise<ApiResponse<AgentConfig>> {\r\n const response = await this.client.get<ApiResponse<AgentConfig>>(\r\n `/api/cli/agents/${id}`\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 Prompt 列表\r\n */\r\n async getPrompts(): Promise<ApiResponse<Prompt[]>> {\r\n const response = await this.client.get<ApiResponse<Prompt[]>>(\r\n '/api/cli/prompts'\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 Prompt 详情\r\n */\r\n async getPromptById(id: string): Promise<ApiResponse<Prompt>> {\r\n const response = await this.client.get<ApiResponse<Prompt>>(\r\n `/api/cli/prompts/${id}`\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 MCP 配置列表\r\n */\r\n async getMcps(): Promise<ApiResponse<McpConfig[]>> {\r\n const response = await this.client.get<ApiResponse<McpConfig[]>>(\r\n '/api/cli/mcps'\r\n )\r\n return response.data\r\n }\r\n\r\n /**\r\n * 获取 MCP 配置详情\r\n */\r\n async getMcpById(id: string): Promise<ApiResponse<McpConfig>> {\r\n const response = await this.client.get<ApiResponse<McpConfig>>(\r\n `/api/cli/mcps/${id}`\r\n )\r\n return response.data\r\n }\r\n}\r\n\r\n// 导出单例\r\nexport const apiClient = new ApiClient()\r\n","/**\r\n * 分页工具函数\r\n */\r\n\r\nexport interface PaginationOptions {\r\n page: number\r\n pageSize: number\r\n}\r\n\r\nexport interface PaginationResult<T> {\r\n items: T[]\r\n total: number\r\n page: number\r\n pageSize: number\r\n totalPages: number\r\n hasNext: boolean\r\n hasPrev: boolean\r\n}\r\n\r\n/**\r\n * 对数组进行分页\r\n */\r\nexport function paginate<T>(\r\n items: T[],\r\n options: PaginationOptions\r\n): PaginationResult<T> {\r\n const { page, pageSize } = options\r\n const total = items.length\r\n const totalPages = Math.ceil(total / pageSize)\r\n const startIndex = (page - 1) * pageSize\r\n const endIndex = startIndex + pageSize\r\n\r\n return {\r\n items: items.slice(startIndex, endIndex),\r\n total,\r\n page,\r\n pageSize,\r\n totalPages,\r\n hasNext: page < totalPages,\r\n hasPrev: page > 1\r\n }\r\n}\r\n\r\n/**\r\n * 按名称搜索(不区分大小写)\r\n */\r\nexport function searchByName<T extends { name: string }>(\r\n items: T[],\r\n query: string\r\n): T[] {\r\n if (!query.trim()) {\r\n return items\r\n }\r\n\r\n const lowerQuery = query.toLowerCase().trim()\r\n return items.filter((item) =>\r\n item.name.toLowerCase().includes(lowerQuery)\r\n )\r\n}\r\n","import fs from 'fs-extra'\r\nimport path from 'path'\r\nimport chalk from 'chalk'\r\nimport inquirer from 'inquirer'\r\nimport { logger } from '../utils/logger.js'\r\nimport { getIdePathMapping, type AiIdeType } from '../utils/ide-mapper.js'\r\nimport type { Solution, Prompt, McpConfig } from '../types/index.js'\r\n\r\n/**\r\n * 配置应用模块 - 将远程配置写入本地文件\r\n */\r\n\r\nexport interface ApplyOptions {\r\n ide: AiIdeType\r\n targetDir: string\r\n}\r\n\r\n/**\r\n * 应用解决方案配置\r\n */\r\nexport async function applySolution(\r\n solution: Solution,\r\n options: ApplyOptions\r\n): Promise<void> {\r\n const { ide, targetDir } = options\r\n const pathMapping = getIdePathMapping(ide)\r\n\r\n logger.title(`📦 应用解决方案: ${chalk.cyan(solution.name)}`)\r\n\r\n // 1. 应用 Agent 配置\r\n if (solution.agentConfig) {\r\n await applyAgentConfig(\r\n solution.agentConfig.content,\r\n pathMapping.agents,\r\n targetDir\r\n )\r\n }\r\n\r\n // 2. 应用 Prompts\r\n if (solution.customPrompts?.length) {\r\n await applyPrompts(\r\n solution.customPrompts,\r\n pathMapping.prompts,\r\n targetDir\r\n )\r\n }\r\n\r\n // 3. 应用 MCP 配置\r\n if (solution.mcpConfigs?.length) {\r\n await applyMcpConfigs(\r\n solution.mcpConfigs,\r\n pathMapping.mcp,\r\n targetDir\r\n )\r\n }\r\n\r\n logger.success(`\\n✨ 解决方案 ${chalk.cyan(solution.name)} 应用成功!`)\r\n}\r\n\r\n/**\r\n * 应用 Agent 配置\r\n */\r\nexport async function applyAgentConfig(\r\n content: string,\r\n relativePath: string,\r\n targetDir: string\r\n): Promise<void> {\r\n const filePath = path.join(targetDir, relativePath)\r\n\r\n logger.step(`写入 Agent 配置: ${chalk.gray(relativePath)}`)\r\n\r\n // 检查文件是否存在\r\n const exists = await fs.pathExists(filePath)\r\n if (exists) {\r\n const { overwrite } = await inquirer.prompt([\r\n {\r\n type: 'confirm',\r\n name: 'overwrite',\r\n message: `文件 ${chalk.cyan(relativePath)} 已存在,是否覆盖?`,\r\n default: true\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.warning(`跳过: ${relativePath}`)\r\n return\r\n }\r\n }\r\n\r\n // 写入文件\r\n await fs.ensureDir(path.dirname(filePath))\r\n await fs.writeFile(filePath, content, 'utf-8')\r\n\r\n logger.success(`已写入: ${relativePath}`)\r\n}\r\n\r\n/**\r\n * 应用 Prompts\r\n */\r\nexport async function applyPrompts(\r\n prompts: Prompt[],\r\n promptsDir: string,\r\n targetDir: string\r\n): Promise<void> {\r\n const fullPromptsDir = path.join(targetDir, promptsDir)\r\n\r\n logger.step(`写入 ${prompts.length} 个 Prompt 配置到: ${chalk.gray(promptsDir)}`)\r\n\r\n // 确保目录存在\r\n await fs.ensureDir(fullPromptsDir)\r\n\r\n for (const prompt of prompts) {\r\n // 生成文件名(清理特殊字符)\r\n const fileName = sanitizeFileName(prompt.name) + '.prompt.md'\r\n const filePath = path.join(fullPromptsDir, fileName)\r\n\r\n // 检查是否存在\r\n const exists = await fs.pathExists(filePath)\r\n if (exists) {\r\n const { overwrite } = await inquirer.prompt([\r\n {\r\n type: 'confirm',\r\n name: 'overwrite',\r\n message: `Prompt ${chalk.cyan(fileName)} 已存在,是否覆盖?`,\r\n default: true\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.warning(`跳过: ${fileName}`)\r\n continue\r\n }\r\n }\r\n\r\n // 写入内容\r\n await fs.writeFile(filePath, prompt.content, 'utf-8')\r\n logger.success(`已写入: ${path.join(promptsDir, fileName)}`)\r\n }\r\n}\r\n\r\n/**\r\n * 应用 MCP 配置\r\n */\r\nexport async function applyMcpConfigs(\r\n mcpConfigs: McpConfig[],\r\n mcpFile: string,\r\n targetDir: string\r\n): Promise<void> {\r\n const filePath = path.join(targetDir, mcpFile)\r\n\r\n logger.step(`写入 MCP 配置: ${chalk.gray(mcpFile)}`)\r\n\r\n // 构造 mcpServers 结构\r\n const mcpServers: Record<string, any> = {}\r\n\r\n for (const mcpConfig of mcpConfigs) {\r\n try {\r\n const config = JSON.parse(mcpConfig.configJson)\r\n // 使用 MCP 配置的名称作为 key\r\n mcpServers[mcpConfig.name] = config\r\n } catch (error) {\r\n logger.warning(`MCP 配置 ${mcpConfig.name} 格式错误,已跳过`)\r\n }\r\n }\r\n\r\n // 检查文件是否存在\r\n const exists = await fs.pathExists(filePath)\r\n if (exists) {\r\n const { overwrite } = await inquirer.prompt([\r\n {\r\n type: 'confirm',\r\n name: 'overwrite',\r\n message: `文件 ${chalk.cyan(mcpFile)} 已存在,是否覆盖?`,\r\n default: true\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.warning(`跳过: ${mcpFile}`)\r\n return\r\n }\r\n }\r\n\r\n // 写入文件\r\n await fs.ensureDir(path.dirname(filePath))\r\n\r\n // 根据文件扩展名和路径决定输出格式\r\n if (mcpFile.endsWith('.toml')) {\r\n // Codex 使用 TOML 格式\r\n const tomlContent = convertMcpToToml(mcpServers)\r\n await fs.writeFile(filePath, tomlContent, 'utf-8')\r\n } else {\r\n // JSON 格式\r\n let mergedConfig: Record<string, any>\r\n \r\n // VS Code 使用 \"servers\",其他 IDE 使用 \"mcpServers\"\r\n if (mcpFile.includes('.vscode')) {\r\n mergedConfig = {\r\n servers: mcpServers\r\n }\r\n } else {\r\n mergedConfig = {\r\n mcpServers\r\n }\r\n }\r\n \r\n await fs.writeFile(filePath, JSON.stringify(mergedConfig, null, 2), 'utf-8')\r\n }\r\n\r\n logger.success(`已写入: ${mcpFile}`)\r\n}\r\n\r\n/**\r\n * 将 MCP 配置转换为 TOML 格式(用于 Codex)\r\n */\r\nfunction convertMcpToToml(mcpServers: Record<string, any>): string {\r\n let tomlContent = ''\r\n\r\n for (const [serverName, config] of Object.entries(mcpServers)) {\r\n tomlContent += `[mcp_servers.${serverName}]\\n`\r\n \r\n // 写入 command\r\n if (config.command) {\r\n tomlContent += `command = ${JSON.stringify(config.command)}\\n`\r\n }\r\n\r\n // 写入 args\r\n if (config.args && Array.isArray(config.args)) {\r\n const argsStr = config.args.map((arg: string) => JSON.stringify(arg)).join(', ')\r\n tomlContent += `args = [${argsStr}]\\n`\r\n }\r\n\r\n // 写入 env\r\n if (config.env && typeof config.env === 'object') {\r\n const envEntries = Object.entries(config.env)\r\n if (envEntries.length > 0) {\r\n const envStr = envEntries\r\n .map(([key, value]) => `${key} = ${JSON.stringify(value)}`)\r\n .join(', ')\r\n tomlContent += `env = { ${envStr} }\\n`\r\n }\r\n }\r\n\r\n tomlContent += '\\n'\r\n }\r\n\r\n return tomlContent\r\n}\r\n\r\n/**\r\n * 清理文件名中的特殊字符\r\n */\r\nfunction sanitizeFileName(name: string): string {\r\n return name\r\n .replace(/[<>:\"/\\\\|?*]/g, '-') // 替换非法字符\r\n .replace(/\\s+/g, '-') // 空格转连字符\r\n .replace(/-+/g, '-') // 多个连字符合并\r\n .toLowerCase()\r\n}\r\n","import type { AiIdeType, IdePathMapping } from '../types/index.js'\r\n\r\n// 重新导出类型\r\nexport type { AiIdeType, IdePathMapping }\r\n\r\n/**\r\n * AI IDE 路径映射配置\r\n * 定义不同 IDE 的配置文件输出路径\r\n */\r\n\r\nexport const IDE_PATH_MAPPINGS: Record<AiIdeType, IdePathMapping> = {\r\n vscode: {\r\n prompts: '.github/prompts',\r\n agents: 'AGENTS.md',\r\n mcp: '.vscode/mcp.json'\r\n },\r\n cursor: {\r\n prompts: '.cursor/commands',\r\n agents: 'AGENTS.md',\r\n mcp: '.cursor/mcp.json'\r\n },\r\n codex: {\r\n prompts: '~/.codex/prompts',\r\n agents: 'AGENTS.md',\r\n mcp: '.codex/config.toml'\r\n },\r\n 'claude-code': {\r\n prompts: '.claude/commands',\r\n agents: 'AGENTS.md',\r\n mcp: '.mcp.json'\r\n }\r\n}\r\n\r\n/**\r\n * 获取 IDE 路径映射\r\n */\r\nexport function getIdePathMapping(ide: AiIdeType): IdePathMapping {\r\n return IDE_PATH_MAPPINGS[ide]\r\n}\r\n\r\n/**\r\n * 获取所有支持的 IDE 列表\r\n */\r\nexport function getSupportedIdes(): AiIdeType[] {\r\n return Object.keys(IDE_PATH_MAPPINGS) as AiIdeType[]\r\n}\r\n\r\n/**\r\n * 验证 IDE 类型是否支持\r\n */\r\nexport function isValidIde(ide: string): ide is AiIdeType {\r\n return ide in IDE_PATH_MAPPINGS\r\n}\r\n"],"mappings":"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","names":["Command","chalk","chalk","chalk","Command","inquirer","chalk","fs","path","chalk","inquirer","chalk","path","fs","inquirer","Command","chalk","inquirer","Command","chalk"]}
|