@ai-config-plaza/acp-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # ACP CLI
2
+
3
+ **AI-Config-Plaza CLI** - 统一 AI 编程工具配置管理工具
4
+
5
+ ## 📖 简介
6
+
7
+ ACP CLI 是一个专为简化 AI 编程工具配置而设计的命令行工具。通过统一的配置标准,帮助开发者快速初始化和配置 AI 工具(如 VS Code、Cursor、Codex、Claude Code 等)。
8
+
9
+ ### 核心特性
10
+
11
+ - 🔐 **统一认证**:通过 CLI Token 统一管理 API 访问权限
12
+ - 📦 **一键应用**:快速拉取并应用配置到本地项目
13
+ - 🔍 **智能搜索**:支持按名称搜索和分页浏览配置
14
+ - 🎨 **多 IDE 支持**:自动适配不同 AI IDE 的配置路径
15
+ - ✨ **友好交互**:清晰的终端提示和进度反馈
16
+
17
+ ## 🚀 快速开始
18
+
19
+ ### 安装
20
+
21
+ ```bash
22
+ # 使用 npm
23
+ npm install -g acp-cli
24
+
25
+ # 使用 pnpm
26
+ pnpm add -g acp-cli
27
+
28
+ # 使用 yarn
29
+ yarn global add acp-cli
30
+ ```
31
+
32
+ ### 本地开发
33
+
34
+ ```bash
35
+ # 克隆仓库
36
+ git clone https://github.com/AIConfigPlaza/acp-cli.git
37
+ cd acp-cli
38
+
39
+ # 安装依赖
40
+ pnpm install
41
+
42
+ # 本地构建
43
+ pnpm build
44
+
45
+ # 链接到全局(用于本地测试)
46
+ npm link
47
+ ```
48
+
49
+ ## 📋 使用指南
50
+
51
+ ### 1. 登录
52
+
53
+ 首次使用需要登录并保存 CLI Token:
54
+
55
+ ```bash
56
+ acp login
57
+ ```
58
+
59
+ 系统会提示输入 CLI Token,Token 将保存在用户主目录 `~/.acp/token` 中。
60
+
61
+ ### 2. 应用配置
62
+
63
+ 拉取并应用配置到本地项目:
64
+
65
+ ```bash
66
+ # 在当前目录应用配置
67
+ acp apply
68
+
69
+ # 指定 IDE 类型
70
+ acp apply --ide vscode
71
+
72
+ # 指定目标目录
73
+ acp apply --dir ./my-project
74
+
75
+ # 完整示例
76
+ acp apply --ide cursor --dir ~/projects/my-app
77
+ ```
78
+
79
+ ### 3. 交互流程
80
+
81
+ 执行 `acp apply` 后,CLI 会引导你完成以下步骤:
82
+
83
+ 1. **选择资源类型**:目前支持 Solution(解决方案)
84
+ 2. **搜索配置**:输入关键词搜索,或留空显示全部
85
+ 3. **分页浏览**:每页显示 20 条记录,支持上下翻页
86
+ 4. **选择配置**:从列表中选择需要的配置
87
+ 5. **选择 IDE**:选择目标 AI IDE 类型
88
+ 6. **确认覆盖**:如果文件已存在,会提示是否覆盖
89
+
90
+ ## 📁 配置输出路径
91
+
92
+ 不同 AI IDE 的配置文件输出路径:
93
+
94
+ | IDE | Prompts 路径 | Agents 文件 | MCP 配置 |
95
+ | ----------- | -------------------- | ------------- | ----------------------- |
96
+ | VS Code | `.github/prompts/` | `AGENTS.md` | `.vscode/mcp.json` |
97
+ | Cursor | `.cursor/prompts/` | `AGENTS.md` | `.cursor/mcp.json` |
98
+ | Codex | `.codex/prompts/` | `AGENTS.md` | `.codex/config.toml` |
99
+ | Claude Code | `.claude/prompts/` | `AGENTS.md` | `.mcp.json` |
100
+
101
+ ### 文件格式
102
+
103
+ - **Prompts**:输出为 `*.prompt.md` 格式的 Markdown 文件
104
+ - **Agents**:输出为项目根目录的 `AGENTS.md` 文件
105
+ - **MCP 配置**:
106
+ - VS Code: JSON 格式(`servers` 结构)在 `.vscode/mcp.json`
107
+ - Cursor/Claude Code: JSON 格式(`mcpServers` 结构)
108
+ - Codex: TOML 格式(`[mcp_servers.xxx]` 结构)在 `.codex/config.toml`
109
+
110
+ ## 🔧 命令参考
111
+
112
+ ### `acp login`
113
+
114
+ 登录并保存 CLI Token。
115
+
116
+ **示例**:
117
+ ```bash
118
+ acp login
119
+ ```
120
+
121
+ ### `acp apply`
122
+
123
+ 拉取并应用配置到本地项目。
124
+
125
+ **选项**:
126
+ - `-t, --type <type>`:资源类型(目前仅支持 `solution`)
127
+ - `-i, --ide <ide>`:AI IDE 类型(`vscode`|`cursor`|`codex`|`claude-code`)
128
+ - `-d, --dir <path>`:目标目录(默认为当前目录)
129
+
130
+ **示例**:
131
+ ```bash
132
+ # 基本用法
133
+ acp apply
134
+
135
+ # 指定 IDE
136
+ acp apply --ide cursor
137
+
138
+ # 指定目录
139
+ acp apply --dir ~/my-project
140
+
141
+ # 完整命令
142
+ acp apply --type solution --ide vscode --dir ./project
143
+ ```
144
+
145
+ ## 🛠️ 开发
146
+
147
+ ### 项目结构
148
+
149
+ ```
150
+ acp-cli/
151
+ ├── bin/ # 可执行文件入口
152
+ │ └── acp.js
153
+ ├── src/
154
+ │ ├── commands/ # 命令实现
155
+ │ │ ├── login.ts # 登录命令
156
+ │ │ └── apply.ts # 应用配置命令
157
+ │ ├── api/ # API 客户端
158
+ │ │ └── client.ts
159
+ │ ├── config/ # 配置管理
160
+ │ │ └── token.ts # Token 存储
161
+ │ ├── apply/ # 配置应用
162
+ │ │ └── writer.ts # 文件写入逻辑
163
+ │ ├── utils/ # 工具函数
164
+ │ │ ├── logger.ts # 日志工具
165
+ │ │ ├── ide-mapper.ts # IDE 路径映射
166
+ │ │ └── pagination.ts # 分页工具
167
+ │ ├── types/ # 类型定义
168
+ │ │ └── index.ts
169
+ │ └── index.ts # 主入口
170
+ ├── package.json
171
+ ├── tsconfig.json
172
+ ├── tsup.config.ts
173
+ └── README.md
174
+ ```
175
+
176
+ ### 技术栈
177
+
178
+ - **运行时**:Node.js 18+
179
+ - **语言**:TypeScript 5.x
180
+ - **命令解析**:Commander.js
181
+ - **交互提示**:Inquirer.js
182
+ - **HTTP 客户端**:Axios
183
+ - **终端样式**:Chalk
184
+ - **进度动画**:Ora
185
+ - **文件操作**:fs-extra
186
+ - **构建工具**:tsup
187
+
188
+ ### 开发命令
189
+
190
+ ```bash
191
+ # 安装依赖
192
+ pnpm install
193
+
194
+ # 开发模式(使用 tsx 直接运行)
195
+ pnpm dev
196
+
197
+ # 构建生产版本
198
+ pnpm build
199
+
200
+ # 类型检查
201
+ pnpm typecheck
202
+
203
+ # 运行测试
204
+ pnpm test
205
+ ```
206
+
207
+ ## 🌐 API 服务
208
+
209
+ ACP CLI 连接到 ACP 平台的后端 API 服务:
210
+
211
+ - **Base URL**:`https://acp-hkbpdeenf8dudmfw.eastasia-01.azurewebsites.net`
212
+ - **认证方式**:通过 `X-CLI-TOKEN` HTTP Header 携带 Token
213
+
214
+ ### API 端点
215
+
216
+ - `GET /api/cli/solutions` - 获取解决方案列表
217
+ - `GET /api/cli/solutions/{id}` - 获取解决方案详情
218
+ - `GET /api/cli/agents` - 获取 Agent 配置列表
219
+ - `GET /api/cli/prompts` - 获取 Prompt 列表
220
+ - `GET /api/cli/mcps` - 获取 MCP 配置列表
221
+
222
+ ## 🐛 问题反馈
223
+
224
+ 遇到问题?请提交 Issue:
225
+
226
+ - GitHub Issues: https://github.com/AIConfigPlaza/acp-cli/issues
227
+
228
+ ## 📄 许可证
229
+
230
+ MIT License - 详见 [LICENSE](LICENSE) 文件
231
+
232
+ ---
233
+
234
+ **Made with ❤️ by AIConfigPlaza Team**
package/bin/acp.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../dist/index.js').catch((error) => {
4
+ console.error('启动失败:', error.message)
5
+ process.exit(1)
6
+ })
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,699 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command as Command3 } from "commander";
5
+ import chalk5 from "chalk";
6
+
7
+ // src/commands/login.ts
8
+ import { Command } from "commander";
9
+ import inquirer from "inquirer";
10
+ import chalk2 from "chalk";
11
+
12
+ // src/config/token.ts
13
+ import fs from "fs-extra";
14
+ import path from "path";
15
+ import os from "os";
16
+ var TOKEN_ENV_KEY = "ACP_CLI_TOKEN";
17
+ var CONFIG_DIR = path.join(os.homedir(), ".acp");
18
+ var TOKEN_FILE = path.join(CONFIG_DIR, "token");
19
+ async function getToken() {
20
+ const envToken = process.env[TOKEN_ENV_KEY];
21
+ if (envToken?.trim()) {
22
+ return envToken.trim();
23
+ }
24
+ try {
25
+ if (await fs.pathExists(TOKEN_FILE)) {
26
+ const token = await fs.readFile(TOKEN_FILE, "utf-8");
27
+ return token.trim() || null;
28
+ }
29
+ } catch (error) {
30
+ }
31
+ return null;
32
+ }
33
+ async function saveToken(token) {
34
+ if (!token?.trim()) {
35
+ throw new Error("Token \u4E0D\u80FD\u4E3A\u7A7A");
36
+ }
37
+ await fs.ensureDir(CONFIG_DIR);
38
+ await fs.writeFile(TOKEN_FILE, token.trim(), "utf-8");
39
+ }
40
+ async function isLoggedIn() {
41
+ const token = await getToken();
42
+ return token !== null && token.length > 0;
43
+ }
44
+
45
+ // src/utils/logger.ts
46
+ import chalk from "chalk";
47
+ var symbols = {
48
+ info: "\u2139",
49
+ tick: "\u2713",
50
+ warning: "\u26A0",
51
+ cross: "\u2716",
52
+ arrowRight: "\u2192"
53
+ };
54
+ var logger = {
55
+ /**
56
+ * 普通信息
57
+ */
58
+ info: (message) => {
59
+ console.log(chalk.blue(symbols.info) + " " + message);
60
+ },
61
+ /**
62
+ * 成功信息
63
+ */
64
+ success: (message) => {
65
+ console.log(chalk.green(symbols.tick) + " " + chalk.green(message));
66
+ },
67
+ /**
68
+ * 警告信息
69
+ */
70
+ warning: (message) => {
71
+ console.log(chalk.yellow(symbols.warning) + " " + chalk.yellow(message));
72
+ },
73
+ /**
74
+ * 错误信息
75
+ */
76
+ error: (message) => {
77
+ console.error(chalk.red(symbols.cross) + " " + chalk.red(message));
78
+ },
79
+ /**
80
+ * 步骤信息
81
+ */
82
+ step: (message) => {
83
+ console.log(chalk.cyan(symbols.arrowRight) + " " + chalk.gray(message));
84
+ },
85
+ /**
86
+ * 标题
87
+ */
88
+ title: (message) => {
89
+ console.log("\n" + chalk.bold.underline(message) + "\n");
90
+ },
91
+ /**
92
+ * 普通文本(无图标)
93
+ */
94
+ log: (message) => {
95
+ console.log(message);
96
+ }
97
+ };
98
+ var CLIError = class extends Error {
99
+ constructor(message, code, suggestions) {
100
+ super(message);
101
+ this.code = code;
102
+ this.suggestions = suggestions;
103
+ this.name = "CLIError";
104
+ }
105
+ };
106
+ function handleError(error) {
107
+ console.error();
108
+ if (error instanceof CLIError) {
109
+ logger.error(error.message);
110
+ if (error.code) {
111
+ console.log(chalk.gray(`\u9519\u8BEF\u4EE3\u7801: ${error.code}`));
112
+ }
113
+ if (error.suggestions?.length) {
114
+ console.log(chalk.yellow.bold("\n\u{1F4A1} \u5EFA\u8BAE:\n"));
115
+ error.suggestions.forEach((suggestion, index) => {
116
+ console.log(chalk.gray(` ${index + 1}. ${suggestion}`));
117
+ });
118
+ }
119
+ } else if (error instanceof Error) {
120
+ logger.error(error.message);
121
+ if (process.env.DEBUG) {
122
+ console.log(chalk.gray("\n" + error.stack));
123
+ }
124
+ } else {
125
+ logger.error("\u672A\u77E5\u9519\u8BEF");
126
+ }
127
+ console.log(
128
+ chalk.gray("\n\u9700\u8981\u5E2E\u52A9? \u8BBF\u95EE: ") + chalk.blue.underline("https://github.com/AIConfigPlaza/acp-cli")
129
+ );
130
+ console.log();
131
+ }
132
+
133
+ // src/commands/login.ts
134
+ var loginCommand = new Command("login").description("\u767B\u5F55 ACP CLI\uFF0C\u4FDD\u5B58\u8BBF\u95EE\u4EE4\u724C").action(async () => {
135
+ try {
136
+ logger.title("\u{1F510} ACP CLI \u767B\u5F55");
137
+ const existingToken = await getToken();
138
+ if (existingToken) {
139
+ const { overwrite } = await inquirer.prompt([
140
+ {
141
+ type: "confirm",
142
+ name: "overwrite",
143
+ message: "\u68C0\u6D4B\u5230\u5DF2\u767B\u5F55\uFF0C\u662F\u5426\u91CD\u65B0\u767B\u5F55?",
144
+ default: false
145
+ }
146
+ ]);
147
+ if (!overwrite) {
148
+ logger.info("\u5DF2\u53D6\u6D88\u767B\u5F55");
149
+ return;
150
+ }
151
+ }
152
+ const { token } = await inquirer.prompt([
153
+ {
154
+ type: "password",
155
+ name: "token",
156
+ message: "\u8BF7\u8F93\u5165 CLI Token:",
157
+ validate: (input) => {
158
+ if (!input.trim()) {
159
+ return "Token \u4E0D\u80FD\u4E3A\u7A7A";
160
+ }
161
+ if (input.trim().length < 10) {
162
+ return "Token \u683C\u5F0F\u4E0D\u6B63\u786E\uFF08\u81F3\u5C11 10 \u4E2A\u5B57\u7B26\uFF09";
163
+ }
164
+ return true;
165
+ },
166
+ mask: "*"
167
+ }
168
+ ]);
169
+ await saveToken(token);
170
+ logger.success("\u767B\u5F55\u6210\u529F\uFF01Token \u5DF2\u4FDD\u5B58\u5230 ~/.acp/token");
171
+ console.log(chalk2.gray("\n\u63D0\u793A: \u73B0\u5728\u53EF\u4EE5\u4F7F\u7528 acp apply \u547D\u4EE4\u62C9\u53D6\u914D\u7F6E\n"));
172
+ } catch (error) {
173
+ if (error instanceof Error) {
174
+ logger.error(`\u767B\u5F55\u5931\u8D25: ${error.message}`);
175
+ }
176
+ process.exit(1);
177
+ }
178
+ });
179
+
180
+ // src/commands/apply.ts
181
+ import { Command as Command2 } from "commander";
182
+ import inquirer3 from "inquirer";
183
+ import chalk4 from "chalk";
184
+ import ora from "ora";
185
+
186
+ // src/api/client.ts
187
+ import axios from "axios";
188
+ var BASE_URL = "https://acp-hkbpdeenf8dudmfw.eastasia-01.azurewebsites.net";
189
+ var ApiClient = class {
190
+ client;
191
+ constructor() {
192
+ this.client = axios.create({
193
+ baseURL: BASE_URL,
194
+ timeout: 3e4,
195
+ headers: {
196
+ "Content-Type": "application/json"
197
+ }
198
+ });
199
+ this.client.interceptors.request.use(async (config) => {
200
+ const token = await getToken();
201
+ if (token) {
202
+ config.headers["X-CLI-TOKEN"] = token;
203
+ }
204
+ return config;
205
+ });
206
+ this.client.interceptors.response.use(
207
+ (response) => response,
208
+ (error) => {
209
+ if (error.response) {
210
+ const status = error.response.status;
211
+ const message = error.response.data?.message || error.message;
212
+ if (status === 401) {
213
+ throw new Error("\u8BA4\u8BC1\u5931\u8D25\uFF0C\u8BF7\u5148\u6267\u884C acp login \u767B\u5F55");
214
+ } else if (status === 403) {
215
+ throw new Error("\u6743\u9650\u4E0D\u8DB3\uFF0C\u8BF7\u68C0\u67E5 token \u662F\u5426\u6709\u6548");
216
+ } else if (status === 404) {
217
+ throw new Error("\u8BF7\u6C42\u7684\u8D44\u6E90\u4E0D\u5B58\u5728");
218
+ } else if (status >= 500) {
219
+ throw new Error(`\u670D\u52A1\u5668\u9519\u8BEF (${status}): ${message}`);
220
+ } else {
221
+ throw new Error(`\u8BF7\u6C42\u5931\u8D25 (${status}): ${message}`);
222
+ }
223
+ } else if (error.request) {
224
+ throw new Error("\u7F51\u7EDC\u9519\u8BEF\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5");
225
+ } else {
226
+ throw new Error(`\u8BF7\u6C42\u914D\u7F6E\u9519\u8BEF: ${error.message}`);
227
+ }
228
+ }
229
+ );
230
+ }
231
+ /**
232
+ * 获取解决方案列表
233
+ */
234
+ async getSolutions(aiTool) {
235
+ const params = aiTool ? { aiTool } : {};
236
+ const response = await this.client.get(
237
+ "/api/cli/solutions",
238
+ { params }
239
+ );
240
+ return response.data;
241
+ }
242
+ /**
243
+ * 获取解决方案详情
244
+ */
245
+ async getSolutionById(id) {
246
+ const response = await this.client.get(
247
+ `/api/cli/solutions/${id}`
248
+ );
249
+ return response.data;
250
+ }
251
+ /**
252
+ * 获取 Agent 配置列表
253
+ */
254
+ async getAgents() {
255
+ const response = await this.client.get(
256
+ "/api/cli/agents"
257
+ );
258
+ return response.data;
259
+ }
260
+ /**
261
+ * 获取 Agent 配置详情
262
+ */
263
+ async getAgentById(id) {
264
+ const response = await this.client.get(
265
+ `/api/cli/agents/${id}`
266
+ );
267
+ return response.data;
268
+ }
269
+ /**
270
+ * 获取 Prompt 列表
271
+ */
272
+ async getPrompts() {
273
+ const response = await this.client.get(
274
+ "/api/cli/prompts"
275
+ );
276
+ return response.data;
277
+ }
278
+ /**
279
+ * 获取 Prompt 详情
280
+ */
281
+ async getPromptById(id) {
282
+ const response = await this.client.get(
283
+ `/api/cli/prompts/${id}`
284
+ );
285
+ return response.data;
286
+ }
287
+ /**
288
+ * 获取 MCP 配置列表
289
+ */
290
+ async getMcps() {
291
+ const response = await this.client.get(
292
+ "/api/cli/mcps"
293
+ );
294
+ return response.data;
295
+ }
296
+ /**
297
+ * 获取 MCP 配置详情
298
+ */
299
+ async getMcpById(id) {
300
+ const response = await this.client.get(
301
+ `/api/cli/mcps/${id}`
302
+ );
303
+ return response.data;
304
+ }
305
+ };
306
+ var apiClient = new ApiClient();
307
+
308
+ // src/utils/pagination.ts
309
+ function paginate(items, options) {
310
+ const { page, pageSize } = options;
311
+ const total = items.length;
312
+ const totalPages = Math.ceil(total / pageSize);
313
+ const startIndex = (page - 1) * pageSize;
314
+ const endIndex = startIndex + pageSize;
315
+ return {
316
+ items: items.slice(startIndex, endIndex),
317
+ total,
318
+ page,
319
+ pageSize,
320
+ totalPages,
321
+ hasNext: page < totalPages,
322
+ hasPrev: page > 1
323
+ };
324
+ }
325
+ function searchByName(items, query) {
326
+ if (!query.trim()) {
327
+ return items;
328
+ }
329
+ const lowerQuery = query.toLowerCase().trim();
330
+ return items.filter(
331
+ (item) => item.name.toLowerCase().includes(lowerQuery)
332
+ );
333
+ }
334
+
335
+ // src/apply/writer.ts
336
+ import fs2 from "fs-extra";
337
+ import path2 from "path";
338
+ import chalk3 from "chalk";
339
+ import inquirer2 from "inquirer";
340
+
341
+ // src/utils/ide-mapper.ts
342
+ var IDE_PATH_MAPPINGS = {
343
+ vscode: {
344
+ prompts: ".github/prompts",
345
+ agents: "AGENTS.md",
346
+ mcp: ".vscode/mcp.json"
347
+ },
348
+ cursor: {
349
+ prompts: ".cursor/prompts",
350
+ agents: "AGENTS.md",
351
+ mcp: ".cursor/mcp.json"
352
+ },
353
+ codex: {
354
+ prompts: ".codex/prompts",
355
+ agents: "AGENTS.md",
356
+ mcp: ".codex/config.toml"
357
+ },
358
+ "claude-code": {
359
+ prompts: ".claude/prompts",
360
+ agents: "AGENTS.md",
361
+ mcp: ".mcp.json"
362
+ }
363
+ };
364
+ function getIdePathMapping(ide) {
365
+ return IDE_PATH_MAPPINGS[ide];
366
+ }
367
+
368
+ // src/apply/writer.ts
369
+ async function applySolution(solution, options) {
370
+ const { ide, targetDir } = options;
371
+ const pathMapping = getIdePathMapping(ide);
372
+ logger.title(`\u{1F4E6} \u5E94\u7528\u89E3\u51B3\u65B9\u6848: ${chalk3.cyan(solution.name)}`);
373
+ if (solution.agentConfig) {
374
+ await applyAgentConfig(
375
+ solution.agentConfig.content,
376
+ pathMapping.agents,
377
+ targetDir
378
+ );
379
+ }
380
+ if (solution.customPrompts?.length) {
381
+ await applyPrompts(
382
+ solution.customPrompts,
383
+ pathMapping.prompts,
384
+ targetDir
385
+ );
386
+ }
387
+ if (solution.mcpConfigs?.length) {
388
+ await applyMcpConfigs(
389
+ solution.mcpConfigs,
390
+ pathMapping.mcp,
391
+ targetDir
392
+ );
393
+ }
394
+ logger.success(`
395
+ \u2728 \u89E3\u51B3\u65B9\u6848 ${chalk3.cyan(solution.name)} \u5E94\u7528\u6210\u529F\uFF01`);
396
+ }
397
+ async function applyAgentConfig(content, relativePath, targetDir) {
398
+ const filePath = path2.join(targetDir, relativePath);
399
+ logger.step(`\u5199\u5165 Agent \u914D\u7F6E: ${chalk3.gray(relativePath)}`);
400
+ const exists = await fs2.pathExists(filePath);
401
+ if (exists) {
402
+ const { overwrite } = await inquirer2.prompt([
403
+ {
404
+ type: "confirm",
405
+ name: "overwrite",
406
+ message: `\u6587\u4EF6 ${chalk3.cyan(relativePath)} \u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6?`,
407
+ default: true
408
+ }
409
+ ]);
410
+ if (!overwrite) {
411
+ logger.warning(`\u8DF3\u8FC7: ${relativePath}`);
412
+ return;
413
+ }
414
+ }
415
+ await fs2.ensureDir(path2.dirname(filePath));
416
+ await fs2.writeFile(filePath, content, "utf-8");
417
+ logger.success(`\u5DF2\u5199\u5165: ${relativePath}`);
418
+ }
419
+ async function applyPrompts(prompts, promptsDir, targetDir) {
420
+ const fullPromptsDir = path2.join(targetDir, promptsDir);
421
+ logger.step(`\u5199\u5165 ${prompts.length} \u4E2A Prompt \u914D\u7F6E\u5230: ${chalk3.gray(promptsDir)}`);
422
+ await fs2.ensureDir(fullPromptsDir);
423
+ for (const prompt of prompts) {
424
+ const fileName = sanitizeFileName(prompt.name) + ".prompt.md";
425
+ const filePath = path2.join(fullPromptsDir, fileName);
426
+ const exists = await fs2.pathExists(filePath);
427
+ if (exists) {
428
+ const { overwrite } = await inquirer2.prompt([
429
+ {
430
+ type: "confirm",
431
+ name: "overwrite",
432
+ message: `Prompt ${chalk3.cyan(fileName)} \u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6?`,
433
+ default: true
434
+ }
435
+ ]);
436
+ if (!overwrite) {
437
+ logger.warning(`\u8DF3\u8FC7: ${fileName}`);
438
+ continue;
439
+ }
440
+ }
441
+ await fs2.writeFile(filePath, prompt.content, "utf-8");
442
+ logger.success(`\u5DF2\u5199\u5165: ${path2.join(promptsDir, fileName)}`);
443
+ }
444
+ }
445
+ async function applyMcpConfigs(mcpConfigs, mcpFile, targetDir) {
446
+ const filePath = path2.join(targetDir, mcpFile);
447
+ logger.step(`\u5199\u5165 MCP \u914D\u7F6E: ${chalk3.gray(mcpFile)}`);
448
+ const mcpServers = {};
449
+ for (const mcpConfig of mcpConfigs) {
450
+ try {
451
+ const config = JSON.parse(mcpConfig.configJson);
452
+ mcpServers[mcpConfig.name] = config;
453
+ } catch (error) {
454
+ logger.warning(`MCP \u914D\u7F6E ${mcpConfig.name} \u683C\u5F0F\u9519\u8BEF\uFF0C\u5DF2\u8DF3\u8FC7`);
455
+ }
456
+ }
457
+ const exists = await fs2.pathExists(filePath);
458
+ if (exists) {
459
+ const { overwrite } = await inquirer2.prompt([
460
+ {
461
+ type: "confirm",
462
+ name: "overwrite",
463
+ message: `\u6587\u4EF6 ${chalk3.cyan(mcpFile)} \u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6?`,
464
+ default: true
465
+ }
466
+ ]);
467
+ if (!overwrite) {
468
+ logger.warning(`\u8DF3\u8FC7: ${mcpFile}`);
469
+ return;
470
+ }
471
+ }
472
+ await fs2.ensureDir(path2.dirname(filePath));
473
+ if (mcpFile.endsWith(".toml")) {
474
+ const tomlContent = convertMcpToToml(mcpServers);
475
+ await fs2.writeFile(filePath, tomlContent, "utf-8");
476
+ } else {
477
+ let mergedConfig;
478
+ if (mcpFile.includes(".vscode")) {
479
+ mergedConfig = {
480
+ servers: mcpServers
481
+ };
482
+ } else {
483
+ mergedConfig = {
484
+ mcpServers
485
+ };
486
+ }
487
+ await fs2.writeFile(filePath, JSON.stringify(mergedConfig, null, 2), "utf-8");
488
+ }
489
+ logger.success(`\u5DF2\u5199\u5165: ${mcpFile}`);
490
+ }
491
+ function convertMcpToToml(mcpServers) {
492
+ let tomlContent = "";
493
+ for (const [serverName, config] of Object.entries(mcpServers)) {
494
+ tomlContent += `[mcp_servers.${serverName}]
495
+ `;
496
+ if (config.command) {
497
+ tomlContent += `command = ${JSON.stringify(config.command)}
498
+ `;
499
+ }
500
+ if (config.args && Array.isArray(config.args)) {
501
+ const argsStr = config.args.map((arg) => JSON.stringify(arg)).join(", ");
502
+ tomlContent += `args = [${argsStr}]
503
+ `;
504
+ }
505
+ if (config.env && typeof config.env === "object") {
506
+ const envEntries = Object.entries(config.env);
507
+ if (envEntries.length > 0) {
508
+ const envStr = envEntries.map(([key, value]) => `${key} = ${JSON.stringify(value)}`).join(", ");
509
+ tomlContent += `env = { ${envStr} }
510
+ `;
511
+ }
512
+ }
513
+ tomlContent += "\n";
514
+ }
515
+ return tomlContent;
516
+ }
517
+ function sanitizeFileName(name) {
518
+ return name.replace(/[<>:"/\\|?*]/g, "-").replace(/\s+/g, "-").replace(/-+/g, "-").toLowerCase();
519
+ }
520
+
521
+ // src/commands/apply.ts
522
+ var applyCommand = new Command2("apply").description("\u62C9\u53D6\u5E76\u5E94\u7528\u914D\u7F6E\u5230\u672C\u5730\u9879\u76EE").option("-t, --type <type>", "\u8D44\u6E90\u7C7B\u578B (solution|agent|prompt|mcp)", "solution").option("-i, --ide <ide>", "AI IDE \u7C7B\u578B (vscode|cursor|codex|claude-code)").option("-d, --dir <path>", "\u76EE\u6807\u76EE\u5F55", process.cwd()).action(async (options) => {
523
+ try {
524
+ if (!await isLoggedIn()) {
525
+ throw new CLIError(
526
+ "\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u6267\u884C acp login",
527
+ "NOT_LOGGED_IN",
528
+ ["\u8FD0\u884C acp login \u547D\u4EE4\u767B\u5F55"]
529
+ );
530
+ }
531
+ logger.title("\u{1F680} ACP \u914D\u7F6E\u5E94\u7528");
532
+ const resourceType = await selectResourceType(options.type);
533
+ let selectedSolution = null;
534
+ if (resourceType === "solution") {
535
+ selectedSolution = await fetchAndSelectSolution();
536
+ } else {
537
+ throw new CLIError("\u6682\u4E0D\u652F\u6301\u72EC\u7ACB\u5E94\u7528 agent/prompt/mcp\uFF0C\u8BF7\u4F7F\u7528 solution \u7C7B\u578B");
538
+ }
539
+ if (!selectedSolution) {
540
+ logger.info("\u672A\u9009\u62E9\u4EFB\u4F55\u914D\u7F6E");
541
+ return;
542
+ }
543
+ const ide = options.ide || await selectIde();
544
+ await applySolution(selectedSolution, {
545
+ ide,
546
+ targetDir: options.dir
547
+ });
548
+ console.log(chalk4.gray(`
549
+ \u914D\u7F6E\u5DF2\u5E94\u7528\u5230: ${chalk4.cyan(options.dir)}
550
+ `));
551
+ } catch (error) {
552
+ if (error instanceof Error) {
553
+ logger.error(error.message);
554
+ }
555
+ process.exit(1);
556
+ }
557
+ });
558
+ async function selectResourceType(defaultType) {
559
+ if (defaultType && ["solution", "agent", "prompt", "mcp"].includes(defaultType)) {
560
+ return defaultType;
561
+ }
562
+ const { type } = await inquirer3.prompt([
563
+ {
564
+ type: "list",
565
+ name: "type",
566
+ message: "\u8BF7\u9009\u62E9\u8D44\u6E90\u7C7B\u578B:",
567
+ choices: [
568
+ { name: chalk4.cyan("\u89E3\u51B3\u65B9\u6848 (Solution)"), value: "solution" },
569
+ { name: chalk4.gray("Agent \u914D\u7F6E (\u6682\u4E0D\u652F\u6301)"), value: "agent", disabled: true },
570
+ { name: chalk4.gray("Prompt (\u6682\u4E0D\u652F\u6301)"), value: "prompt", disabled: true },
571
+ { name: chalk4.gray("MCP \u914D\u7F6E (\u6682\u4E0D\u652F\u6301)"), value: "mcp", disabled: true }
572
+ ],
573
+ default: "solution"
574
+ }
575
+ ]);
576
+ return type;
577
+ }
578
+ async function fetchAndSelectSolution() {
579
+ const spinner = ora("\u6B63\u5728\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u5217\u8868...").start();
580
+ try {
581
+ const response = await apiClient.getSolutions();
582
+ spinner.stop();
583
+ if (!response.data || response.data.length === 0) {
584
+ logger.warning("\u6682\u65E0\u53EF\u7528\u7684\u89E3\u51B3\u65B9\u6848");
585
+ return null;
586
+ }
587
+ logger.success(`\u83B7\u53D6\u5230 ${response.data.length} \u4E2A\u89E3\u51B3\u65B9\u6848`);
588
+ const { searchQuery } = await inquirer3.prompt([
589
+ {
590
+ type: "input",
591
+ name: "searchQuery",
592
+ message: "\u641C\u7D22\u89E3\u51B3\u65B9\u6848 (\u6309\u540D\u79F0\u641C\u7D22\uFF0C\u7559\u7A7A\u663E\u793A\u5168\u90E8):",
593
+ default: ""
594
+ }
595
+ ]);
596
+ let filteredSolutions = searchByName(response.data, searchQuery);
597
+ if (filteredSolutions.length === 0) {
598
+ logger.warning("\u672A\u627E\u5230\u5339\u914D\u7684\u89E3\u51B3\u65B9\u6848");
599
+ return null;
600
+ }
601
+ const PAGE_SIZE = 20;
602
+ let currentPage = 1;
603
+ let selectedSolution = null;
604
+ while (!selectedSolution) {
605
+ const paginatedResult = paginate(filteredSolutions, {
606
+ page: currentPage,
607
+ pageSize: PAGE_SIZE
608
+ });
609
+ const choices = paginatedResult.items.map((solution) => ({
610
+ name: `${chalk4.cyan(solution.name)} - ${chalk4.gray(solution.description)}`,
611
+ value: solution.id,
612
+ short: solution.name
613
+ }));
614
+ if (paginatedResult.hasNext) {
615
+ choices.push({
616
+ name: chalk4.yellow(">>> \u4E0B\u4E00\u9875"),
617
+ value: "__NEXT_PAGE__",
618
+ short: "\u4E0B\u4E00\u9875"
619
+ });
620
+ }
621
+ if (paginatedResult.hasPrev) {
622
+ choices.unshift({
623
+ name: chalk4.yellow("<<< \u4E0A\u4E00\u9875"),
624
+ value: "__PREV_PAGE__",
625
+ short: "\u4E0A\u4E00\u9875"
626
+ });
627
+ }
628
+ choices.push({
629
+ name: chalk4.red("\u53D6\u6D88"),
630
+ value: "__CANCEL__",
631
+ short: "\u53D6\u6D88"
632
+ });
633
+ const { selected } = await inquirer3.prompt([
634
+ {
635
+ type: "list",
636
+ name: "selected",
637
+ message: `\u9009\u62E9\u89E3\u51B3\u65B9\u6848 (\u7B2C ${currentPage}/${paginatedResult.totalPages} \u9875):`,
638
+ choices,
639
+ pageSize: 15
640
+ }
641
+ ]);
642
+ if (selected === "__CANCEL__") {
643
+ return null;
644
+ } else if (selected === "__NEXT_PAGE__") {
645
+ currentPage++;
646
+ } else if (selected === "__PREV_PAGE__") {
647
+ currentPage--;
648
+ } else {
649
+ const detailSpinner = ora("\u6B63\u5728\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u8BE6\u60C5...").start();
650
+ const detailResponse = await apiClient.getSolutionById(selected);
651
+ detailSpinner.stop();
652
+ selectedSolution = detailResponse.data;
653
+ }
654
+ }
655
+ return selectedSolution;
656
+ } catch (error) {
657
+ spinner.fail("\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u5931\u8D25");
658
+ throw error;
659
+ }
660
+ }
661
+ async function selectIde() {
662
+ const { ide } = await inquirer3.prompt([
663
+ {
664
+ type: "list",
665
+ name: "ide",
666
+ message: "\u8BF7\u9009\u62E9 AI IDE \u7C7B\u578B:",
667
+ choices: [
668
+ { name: chalk4.cyan("VS Code"), value: "vscode" },
669
+ { name: chalk4.cyan("Cursor"), value: "cursor" },
670
+ { name: chalk4.cyan("Codex"), value: "codex" },
671
+ { name: chalk4.cyan("Claude Code"), value: "claude-code" }
672
+ ],
673
+ default: "vscode"
674
+ }
675
+ ]);
676
+ return ide;
677
+ }
678
+
679
+ // src/index.ts
680
+ var program = new Command3();
681
+ program.name("acp").description(
682
+ chalk5.gray("AI-Config-Plaza CLI - \u7EDF\u4E00 AI \u7F16\u7A0B\u5DE5\u5177\u914D\u7F6E\u7BA1\u7406")
683
+ ).version("1.0.0", "-v, --version", "\u663E\u793A\u7248\u672C\u53F7").helpOption("-h, --help", "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");
684
+ program.addCommand(loginCommand);
685
+ program.addCommand(applyCommand);
686
+ program.on("--help", () => {
687
+ console.log(chalk5.bold("\n\u793A\u4F8B:\n"));
688
+ console.log(chalk5.gray(" $ acp login"));
689
+ console.log(chalk5.gray(" $ acp apply"));
690
+ console.log(chalk5.gray(" $ acp apply --ide vscode --dir ./my-project"));
691
+ console.log();
692
+ });
693
+ try {
694
+ await program.parseAsync(process.argv);
695
+ } catch (error) {
696
+ handleError(error);
697
+ process.exit(1);
698
+ }
699
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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 } 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 // 检查是否已有 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 配置管理\r\n * 优先级: 环境变量 > ~/.acp/token 文件\r\n */\r\n\r\nconst TOKEN_ENV_KEY = 'ACP_CLI_TOKEN'\r\nconst CONFIG_DIR = path.join(os.homedir(), '.acp')\r\nconst TOKEN_FILE = path.join(CONFIG_DIR, 'token')\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","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 } 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\nconst BASE_URL = 'https://acp-hkbpdeenf8dudmfw.eastasia-01.azurewebsites.net'\r\n\r\nclass ApiClient {\r\n private client: AxiosInstance\r\n\r\n constructor() {\r\n this.client = axios.create({\r\n baseURL: BASE_URL,\r\n timeout: 30000,\r\n headers: {\r\n 'Content-Type': 'application/json'\r\n }\r\n })\r\n\r\n // 请求拦截器:自动添加 token\r\n this.client.interceptors.request.use(async (config) => {\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"]}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@ai-config-plaza/acp-cli",
3
+ "version": "1.0.0",
4
+ "description": "AI-Config-Plaza CLI 工具 - 统一 AI 编程工具配置管理",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "acp": "./bin/acp.js"
10
+ },
11
+ "files": [
12
+ "bin",
13
+ "dist",
14
+ "README.md",
15
+ "LICENSE"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/AIConfigPlaza/acp-cli.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/AIConfigPlaza/acp-cli/issues"
23
+ },
24
+ "homepage": "https://github.com/AIConfigPlaza/acp-cli#readme",
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "registry": "https://registry.npmjs.org/"
28
+ },
29
+ "scripts": {
30
+ "dev": "tsx src/index.ts",
31
+ "build": "tsup src/index.ts --format esm --dts --clean",
32
+ "start": "node bin/acp.js",
33
+ "typecheck": "tsc --noEmit",
34
+ "lint": "eslint .",
35
+ "test": "vitest",
36
+ "prepublishOnly": "pnpm build && pnpm typecheck"
37
+ },
38
+ "keywords": [
39
+ "cli",
40
+ "ai",
41
+ "config",
42
+ "scaffolding",
43
+ "mcp",
44
+ "prompt"
45
+ ],
46
+ "author": "AIConfigPlaza",
47
+ "license": "MIT",
48
+ "engines": {
49
+ "node": ">=18.0.0"
50
+ },
51
+ "dependencies": {
52
+ "commander": "^12.1.0",
53
+ "inquirer": "^10.2.2",
54
+ "axios": "^1.7.7",
55
+ "chalk": "^5.3.0",
56
+ "ora": "^8.1.0",
57
+ "fs-extra": "^11.2.0",
58
+ "cosmiconfig": "^9.0.0"
59
+ },
60
+ "devDependencies": {
61
+ "@types/fs-extra": "^11.0.4",
62
+ "@types/inquirer": "^9.0.7",
63
+ "@types/node": "^22.8.4",
64
+ "tsup": "^8.3.0",
65
+ "tsx": "^4.19.1",
66
+ "typescript": "^5.6.3",
67
+ "vitest": "^2.1.3"
68
+ }
69
+ }