@ai-config-plaza/acp-cli 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,6 +12,7 @@ ACP CLI 是一个专为简化 AI 编程工具配置而设计的命令行工具
12
12
  - 📦 **一键应用**:快速拉取并应用配置到本地项目
13
13
  - 🔍 **智能搜索**:支持按名称搜索和分页浏览配置
14
14
  - 🎨 **多 IDE 支持**:自动适配不同 AI IDE 的配置路径
15
+ - 🌐 **多语言支持**:支持中文和英文界面切换
15
16
  - ✨ **友好交互**:清晰的终端提示和进度反馈
16
17
 
17
18
  ## 🚀 快速开始
@@ -87,6 +88,33 @@ acp apply --ide cursor --dir ~/projects/my-app
87
88
  5. **选择 IDE**:选择目标 AI IDE 类型
88
89
  6. **确认覆盖**:如果文件已存在,会提示是否覆盖
89
90
 
91
+ ### 4. 切换语言
92
+
93
+ ACP CLI 支持中文和英文界面:
94
+
95
+ ```bash
96
+ # 打开语言设置
97
+ acp locale
98
+ ```
99
+
100
+ 或通过环境变量临时设置:
101
+
102
+ ```bash
103
+ # Windows PowerShell
104
+ $env:ACP_CLI_LOCALE = "en-US"
105
+ acp apply
106
+
107
+ # Linux/macOS
108
+ export ACP_CLI_LOCALE=en-US
109
+ acp apply
110
+ ```
111
+
112
+ 支持的语言代码:
113
+ - `zh-CN`:简体中文(默认)
114
+ - `en-US`:English
115
+
116
+ 详细文档:[多语言支持文档](docs/i18n.md)
117
+
90
118
  ## 📁 配置输出路径
91
119
 
92
120
  不同 AI IDE 的配置文件输出路径:
@@ -142,6 +170,20 @@ acp apply --dir ~/my-project
142
170
  acp apply --type solution --ide vscode --dir ./project
143
171
  ```
144
172
 
173
+ ### `acp locale`
174
+
175
+ 切换 CLI 界面语言。
176
+
177
+ **示例**:
178
+ ```bash
179
+ # 打开语言选择菜单
180
+ acp locale
181
+ ```
182
+
183
+ **支持的语言**:
184
+ - `zh-CN`:简体中文
185
+ - `en-US`:English
186
+
145
187
  ## 🛠️ 开发
146
188
 
147
189
  ### 项目结构
@@ -153,11 +195,17 @@ acp-cli/
153
195
  ├── src/
154
196
  │ ├── commands/ # 命令实现
155
197
  │ │ ├── login.ts # 登录命令
156
- │ │ └── apply.ts # 应用配置命令
198
+ │ │ ├── apply.ts # 应用配置命令
199
+ │ │ └── locale.ts # 语言切换命令
157
200
  │ ├── api/ # API 客户端
158
201
  │ │ └── client.ts
159
202
  │ ├── config/ # 配置管理
160
- │ │ └── token.ts # Token 存储
203
+ │ │ ├── token.ts # Token 存储
204
+ │ │ └── locale.ts # 语言配置
205
+ │ ├── i18n/ # 国际化
206
+ │ │ ├── index.ts # i18n 工具函数
207
+ │ │ ├── zh-CN.ts # 中文语言包
208
+ │ │ └── en-US.ts # 英文语言包
161
209
  │ ├── apply/ # 配置应用
162
210
  │ │ └── writer.ts # 文件写入逻辑
163
211
  │ ├── utils/ # 工具函数
@@ -167,6 +215,8 @@ acp-cli/
167
215
  │ ├── types/ # 类型定义
168
216
  │ │ └── index.ts
169
217
  │ └── index.ts # 主入口
218
+ ├── docs/ # 文档
219
+ │ └── i18n.md # 多语言支持文档
170
220
  ├── package.json
171
221
  ├── tsconfig.json
172
222
  ├── tsup.config.ts
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command3 } from "commander";
5
- import chalk5 from "chalk";
4
+ import { Command as Command4 } from "commander";
5
+ import chalk6 from "chalk";
6
6
 
7
7
  // src/commands/login.ts
8
8
  import { Command } from "commander";
@@ -81,6 +81,290 @@ async function initDefaultConfig() {
81
81
 
82
82
  // src/utils/logger.ts
83
83
  import chalk from "chalk";
84
+
85
+ // src/config/locale.ts
86
+ import fs2 from "fs-extra";
87
+ import path2 from "path";
88
+ import os2 from "os";
89
+ var LOCALE_ENV_KEY = "ACP_CLI_LOCALE";
90
+ var DEFAULT_LOCALE = "zh-CN";
91
+ var CONFIG_DIR2 = path2.join(os2.homedir(), ".acp");
92
+ var LOCALE_FILE = path2.join(CONFIG_DIR2, "locale");
93
+ async function getLocale() {
94
+ const envLocale = process.env[LOCALE_ENV_KEY];
95
+ if (envLocale && isValidLocale(envLocale)) {
96
+ return envLocale;
97
+ }
98
+ try {
99
+ if (await fs2.pathExists(LOCALE_FILE)) {
100
+ const locale = (await fs2.readFile(LOCALE_FILE, "utf-8")).trim();
101
+ if (isValidLocale(locale)) {
102
+ return locale;
103
+ }
104
+ }
105
+ } catch (error) {
106
+ }
107
+ return DEFAULT_LOCALE;
108
+ }
109
+ async function saveLocale(locale) {
110
+ if (!isValidLocale(locale)) {
111
+ throw new Error(`\u4E0D\u652F\u6301\u7684\u8BED\u8A00: ${locale}`);
112
+ }
113
+ await fs2.ensureDir(CONFIG_DIR2);
114
+ await fs2.writeFile(LOCALE_FILE, locale, "utf-8");
115
+ }
116
+ function isValidLocale(locale) {
117
+ return locale === "zh-CN" || locale === "en-US";
118
+ }
119
+ function getSupportedLocales() {
120
+ return ["zh-CN", "en-US"];
121
+ }
122
+ function getLocaleName(locale) {
123
+ const names = {
124
+ "zh-CN": "\u7B80\u4F53\u4E2D\u6587",
125
+ "en-US": "English"
126
+ };
127
+ return names[locale];
128
+ }
129
+
130
+ // src/i18n/zh-CN.ts
131
+ var zhCN = {
132
+ // 通用
133
+ common: {
134
+ confirm: "\u786E\u8BA4",
135
+ cancel: "\u53D6\u6D88",
136
+ yes: "\u662F",
137
+ no: "\u5426",
138
+ success: "\u6210\u529F",
139
+ failed: "\u5931\u8D25",
140
+ error: "\u9519\u8BEF",
141
+ warning: "\u8B66\u544A",
142
+ info: "\u63D0\u793A"
143
+ },
144
+ // CLI 主程序
145
+ cli: {
146
+ name: "acp",
147
+ description: "AI-Config-Plaza CLI - \u7EDF\u4E00 AI \u7F16\u7A0B\u5DE5\u5177\u914D\u7F6E\u7BA1\u7406",
148
+ version: "\u663E\u793A\u7248\u672C\u53F7",
149
+ help: "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F",
150
+ exampleTitle: "\u793A\u4F8B:"
151
+ },
152
+ // login 命令
153
+ login: {
154
+ command: "login",
155
+ description: "\u767B\u5F55 ACP CLI\uFF0C\u4FDD\u5B58\u8BBF\u95EE\u4EE4\u724C",
156
+ title: "\u{1F510} ACP CLI \u767B\u5F55",
157
+ alreadyLoggedIn: "\u68C0\u6D4B\u5230\u5DF2\u767B\u5F55\uFF0C\u662F\u5426\u91CD\u65B0\u767B\u5F55?",
158
+ cancelled: "\u5DF2\u53D6\u6D88\u767B\u5F55",
159
+ inputToken: "\u8BF7\u8F93\u5165 CLI Token:",
160
+ tokenEmpty: "Token \u4E0D\u80FD\u4E3A\u7A7A",
161
+ tokenInvalid: "Token \u683C\u5F0F\u4E0D\u6B63\u786E\uFF08\u81F3\u5C11 10 \u4E2A\u5B57\u7B26\uFF09",
162
+ success: "\u767B\u5F55\u6210\u529F\uFF01Token \u5DF2\u4FDD\u5B58\u5230 ~/.acp/token",
163
+ hint: "\u63D0\u793A: \u73B0\u5728\u53EF\u4EE5\u4F7F\u7528 acp apply \u547D\u4EE4\u62C9\u53D6\u914D\u7F6E",
164
+ failed: "\u767B\u5F55\u5931\u8D25"
165
+ },
166
+ // apply 命令
167
+ apply: {
168
+ command: "apply",
169
+ description: "\u62C9\u53D6\u5E76\u5E94\u7528\u914D\u7F6E\u5230\u672C\u5730\u9879\u76EE",
170
+ title: "\u{1F680} ACP \u914D\u7F6E\u5E94\u7528",
171
+ optionType: "\u8D44\u6E90\u7C7B\u578B (solution|agent|prompt|mcp)",
172
+ optionIde: "AI IDE \u7C7B\u578B (vscode|cursor|codex|claude-code)",
173
+ optionDir: "\u76EE\u6807\u76EE\u5F55",
174
+ notLoggedIn: "\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u6267\u884C acp login",
175
+ loginFirst: "\u8FD0\u884C acp login \u547D\u4EE4\u767B\u5F55",
176
+ selectResourceType: "\u8BF7\u9009\u62E9\u8D44\u6E90\u7C7B\u578B:",
177
+ resourceTypes: {
178
+ solution: "\u89E3\u51B3\u65B9\u6848 (Solution)",
179
+ agent: "Agent \u914D\u7F6E (\u6682\u4E0D\u652F\u6301)",
180
+ prompt: "Prompt (\u6682\u4E0D\u652F\u6301)",
181
+ mcp: "MCP \u914D\u7F6E (\u6682\u4E0D\u652F\u6301)"
182
+ },
183
+ notSupported: "\u6682\u4E0D\u652F\u6301\u72EC\u7ACB\u5E94\u7528 agent/prompt/mcp\uFF0C\u8BF7\u4F7F\u7528 solution \u7C7B\u578B",
184
+ noSelection: "\u672A\u9009\u62E9\u4EFB\u4F55\u914D\u7F6E",
185
+ selectIde: "\u8BF7\u9009\u62E9 AI IDE \u7C7B\u578B:",
186
+ applied: "\u914D\u7F6E\u5DF2\u5E94\u7528\u5230:",
187
+ searchPlaceholder: "\u641C\u7D22\u89E3\u51B3\u65B9\u6848\uFF08\u8F93\u5165\u540D\u79F0\u6216\u63CF\u8FF0\uFF09",
188
+ noResults: "\u6CA1\u6709\u627E\u5230\u89E3\u51B3\u65B9\u6848",
189
+ loadingMore: "\u52A0\u8F7D\u66F4\u591A...",
190
+ noMore: "\u6CA1\u6709\u66F4\u591A\u4E86",
191
+ selected: "\u5DF2\u9009\u62E9",
192
+ selectSolution: "\u8BF7\u9009\u62E9\u4E00\u4E2A\u89E3\u51B3\u65B9\u6848:",
193
+ fetching: "\u6B63\u5728\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u5217\u8868...",
194
+ fetchSuccess: "\u83B7\u53D6\u5230 {count} \u4E2A\u89E3\u51B3\u65B9\u6848",
195
+ noSolutions: "\u6682\u65E0\u53EF\u7528\u7684\u89E3\u51B3\u65B9\u6848",
196
+ searchPrompt: "\u641C\u7D22\u89E3\u51B3\u65B9\u6848 (\u6309\u540D\u79F0\u641C\u7D22\uFF0C\u7559\u7A7A\u663E\u793A\u5168\u90E8):",
197
+ noMatch: "\u672A\u627E\u5230\u5339\u914D\u7684\u89E3\u51B3\u65B9\u6848",
198
+ selectSolutionPage: "\u9009\u62E9\u89E3\u51B3\u65B9\u6848 (\u7B2C {current}/{total} \u9875):",
199
+ nextPage: ">>> \u4E0B\u4E00\u9875",
200
+ prevPage: "<<< \u4E0A\u4E00\u9875",
201
+ cancel: "\u53D6\u6D88",
202
+ fetchingDetail: "\u6B63\u5728\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u8BE6\u60C5...",
203
+ fetchDetailFailed: "\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u5931\u8D25",
204
+ ideTypes: {
205
+ vscode: "VS Code",
206
+ cursor: "Cursor",
207
+ codex: "Codex",
208
+ claudeCode: "Claude Code"
209
+ }
210
+ },
211
+ // locale 命令
212
+ locale: {
213
+ command: "locale",
214
+ description: "\u5207\u6362 CLI \u8BED\u8A00",
215
+ title: "\u{1F310} \u8BED\u8A00\u8BBE\u7F6E",
216
+ current: "\u5F53\u524D\u8BED\u8A00",
217
+ selectLanguage: "\u8BF7\u9009\u62E9\u8BED\u8A00:",
218
+ success: "\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A",
219
+ failed: "\u8BED\u8A00\u5207\u6362\u5931\u8D25",
220
+ restartHint: "\u63D0\u793A: \u5DF2\u751F\u6548\uFF0C\u65B0\u547D\u4EE4\u5C06\u4F7F\u7528\u6240\u9009\u8BED\u8A00"
221
+ },
222
+ // 错误处理
223
+ error: {
224
+ errorCode: "\u9519\u8BEF\u4EE3\u7801:",
225
+ suggestions: "\u{1F4A1} \u5EFA\u8BAE:",
226
+ needHelp: "\u9700\u8981\u5E2E\u52A9? \u8BBF\u95EE:",
227
+ unknownError: "\u672A\u77E5\u9519\u8BEF"
228
+ }
229
+ };
230
+
231
+ // src/i18n/en-US.ts
232
+ var enUS = {
233
+ // Common
234
+ common: {
235
+ confirm: "Confirm",
236
+ cancel: "Cancel",
237
+ yes: "Yes",
238
+ no: "No",
239
+ success: "Success",
240
+ failed: "Failed",
241
+ error: "Error",
242
+ warning: "Warning",
243
+ info: "Info"
244
+ },
245
+ // CLI Main
246
+ cli: {
247
+ name: "acp",
248
+ description: "AI-Config-Plaza CLI - Unified AI Programming Tool Configuration Management",
249
+ version: "Show version number",
250
+ help: "Show help information",
251
+ exampleTitle: "Examples:"
252
+ },
253
+ // login command
254
+ login: {
255
+ command: "login",
256
+ description: "Login to ACP CLI and save access token",
257
+ title: "\u{1F510} ACP CLI Login",
258
+ alreadyLoggedIn: "Already logged in. Do you want to login again?",
259
+ cancelled: "Login cancelled",
260
+ inputToken: "Please enter CLI Token:",
261
+ tokenEmpty: "Token cannot be empty",
262
+ tokenInvalid: "Invalid token format (at least 10 characters)",
263
+ success: "Login successful! Token saved to ~/.acp/token",
264
+ hint: "Tip: You can now use acp apply command to fetch configurations",
265
+ failed: "Login failed"
266
+ },
267
+ // apply command
268
+ apply: {
269
+ command: "apply",
270
+ description: "Fetch and apply configurations to local project",
271
+ title: "\u{1F680} ACP Configuration Apply",
272
+ optionType: "Resource type (solution|agent|prompt|mcp)",
273
+ optionIde: "AI IDE type (vscode|cursor|codex|claude-code)",
274
+ optionDir: "Target directory",
275
+ notLoggedIn: "Not logged in. Please run acp login first",
276
+ loginFirst: "Run acp login command to login",
277
+ selectResourceType: "Please select resource type:",
278
+ resourceTypes: {
279
+ solution: "Solution",
280
+ agent: "Agent Configuration (Not supported yet)",
281
+ prompt: "Prompt (Not supported yet)",
282
+ mcp: "MCP Configuration (Not supported yet)"
283
+ },
284
+ notSupported: "Standalone application of agent/prompt/mcp is not supported yet. Please use solution type",
285
+ noSelection: "No configuration selected",
286
+ selectIde: "Please select AI IDE type:",
287
+ applied: "Configuration applied to:",
288
+ searchPlaceholder: "Search solutions (enter name or description)",
289
+ noResults: "No solutions found",
290
+ loadingMore: "Loading more...",
291
+ noMore: "No more items",
292
+ selected: "Selected",
293
+ selectSolution: "Please select a solution:",
294
+ fetching: "Fetching solution list...",
295
+ fetchSuccess: "Fetched {count} solutions",
296
+ noSolutions: "No solutions available",
297
+ searchPrompt: "Search solutions (search by name, leave empty to show all):",
298
+ noMatch: "No matching solutions found",
299
+ selectSolutionPage: "Select solution (Page {current}/{total}):",
300
+ nextPage: ">>> Next Page",
301
+ prevPage: "<<< Previous Page",
302
+ cancel: "Cancel",
303
+ fetchingDetail: "Fetching solution details...",
304
+ fetchDetailFailed: "Failed to fetch solutions",
305
+ ideTypes: {
306
+ vscode: "VS Code",
307
+ cursor: "Cursor",
308
+ codex: "Codex",
309
+ claudeCode: "Claude Code"
310
+ }
311
+ },
312
+ // locale command
313
+ locale: {
314
+ command: "locale",
315
+ description: "Switch CLI language",
316
+ title: "\u{1F310} Language Settings",
317
+ current: "Current Language",
318
+ selectLanguage: "Please select language:",
319
+ success: "Language switched to",
320
+ failed: "Failed to switch language",
321
+ restartHint: "Tip: Changes take effect immediately for new commands"
322
+ },
323
+ // Error handling
324
+ error: {
325
+ errorCode: "Error Code:",
326
+ suggestions: "\u{1F4A1} Suggestions:",
327
+ needHelp: "Need help? Visit:",
328
+ unknownError: "Unknown error"
329
+ }
330
+ };
331
+
332
+ // src/i18n/index.ts
333
+ var messages = {
334
+ "zh-CN": zhCN,
335
+ "en-US": enUS
336
+ };
337
+ var currentLocale = null;
338
+ var currentMessages = null;
339
+ async function initI18n() {
340
+ if (!currentLocale) {
341
+ currentLocale = await getLocale();
342
+ currentMessages = messages[currentLocale];
343
+ }
344
+ }
345
+ async function t(key, params) {
346
+ await initI18n();
347
+ const keys = key.split(".");
348
+ let value = currentMessages;
349
+ for (const k of keys) {
350
+ if (value && typeof value === "object" && k in value) {
351
+ value = value[k];
352
+ } else {
353
+ return key;
354
+ }
355
+ }
356
+ if (typeof value !== "string") {
357
+ return key;
358
+ }
359
+ if (params) {
360
+ return value.replace(/\{(\w+)\}/g, (match, paramKey) => {
361
+ return paramKey in params ? String(params[paramKey]) : match;
362
+ });
363
+ }
364
+ return value;
365
+ }
366
+
367
+ // src/utils/logger.ts
84
368
  var symbols = {
85
369
  info: "\u2139",
86
370
  tick: "\u2713",
@@ -140,15 +424,19 @@ var CLIError = class extends Error {
140
424
  this.name = "CLIError";
141
425
  }
142
426
  };
143
- function handleError(error) {
427
+ async function handleError(error) {
144
428
  console.error();
145
429
  if (error instanceof CLIError) {
146
430
  logger.error(error.message);
147
431
  if (error.code) {
148
- console.log(chalk.gray(`\u9519\u8BEF\u4EE3\u7801: ${error.code}`));
432
+ const errorCodeText = await t("error.errorCode");
433
+ console.log(chalk.gray(`${errorCodeText} ${error.code}`));
149
434
  }
150
435
  if (error.suggestions?.length) {
151
- console.log(chalk.yellow.bold("\n\u{1F4A1} \u5EFA\u8BAE:\n"));
436
+ const suggestionsText = await t("error.suggestions");
437
+ console.log(chalk.yellow.bold(`
438
+ ${suggestionsText}
439
+ `));
152
440
  error.suggestions.forEach((suggestion, index) => {
153
441
  console.log(chalk.gray(` ${index + 1}. ${suggestion}`));
154
442
  });
@@ -159,18 +447,20 @@ function handleError(error) {
159
447
  console.log(chalk.gray("\n" + error.stack));
160
448
  }
161
449
  } else {
162
- logger.error("\u672A\u77E5\u9519\u8BEF");
450
+ logger.error(await t("error.unknownError"));
163
451
  }
452
+ const needHelpText = await t("error.needHelp");
164
453
  console.log(
165
- chalk.gray("\n\u9700\u8981\u5E2E\u52A9? \u8BBF\u95EE: ") + chalk.blue.underline("https://github.com/AIConfigPlaza/acp-cli")
454
+ chalk.gray(`
455
+ ${needHelpText} `) + chalk.blue.underline("https://github.com/AIConfigPlaza/acp-cli")
166
456
  );
167
457
  console.log();
168
458
  }
169
459
 
170
460
  // src/commands/login.ts
171
- var loginCommand = new Command("login").description("\u767B\u5F55 ACP CLI\uFF0C\u4FDD\u5B58\u8BBF\u95EE\u4EE4\u724C").action(async () => {
461
+ var loginCommand = new Command("login").description("\u767B\u5F55 ACP CLI\uFF0C\u4FDD\u5B58\u8BBF\u95EE\u4EE4\u724C / Login to ACP CLI and save access token").action(async () => {
172
462
  try {
173
- logger.title("\u{1F510} ACP CLI \u767B\u5F55");
463
+ logger.title(await t("login.title"));
174
464
  await initDefaultConfig();
175
465
  const existingToken = await getToken();
176
466
  if (existingToken) {
@@ -178,12 +468,12 @@ var loginCommand = new Command("login").description("\u767B\u5F55 ACP CLI\uFF0C\
178
468
  {
179
469
  type: "confirm",
180
470
  name: "overwrite",
181
- message: "\u68C0\u6D4B\u5230\u5DF2\u767B\u5F55\uFF0C\u662F\u5426\u91CD\u65B0\u767B\u5F55?",
471
+ message: await t("login.alreadyLoggedIn"),
182
472
  default: false
183
473
  }
184
474
  ]);
185
475
  if (!overwrite) {
186
- logger.info("\u5DF2\u53D6\u6D88\u767B\u5F55");
476
+ logger.info(await t("login.cancelled"));
187
477
  return;
188
478
  }
189
479
  }
@@ -191,13 +481,13 @@ var loginCommand = new Command("login").description("\u767B\u5F55 ACP CLI\uFF0C\
191
481
  {
192
482
  type: "password",
193
483
  name: "token",
194
- message: "\u8BF7\u8F93\u5165 CLI Token:",
195
- validate: (input) => {
484
+ message: await t("login.inputToken"),
485
+ validate: async (input) => {
196
486
  if (!input.trim()) {
197
- return "Token \u4E0D\u80FD\u4E3A\u7A7A";
487
+ return await t("login.tokenEmpty");
198
488
  }
199
489
  if (input.trim().length < 10) {
200
- return "Token \u683C\u5F0F\u4E0D\u6B63\u786E\uFF08\u81F3\u5C11 10 \u4E2A\u5B57\u7B26\uFF09";
490
+ return await t("login.tokenInvalid");
201
491
  }
202
492
  return true;
203
493
  },
@@ -205,11 +495,11 @@ var loginCommand = new Command("login").description("\u767B\u5F55 ACP CLI\uFF0C\
205
495
  }
206
496
  ]);
207
497
  await saveToken(token);
208
- logger.success("\u767B\u5F55\u6210\u529F\uFF01Token \u5DF2\u4FDD\u5B58\u5230 ~/.acp/token");
209
- console.log(chalk2.gray("\n\u63D0\u793A: \u73B0\u5728\u53EF\u4EE5\u4F7F\u7528 acp apply \u547D\u4EE4\u62C9\u53D6\u914D\u7F6E\n"));
498
+ logger.success(await t("login.success"));
499
+ console.log(chalk2.gray("\n" + await t("login.hint") + "\n"));
210
500
  } catch (error) {
211
501
  if (error instanceof Error) {
212
- logger.error(`\u767B\u5F55\u5931\u8D25: ${error.message}`);
502
+ logger.error(`${await t("login.failed")}: ${error.message}`);
213
503
  }
214
504
  process.exit(1);
215
505
  }
@@ -374,8 +664,8 @@ function searchByName(items, query) {
374
664
  }
375
665
 
376
666
  // src/apply/writer.ts
377
- import fs2 from "fs-extra";
378
- import path2 from "path";
667
+ import fs3 from "fs-extra";
668
+ import path3 from "path";
379
669
  import chalk3 from "chalk";
380
670
  import inquirer2 from "inquirer";
381
671
 
@@ -436,9 +726,9 @@ async function applySolution(solution, options) {
436
726
  \u2728 \u89E3\u51B3\u65B9\u6848 ${chalk3.cyan(solution.name)} \u5E94\u7528\u6210\u529F\uFF01`);
437
727
  }
438
728
  async function applyAgentConfig(content, relativePath, targetDir) {
439
- const filePath = path2.join(targetDir, relativePath);
729
+ const filePath = path3.join(targetDir, relativePath);
440
730
  logger.step(`\u5199\u5165 Agent \u914D\u7F6E: ${chalk3.gray(relativePath)}`);
441
- const exists = await fs2.pathExists(filePath);
731
+ const exists = await fs3.pathExists(filePath);
442
732
  if (exists) {
443
733
  const { overwrite } = await inquirer2.prompt([
444
734
  {
@@ -453,18 +743,18 @@ async function applyAgentConfig(content, relativePath, targetDir) {
453
743
  return;
454
744
  }
455
745
  }
456
- await fs2.ensureDir(path2.dirname(filePath));
457
- await fs2.writeFile(filePath, content, "utf-8");
746
+ await fs3.ensureDir(path3.dirname(filePath));
747
+ await fs3.writeFile(filePath, content, "utf-8");
458
748
  logger.success(`\u5DF2\u5199\u5165: ${relativePath}`);
459
749
  }
460
750
  async function applyPrompts(prompts, promptsDir, targetDir) {
461
- const fullPromptsDir = path2.join(targetDir, promptsDir);
751
+ const fullPromptsDir = path3.join(targetDir, promptsDir);
462
752
  logger.step(`\u5199\u5165 ${prompts.length} \u4E2A Prompt \u914D\u7F6E\u5230: ${chalk3.gray(promptsDir)}`);
463
- await fs2.ensureDir(fullPromptsDir);
753
+ await fs3.ensureDir(fullPromptsDir);
464
754
  for (const prompt of prompts) {
465
755
  const fileName = sanitizeFileName(prompt.name) + ".prompt.md";
466
- const filePath = path2.join(fullPromptsDir, fileName);
467
- const exists = await fs2.pathExists(filePath);
756
+ const filePath = path3.join(fullPromptsDir, fileName);
757
+ const exists = await fs3.pathExists(filePath);
468
758
  if (exists) {
469
759
  const { overwrite } = await inquirer2.prompt([
470
760
  {
@@ -479,12 +769,12 @@ async function applyPrompts(prompts, promptsDir, targetDir) {
479
769
  continue;
480
770
  }
481
771
  }
482
- await fs2.writeFile(filePath, prompt.content, "utf-8");
483
- logger.success(`\u5DF2\u5199\u5165: ${path2.join(promptsDir, fileName)}`);
772
+ await fs3.writeFile(filePath, prompt.content, "utf-8");
773
+ logger.success(`\u5DF2\u5199\u5165: ${path3.join(promptsDir, fileName)}`);
484
774
  }
485
775
  }
486
776
  async function applyMcpConfigs(mcpConfigs, mcpFile, targetDir) {
487
- const filePath = path2.join(targetDir, mcpFile);
777
+ const filePath = path3.join(targetDir, mcpFile);
488
778
  logger.step(`\u5199\u5165 MCP \u914D\u7F6E: ${chalk3.gray(mcpFile)}`);
489
779
  const mcpServers = {};
490
780
  for (const mcpConfig of mcpConfigs) {
@@ -495,7 +785,7 @@ async function applyMcpConfigs(mcpConfigs, mcpFile, targetDir) {
495
785
  logger.warning(`MCP \u914D\u7F6E ${mcpConfig.name} \u683C\u5F0F\u9519\u8BEF\uFF0C\u5DF2\u8DF3\u8FC7`);
496
786
  }
497
787
  }
498
- const exists = await fs2.pathExists(filePath);
788
+ const exists = await fs3.pathExists(filePath);
499
789
  if (exists) {
500
790
  const { overwrite } = await inquirer2.prompt([
501
791
  {
@@ -510,10 +800,10 @@ async function applyMcpConfigs(mcpConfigs, mcpFile, targetDir) {
510
800
  return;
511
801
  }
512
802
  }
513
- await fs2.ensureDir(path2.dirname(filePath));
803
+ await fs3.ensureDir(path3.dirname(filePath));
514
804
  if (mcpFile.endsWith(".toml")) {
515
805
  const tomlContent = convertMcpToToml(mcpServers);
516
- await fs2.writeFile(filePath, tomlContent, "utf-8");
806
+ await fs3.writeFile(filePath, tomlContent, "utf-8");
517
807
  } else {
518
808
  let mergedConfig;
519
809
  if (mcpFile.includes(".vscode")) {
@@ -525,7 +815,7 @@ async function applyMcpConfigs(mcpConfigs, mcpFile, targetDir) {
525
815
  mcpServers
526
816
  };
527
817
  }
528
- await fs2.writeFile(filePath, JSON.stringify(mergedConfig, null, 2), "utf-8");
818
+ await fs3.writeFile(filePath, JSON.stringify(mergedConfig, null, 2), "utf-8");
529
819
  }
530
820
  logger.success(`\u5DF2\u5199\u5165: ${mcpFile}`);
531
821
  }
@@ -560,25 +850,25 @@ function sanitizeFileName(name) {
560
850
  }
561
851
 
562
852
  // src/commands/apply.ts
563
- 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) => {
853
+ var applyCommand = new Command2("apply").description("\u62C9\u53D6\u5E76\u5E94\u7528\u914D\u7F6E\u5230\u672C\u5730\u9879\u76EE / Fetch and apply configurations to local project").option("-t, --type <type>", "\u8D44\u6E90\u7C7B\u578B (solution|agent|prompt|mcp) / Resource type", "solution").option("-i, --ide <ide>", "AI IDE \u7C7B\u578B / AI IDE type (vscode|cursor|codex|claude-code)").option("-d, --dir <path>", "\u76EE\u6807\u76EE\u5F55 / Target directory", process.cwd()).action(async (options) => {
564
854
  try {
565
855
  if (!await isLoggedIn()) {
566
856
  throw new CLIError(
567
- "\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u6267\u884C acp login",
857
+ await t("apply.notLoggedIn"),
568
858
  "NOT_LOGGED_IN",
569
- ["\u8FD0\u884C acp login \u547D\u4EE4\u767B\u5F55"]
859
+ [await t("apply.loginFirst")]
570
860
  );
571
861
  }
572
- logger.title("\u{1F680} ACP \u914D\u7F6E\u5E94\u7528");
862
+ logger.title(await t("apply.title"));
573
863
  const resourceType = await selectResourceType(options.type);
574
864
  let selectedSolution = null;
575
865
  if (resourceType === "solution") {
576
866
  selectedSolution = await fetchAndSelectSolution();
577
867
  } else {
578
- throw new CLIError("\u6682\u4E0D\u652F\u6301\u72EC\u7ACB\u5E94\u7528 agent/prompt/mcp\uFF0C\u8BF7\u4F7F\u7528 solution \u7C7B\u578B");
868
+ throw new CLIError(await t("apply.notSupported"));
579
869
  }
580
870
  if (!selectedSolution) {
581
- logger.info("\u672A\u9009\u62E9\u4EFB\u4F55\u914D\u7F6E");
871
+ logger.info(await t("apply.noSelection"));
582
872
  return;
583
873
  }
584
874
  const ide = options.ide || await selectIde();
@@ -586,8 +876,9 @@ var applyCommand = new Command2("apply").description("\u62C9\u53D6\u5E76\u5E94\u
586
876
  ide,
587
877
  targetDir: options.dir
588
878
  });
879
+ const appliedMsg = await t("apply.applied");
589
880
  console.log(chalk4.gray(`
590
- \u914D\u7F6E\u5DF2\u5E94\u7528\u5230: ${chalk4.cyan(options.dir)}
881
+ ${appliedMsg} ${chalk4.cyan(options.dir)}
591
882
  `));
592
883
  } catch (error) {
593
884
  if (error instanceof Error) {
@@ -604,12 +895,12 @@ async function selectResourceType(defaultType) {
604
895
  {
605
896
  type: "list",
606
897
  name: "type",
607
- message: "\u8BF7\u9009\u62E9\u8D44\u6E90\u7C7B\u578B:",
898
+ message: await t("apply.selectResourceType"),
608
899
  choices: [
609
- { name: chalk4.cyan("\u89E3\u51B3\u65B9\u6848 (Solution)"), value: "solution" },
610
- { name: chalk4.gray("Agent \u914D\u7F6E (\u6682\u4E0D\u652F\u6301)"), value: "agent", disabled: true },
611
- { name: chalk4.gray("Prompt (\u6682\u4E0D\u652F\u6301)"), value: "prompt", disabled: true },
612
- { name: chalk4.gray("MCP \u914D\u7F6E (\u6682\u4E0D\u652F\u6301)"), value: "mcp", disabled: true }
900
+ { name: chalk4.cyan(await t("apply.resourceTypes.solution")), value: "solution" },
901
+ { name: chalk4.gray(await t("apply.resourceTypes.agent")), value: "agent", disabled: true },
902
+ { name: chalk4.gray(await t("apply.resourceTypes.prompt")), value: "prompt", disabled: true },
903
+ { name: chalk4.gray(await t("apply.resourceTypes.mcp")), value: "mcp", disabled: true }
613
904
  ],
614
905
  default: "solution"
615
906
  }
@@ -617,26 +908,26 @@ async function selectResourceType(defaultType) {
617
908
  return type;
618
909
  }
619
910
  async function fetchAndSelectSolution() {
620
- const spinner = ora("\u6B63\u5728\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u5217\u8868...").start();
911
+ const spinner = ora(await t("apply.fetching")).start();
621
912
  try {
622
913
  const response = await apiClient.getSolutions();
623
914
  spinner.stop();
624
915
  if (!response.data || response.data.length === 0) {
625
- logger.warning("\u6682\u65E0\u53EF\u7528\u7684\u89E3\u51B3\u65B9\u6848");
916
+ logger.warning(await t("apply.noSolutions"));
626
917
  return null;
627
918
  }
628
- logger.success(`\u83B7\u53D6\u5230 ${response.data.length} \u4E2A\u89E3\u51B3\u65B9\u6848`);
919
+ logger.success(await t("apply.fetchSuccess", { count: response.data.length }));
629
920
  const { searchQuery } = await inquirer3.prompt([
630
921
  {
631
922
  type: "input",
632
923
  name: "searchQuery",
633
- message: "\u641C\u7D22\u89E3\u51B3\u65B9\u6848 (\u6309\u540D\u79F0\u641C\u7D22\uFF0C\u7559\u7A7A\u663E\u793A\u5168\u90E8):",
924
+ message: await t("apply.searchPrompt"),
634
925
  default: ""
635
926
  }
636
927
  ]);
637
928
  let filteredSolutions = searchByName(response.data, searchQuery);
638
929
  if (filteredSolutions.length === 0) {
639
- logger.warning("\u672A\u627E\u5230\u5339\u914D\u7684\u89E3\u51B3\u65B9\u6848");
930
+ logger.warning(await t("apply.noMatch"));
640
931
  return null;
641
932
  }
642
933
  const PAGE_SIZE = 20;
@@ -648,34 +939,37 @@ async function fetchAndSelectSolution() {
648
939
  pageSize: PAGE_SIZE
649
940
  });
650
941
  const choices = paginatedResult.items.map((solution) => ({
651
- name: `${chalk4.cyan(solution.name)} - ${chalk4.gray(solution.description)}`,
942
+ name: `${chalk4.cyan(solution.name)} ${chalk4.yellow(`@${solution.author.username}`)} - ${chalk4.gray(solution.description)}`,
652
943
  value: solution.id,
653
944
  short: solution.name
654
945
  }));
655
946
  if (paginatedResult.hasNext) {
656
947
  choices.push({
657
- name: chalk4.yellow(">>> \u4E0B\u4E00\u9875"),
948
+ name: chalk4.yellow(await t("apply.nextPage")),
658
949
  value: "__NEXT_PAGE__",
659
- short: "\u4E0B\u4E00\u9875"
950
+ short: await t("apply.nextPage")
660
951
  });
661
952
  }
662
953
  if (paginatedResult.hasPrev) {
663
954
  choices.unshift({
664
- name: chalk4.yellow("<<< \u4E0A\u4E00\u9875"),
955
+ name: chalk4.yellow(await t("apply.prevPage")),
665
956
  value: "__PREV_PAGE__",
666
- short: "\u4E0A\u4E00\u9875"
957
+ short: await t("apply.prevPage")
667
958
  });
668
959
  }
669
960
  choices.push({
670
- name: chalk4.red("\u53D6\u6D88"),
961
+ name: chalk4.red(await t("apply.cancel")),
671
962
  value: "__CANCEL__",
672
- short: "\u53D6\u6D88"
963
+ short: await t("apply.cancel")
673
964
  });
674
965
  const { selected } = await inquirer3.prompt([
675
966
  {
676
967
  type: "list",
677
968
  name: "selected",
678
- message: `\u9009\u62E9\u89E3\u51B3\u65B9\u6848 (\u7B2C ${currentPage}/${paginatedResult.totalPages} \u9875):`,
969
+ message: await t("apply.selectSolutionPage", {
970
+ current: currentPage,
971
+ total: paginatedResult.totalPages
972
+ }),
679
973
  choices,
680
974
  pageSize: 15
681
975
  }
@@ -687,7 +981,7 @@ async function fetchAndSelectSolution() {
687
981
  } else if (selected === "__PREV_PAGE__") {
688
982
  currentPage--;
689
983
  } else {
690
- const detailSpinner = ora("\u6B63\u5728\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u8BE6\u60C5...").start();
984
+ const detailSpinner = ora(await t("apply.fetchingDetail")).start();
691
985
  const detailResponse = await apiClient.getSolutionById(selected);
692
986
  detailSpinner.stop();
693
987
  selectedSolution = detailResponse.data;
@@ -695,7 +989,7 @@ async function fetchAndSelectSolution() {
695
989
  }
696
990
  return selectedSolution;
697
991
  } catch (error) {
698
- spinner.fail("\u83B7\u53D6\u89E3\u51B3\u65B9\u6848\u5931\u8D25");
992
+ spinner.fail(await t("apply.fetchDetailFailed"));
699
993
  throw error;
700
994
  }
701
995
  }
@@ -704,12 +998,12 @@ async function selectIde() {
704
998
  {
705
999
  type: "list",
706
1000
  name: "ide",
707
- message: "\u8BF7\u9009\u62E9 AI IDE \u7C7B\u578B:",
1001
+ message: await t("apply.selectIde"),
708
1002
  choices: [
709
- { name: chalk4.cyan("VS Code"), value: "vscode" },
710
- { name: chalk4.cyan("Cursor"), value: "cursor" },
711
- { name: chalk4.cyan("Codex"), value: "codex" },
712
- { name: chalk4.cyan("Claude Code"), value: "claude-code" }
1003
+ { name: chalk4.cyan(await t("apply.ideTypes.vscode")), value: "vscode" },
1004
+ { name: chalk4.cyan(await t("apply.ideTypes.cursor")), value: "cursor" },
1005
+ { name: chalk4.cyan(await t("apply.ideTypes.codex")), value: "codex" },
1006
+ { name: chalk4.cyan(await t("apply.ideTypes.claudeCode")), value: "claude-code" }
713
1007
  ],
714
1008
  default: "vscode"
715
1009
  }
@@ -717,25 +1011,76 @@ async function selectIde() {
717
1011
  return ide;
718
1012
  }
719
1013
 
720
- // src/index.ts
721
- var version = true ? "1.0.3" : "0.0.0-dev";
722
- var program = new Command3();
723
- program.name("acp").description(
724
- chalk5.gray("AI-Config-Plaza CLI - \u7EDF\u4E00 AI \u7F16\u7A0B\u5DE5\u5177\u914D\u7F6E\u7BA1\u7406")
725
- ).version(version, "-v, --version", "\u663E\u793A\u7248\u672C\u53F7").helpOption("-h, --help", "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F");
726
- program.addCommand(loginCommand);
727
- program.addCommand(applyCommand);
728
- program.on("--help", () => {
729
- console.log(chalk5.bold("\n\u793A\u4F8B:\n"));
730
- console.log(chalk5.gray(" $ acp login"));
731
- console.log(chalk5.gray(" $ acp apply"));
732
- console.log(chalk5.gray(" $ acp apply --ide vscode --dir ./my-project"));
733
- console.log();
1014
+ // src/commands/locale.ts
1015
+ import { Command as Command3 } from "commander";
1016
+ import inquirer4 from "inquirer";
1017
+ import chalk5 from "chalk";
1018
+ var localeCommand = new Command3("locale").description("\u5207\u6362 CLI \u8BED\u8A00 / Switch CLI language").action(async () => {
1019
+ try {
1020
+ const currentLocale2 = await getLocale();
1021
+ const title = await t("locale.title");
1022
+ logger.title(title);
1023
+ const currentText = await t("locale.current");
1024
+ console.log(chalk5.gray(`${currentText}: `) + chalk5.cyan(getLocaleName(currentLocale2)));
1025
+ console.log();
1026
+ const supportedLocales = getSupportedLocales();
1027
+ const selectText = await t("locale.selectLanguage");
1028
+ const { newLocale } = await inquirer4.prompt([
1029
+ {
1030
+ type: "list",
1031
+ name: "newLocale",
1032
+ message: selectText,
1033
+ choices: supportedLocales.map((locale) => ({
1034
+ name: locale === currentLocale2 ? chalk5.cyan(`${getLocaleName(locale)} (\u5F53\u524D / Current)`) : getLocaleName(locale),
1035
+ value: locale
1036
+ })),
1037
+ default: currentLocale2
1038
+ }
1039
+ ]);
1040
+ if (newLocale === currentLocale2) {
1041
+ logger.info(`${await t("locale.current")}: ${getLocaleName(currentLocale2)}`);
1042
+ return;
1043
+ }
1044
+ await saveLocale(newLocale);
1045
+ if (newLocale === "zh-CN") {
1046
+ logger.success(`\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A ${getLocaleName(newLocale)}`);
1047
+ console.log(chalk5.gray("\n\u63D0\u793A: \u5DF2\u751F\u6548\uFF0C\u65B0\u547D\u4EE4\u5C06\u4F7F\u7528\u6240\u9009\u8BED\u8A00\n"));
1048
+ } else {
1049
+ logger.success(`Language switched to ${getLocaleName(newLocale)}`);
1050
+ console.log(chalk5.gray("\nTip: Changes take effect immediately for new commands\n"));
1051
+ }
1052
+ } catch (error) {
1053
+ if (error instanceof Error) {
1054
+ logger.error(`${await t("locale.failed")}: ${error.message}`);
1055
+ }
1056
+ process.exit(1);
1057
+ }
734
1058
  });
735
- try {
736
- await program.parseAsync(process.argv);
737
- } catch (error) {
738
- handleError(error);
739
- process.exit(1);
1059
+
1060
+ // src/index.ts
1061
+ var version = true ? "1.0.5" : "0.0.0-dev";
1062
+ async function main() {
1063
+ const program = new Command4();
1064
+ program.name("acp").description(
1065
+ chalk6.gray(await t("cli.description"))
1066
+ ).version(version, "-v, --version", await t("cli.version")).helpOption("-h, --help", await t("cli.help"));
1067
+ program.addCommand(loginCommand);
1068
+ program.addCommand(applyCommand);
1069
+ program.addCommand(localeCommand);
1070
+ program.on("--help", async () => {
1071
+ console.log(chalk6.bold("\n" + await t("cli.exampleTitle") + "\n"));
1072
+ console.log(chalk6.gray(" $ acp login"));
1073
+ console.log(chalk6.gray(" $ acp apply"));
1074
+ console.log(chalk6.gray(" $ acp apply --ide vscode --dir ./my-project"));
1075
+ console.log(chalk6.gray(" $ acp locale"));
1076
+ console.log();
1077
+ });
1078
+ try {
1079
+ await program.parseAsync(process.argv);
1080
+ } catch (error) {
1081
+ await handleError(error);
1082
+ process.exit(1);
1083
+ }
740
1084
  }
1085
+ main();
741
1086
  //# sourceMappingURL=index.js.map
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\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":";;;AAEA,SAAS,WAAAA,gBAAe;AACxB,OAAOC,YAAW;;;ACHlB,SAAS,eAAe;AACxB,OAAO,cAAc;AACrB,OAAOC,YAAW;;;ACFlB,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AAOf,IAAM,gBAAgB;AACtB,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAEzB,IAAM,aAAa,KAAK,KAAK,GAAG,QAAQ,GAAG,MAAM;AACjD,IAAM,aAAa,KAAK,KAAK,YAAY,OAAO;AAChD,IAAM,gBAAgB,KAAK,KAAK,YAAY,UAAU;AAKtD,eAAsB,WAAmC;AAEvD,QAAM,WAAW,QAAQ,IAAI,aAAa;AAC1C,MAAI,UAAU,KAAK,GAAG;AACpB,WAAO,SAAS,KAAK;AAAA,EACvB;AAGA,MAAI;AACF,QAAI,MAAM,GAAG,WAAW,UAAU,GAAG;AACnC,YAAM,QAAQ,MAAM,GAAG,SAAS,YAAY,OAAO;AACnD,aAAO,MAAM,KAAK,KAAK;AAAA,IACzB;AAAA,EACF,SAAS,OAAO;AAAA,EAEhB;AAEA,SAAO;AACT;AAKA,eAAsB,UAAU,OAA8B;AAC5D,MAAI,CAAC,OAAO,KAAK,GAAG;AAClB,UAAM,IAAI,MAAM,gCAAY;AAAA,EAC9B;AAGA,QAAM,GAAG,UAAU,UAAU;AAG7B,QAAM,GAAG,UAAU,YAAY,MAAM,KAAK,GAAG,OAAO;AACtD;AAcA,eAAsB,aAA+B;AACnD,QAAM,QAAQ,MAAM,SAAS;AAC7B,SAAO,UAAU,QAAQ,MAAM,SAAS;AAC1C;AAKA,eAAsB,aAA8B;AAElD,QAAM,aAAa,QAAQ,IAAI,gBAAgB;AAC/C,MAAI,YAAY,KAAK,GAAG;AACtB,WAAO,WAAW,KAAK;AAAA,EACzB;AAGA,MAAI;AACF,QAAI,MAAM,GAAG,WAAW,aAAa,GAAG;AACtC,YAAM,UAAU,MAAM,GAAG,SAAS,eAAe,OAAO;AACxD,UAAI,QAAQ,KAAK,GAAG;AAClB,eAAO,QAAQ,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAAA,EAEhB;AAGA,SAAO;AACT;AAKA,eAAsB,YAAY,SAAgC;AAChE,MAAI,CAAC,SAAS,KAAK,GAAG;AACpB,UAAM,IAAI,MAAM,mCAAe;AAAA,EACjC;AAGA,MAAI;AACF,QAAI,IAAI,QAAQ,KAAK,CAAC;AAAA,EACxB,QAAQ;AACN,UAAM,IAAI,MAAM,uFAA2B;AAAA,EAC7C;AAGA,QAAM,GAAG,UAAU,UAAU;AAG7B,QAAM,GAAG,UAAU,eAAe,QAAQ,KAAK,GAAG,OAAO;AAC3D;AAcA,eAAsB,oBAAmC;AACvD,QAAM,GAAG,UAAU,UAAU;AAG7B,MAAI,CAAE,MAAM,GAAG,WAAW,aAAa,GAAI;AACzC,UAAM,YAAY,gBAAgB;AAAA,EACpC;AACF;;;AC3IA,OAAO,WAAW;AAOlB,IAAM,UAAU;AAAA,EACd,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,YAAY;AACd;AAEO,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA,EAIpB,MAAM,CAAC,YAAoB;AACzB,YAAQ,IAAI,MAAM,KAAK,QAAQ,IAAI,IAAI,MAAM,OAAO;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,CAAC,YAAoB;AAC5B,YAAQ,IAAI,MAAM,MAAM,QAAQ,IAAI,IAAI,MAAM,MAAM,MAAM,OAAO,CAAC;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,CAAC,YAAoB;AAC5B,YAAQ,IAAI,MAAM,OAAO,QAAQ,OAAO,IAAI,MAAM,MAAM,OAAO,OAAO,CAAC;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,CAAC,YAAoB;AAC1B,YAAQ,MAAM,MAAM,IAAI,QAAQ,KAAK,IAAI,MAAM,MAAM,IAAI,OAAO,CAAC;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,CAAC,YAAoB;AACzB,YAAQ,IAAI,MAAM,KAAK,QAAQ,UAAU,IAAI,MAAM,MAAM,KAAK,OAAO,CAAC;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,CAAC,YAAoB;AAC1B,YAAQ,IAAI,OAAO,MAAM,KAAK,UAAU,OAAO,IAAI,IAAI;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,CAAC,YAAoB;AACxB,YAAQ,IAAI,OAAO;AAAA,EACrB;AACF;AAKO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC,YACE,SACO,MACA,aACP;AACA,UAAM,OAAO;AAHN;AACA;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAKO,SAAS,YAAY,OAAsB;AAChD,UAAQ,MAAM;AAEd,MAAI,iBAAiB,UAAU;AAC7B,WAAO,MAAM,MAAM,OAAO;AAE1B,QAAI,MAAM,MAAM;AACd,cAAQ,IAAI,MAAM,KAAK,6BAAS,MAAM,IAAI,EAAE,CAAC;AAAA,IAC/C;AAEA,QAAI,MAAM,aAAa,QAAQ;AAC7B,cAAQ,IAAI,MAAM,OAAO,KAAK,6BAAY,CAAC;AAC3C,YAAM,YAAY,QAAQ,CAAC,YAAY,UAAU;AAC/C,gBAAQ,IAAI,MAAM,KAAK,KAAK,QAAQ,CAAC,KAAK,UAAU,EAAE,CAAC;AAAA,MACzD,CAAC;AAAA,IACH;AAAA,EACF,WAAW,iBAAiB,OAAO;AACjC,WAAO,MAAM,MAAM,OAAO;AAE1B,QAAI,QAAQ,IAAI,OAAO;AACrB,cAAQ,IAAI,MAAM,KAAK,OAAO,MAAM,KAAK,CAAC;AAAA,IAC5C;AAAA,EACF,OAAO;AACL,WAAO,MAAM,0BAAM;AAAA,EACrB;AAEA,UAAQ;AAAA,IACN,MAAM,KAAK,4CAAc,IACvB,MAAM,KAAK,UAAU,0CAA0C;AAAA,EACnE;AACA,UAAQ,IAAI;AACd;;;AFvGO,IAAM,eAAe,IAAI,QAAQ,OAAO,EAC5C,YAAY,gEAAmB,EAC/B,OAAO,YAAY;AAClB,MAAI;AACF,WAAO,MAAM,gCAAe;AAG5B,UAAM,kBAAkB;AAGxB,UAAM,gBAAgB,MAAM,SAAS;AACrC,QAAI,eAAe;AACjB,YAAM,EAAE,UAAU,IAAI,MAAM,SAAS,OAAO;AAAA,QAC1C;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AAED,UAAI,CAAC,WAAW;AACd,eAAO,KAAK,gCAAO;AACnB;AAAA,MACF;AAAA,IACF;AAGA,UAAM,EAAE,MAAM,IAAI,MAAM,SAAS,OAAO;AAAA,MACtC;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,UAAU,CAAC,UAAkB;AAC3B,cAAI,CAAC,MAAM,KAAK,GAAG;AACjB,mBAAO;AAAA,UACT;AACA,cAAI,MAAM,KAAK,EAAE,SAAS,IAAI;AAC5B,mBAAO;AAAA,UACT;AACA,iBAAO;AAAA,QACT;AAAA,QACA,MAAM;AAAA,MACR;AAAA,IACF,CAAC;AAGD,UAAM,UAAU,KAAK;AAErB,WAAO,QAAQ,2EAA8B;AAC7C,YAAQ,IAAIC,OAAM,KAAK,uGAAiC,CAAC;AAAA,EAC3D,SAAS,OAAO;AACd,QAAI,iBAAiB,OAAO;AAC1B,aAAO,MAAM,6BAAS,MAAM,OAAO,EAAE;AAAA,IACvC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;;;AGpEH,SAAS,WAAAC,gBAAe;AACxB,OAAOC,eAAc;AACrB,OAAOC,YAAW;AAClB,OAAO,SAAS;;;ACHhB,OAAO,WAA0C;AAcjD,IAAM,YAAN,MAAgB;AAAA,EACN;AAAA,EACA;AAAA,EAER,cAAc;AAEZ,SAAK,iBAAiB,WAAW;AAEjC,SAAK,SAAS,MAAM,OAAO;AAAA,MACzB,SAAS;AAAA,MACT,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,IACF,CAAC;AAGD,SAAK,OAAO,aAAa,QAAQ,IAAI,OAAO,WAAW;AAErD,UAAI,CAAC,OAAO,SAAS;AACnB,eAAO,UAAU,MAAM,KAAK;AAAA,MAC9B;AAGA,YAAM,QAAQ,MAAM,SAAS;AAC7B,UAAI,OAAO;AACT,eAAO,QAAQ,aAAa,IAAI;AAAA,MAClC;AACA,aAAO;AAAA,IACT,CAAC;AAGD,SAAK,OAAO,aAAa,SAAS;AAAA,MAChC,CAAC,aAAa;AAAA,MACd,CAAC,UAAsB;AACrB,YAAI,MAAM,UAAU;AAClB,gBAAM,SAAS,MAAM,SAAS;AAC9B,gBAAM,UAAW,MAAM,SAAS,MAAc,WAAW,MAAM;AAE/D,cAAI,WAAW,KAAK;AAClB,kBAAM,IAAI,MAAM,+EAAwB;AAAA,UAC1C,WAAW,WAAW,KAAK;AACzB,kBAAM,IAAI,MAAM,iFAAqB;AAAA,UACvC,WAAW,WAAW,KAAK;AACzB,kBAAM,IAAI,MAAM,kDAAU;AAAA,UAC5B,WAAW,UAAU,KAAK;AACxB,kBAAM,IAAI,MAAM,mCAAU,MAAM,MAAM,OAAO,EAAE;AAAA,UACjD,OAAO;AACL,kBAAM,IAAI,MAAM,6BAAS,MAAM,MAAM,OAAO,EAAE;AAAA,UAChD;AAAA,QACF,WAAW,MAAM,SAAS;AACxB,gBAAM,IAAI,MAAM,0EAAc;AAAA,QAChC,OAAO;AACL,gBAAM,IAAI,MAAM,yCAAW,MAAM,OAAO,EAAE;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,QAAmD;AACpE,UAAM,SAAS,SAAS,EAAE,OAAO,IAAI,CAAC;AACtC,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MACjC;AAAA,MACA,EAAE,OAAO;AAAA,IACX;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgB,IAA4C;AAChE,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MACjC,sBAAsB,EAAE;AAAA,IAC1B;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAiD;AACrD,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MACjC;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,IAA+C;AAChE,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MACjC,mBAAmB,EAAE;AAAA,IACvB;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA6C;AACjD,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MACjC;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,IAA0C;AAC5D,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MACjC,oBAAoB,EAAE;AAAA,IACxB;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAA6C;AACjD,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MACjC;AAAA,IACF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,IAA6C;AAC5D,UAAM,WAAW,MAAM,KAAK,OAAO;AAAA,MACjC,iBAAiB,EAAE;AAAA,IACrB;AACA,WAAO,SAAS;AAAA,EAClB;AACF;AAGO,IAAM,YAAY,IAAI,UAAU;;;ACtIhC,SAAS,SACd,OACA,SACqB;AACrB,QAAM,EAAE,MAAM,SAAS,IAAI;AAC3B,QAAM,QAAQ,MAAM;AACpB,QAAM,aAAa,KAAK,KAAK,QAAQ,QAAQ;AAC7C,QAAM,cAAc,OAAO,KAAK;AAChC,QAAM,WAAW,aAAa;AAE9B,SAAO;AAAA,IACL,OAAO,MAAM,MAAM,YAAY,QAAQ;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,OAAO;AAAA,IAChB,SAAS,OAAO;AAAA,EAClB;AACF;AAKO,SAAS,aACd,OACA,OACK;AACL,MAAI,CAAC,MAAM,KAAK,GAAG;AACjB,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,MAAM,YAAY,EAAE,KAAK;AAC5C,SAAO,MAAM;AAAA,IAAO,CAAC,SACnB,KAAK,KAAK,YAAY,EAAE,SAAS,UAAU;AAAA,EAC7C;AACF;;;AC1DA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,YAAW;AAClB,OAAOC,eAAc;;;ACOd,IAAM,oBAAuD;AAAA,EAClE,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AAAA,EACA,eAAe;AAAA,IACb,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,KAAK;AAAA,EACP;AACF;AAKO,SAAS,kBAAkB,KAAgC;AAChE,SAAO,kBAAkB,GAAG;AAC9B;;;ADlBA,eAAsB,cACpB,UACA,SACe;AACf,QAAM,EAAE,KAAK,UAAU,IAAI;AAC3B,QAAM,cAAc,kBAAkB,GAAG;AAEzC,SAAO,MAAM,mDAAcC,OAAM,KAAK,SAAS,IAAI,CAAC,EAAE;AAGtD,MAAI,SAAS,aAAa;AACxB,UAAM;AAAA,MACJ,SAAS,YAAY;AAAA,MACrB,YAAY;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,eAAe,QAAQ;AAClC,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,YAAY,QAAQ;AAC/B,UAAM;AAAA,MACJ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAEA,SAAO,QAAQ;AAAA,kCAAYA,OAAM,KAAK,SAAS,IAAI,CAAC,iCAAQ;AAC9D;AAKA,eAAsB,iBACpB,SACA,cACA,WACe;AACf,QAAM,WAAWC,MAAK,KAAK,WAAW,YAAY;AAElD,SAAO,KAAK,oCAAgBD,OAAM,KAAK,YAAY,CAAC,EAAE;AAGtD,QAAM,SAAS,MAAME,IAAG,WAAW,QAAQ;AAC3C,MAAI,QAAQ;AACV,UAAM,EAAE,UAAU,IAAI,MAAMC,UAAS,OAAO;AAAA,MAC1C;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS,gBAAMH,OAAM,KAAK,YAAY,CAAC;AAAA,QACvC,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAED,QAAI,CAAC,WAAW;AACd,aAAO,QAAQ,iBAAO,YAAY,EAAE;AACpC;AAAA,IACF;AAAA,EACF;AAGA,QAAME,IAAG,UAAUD,MAAK,QAAQ,QAAQ,CAAC;AACzC,QAAMC,IAAG,UAAU,UAAU,SAAS,OAAO;AAE7C,SAAO,QAAQ,uBAAQ,YAAY,EAAE;AACvC;AAKA,eAAsB,aACpB,SACA,YACA,WACe;AACf,QAAM,iBAAiBD,MAAK,KAAK,WAAW,UAAU;AAEtD,SAAO,KAAK,gBAAM,QAAQ,MAAM,sCAAkBD,OAAM,KAAK,UAAU,CAAC,EAAE;AAG1E,QAAME,IAAG,UAAU,cAAc;AAEjC,aAAW,UAAU,SAAS;AAE5B,UAAM,WAAW,iBAAiB,OAAO,IAAI,IAAI;AACjD,UAAM,WAAWD,MAAK,KAAK,gBAAgB,QAAQ;AAGnD,UAAM,SAAS,MAAMC,IAAG,WAAW,QAAQ;AAC3C,QAAI,QAAQ;AACV,YAAM,EAAE,UAAU,IAAI,MAAMC,UAAS,OAAO;AAAA,QAC1C;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS,UAAUH,OAAM,KAAK,QAAQ,CAAC;AAAA,UACvC,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AAED,UAAI,CAAC,WAAW;AACd,eAAO,QAAQ,iBAAO,QAAQ,EAAE;AAChC;AAAA,MACF;AAAA,IACF;AAGA,UAAME,IAAG,UAAU,UAAU,OAAO,SAAS,OAAO;AACpD,WAAO,QAAQ,uBAAQD,MAAK,KAAK,YAAY,QAAQ,CAAC,EAAE;AAAA,EAC1D;AACF;AAKA,eAAsB,gBACpB,YACA,SACA,WACe;AACf,QAAM,WAAWA,MAAK,KAAK,WAAW,OAAO;AAE7C,SAAO,KAAK,kCAAcD,OAAM,KAAK,OAAO,CAAC,EAAE;AAG/C,QAAM,aAAkC,CAAC;AAEzC,aAAW,aAAa,YAAY;AAClC,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,UAAU,UAAU;AAE9C,iBAAW,UAAU,IAAI,IAAI;AAAA,IAC/B,SAAS,OAAO;AACd,aAAO,QAAQ,oBAAU,UAAU,IAAI,mDAAW;AAAA,IACpD;AAAA,EACF;AAGA,QAAM,SAAS,MAAME,IAAG,WAAW,QAAQ;AAC3C,MAAI,QAAQ;AACV,UAAM,EAAE,UAAU,IAAI,MAAMC,UAAS,OAAO;AAAA,MAC1C;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS,gBAAMH,OAAM,KAAK,OAAO,CAAC;AAAA,QAClC,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAED,QAAI,CAAC,WAAW;AACd,aAAO,QAAQ,iBAAO,OAAO,EAAE;AAC/B;AAAA,IACF;AAAA,EACF;AAGA,QAAME,IAAG,UAAUD,MAAK,QAAQ,QAAQ,CAAC;AAGzC,MAAI,QAAQ,SAAS,OAAO,GAAG;AAE7B,UAAM,cAAc,iBAAiB,UAAU;AAC/C,UAAMC,IAAG,UAAU,UAAU,aAAa,OAAO;AAAA,EACnD,OAAO;AAEL,QAAI;AAGJ,QAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,qBAAe;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF,OAAO;AACL,qBAAe;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAEA,UAAMA,IAAG,UAAU,UAAU,KAAK,UAAU,cAAc,MAAM,CAAC,GAAG,OAAO;AAAA,EAC7E;AAEA,SAAO,QAAQ,uBAAQ,OAAO,EAAE;AAClC;AAKA,SAAS,iBAAiB,YAAyC;AACjE,MAAI,cAAc;AAElB,aAAW,CAAC,YAAY,MAAM,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC7D,mBAAe,gBAAgB,UAAU;AAAA;AAGzC,QAAI,OAAO,SAAS;AAClB,qBAAe,aAAa,KAAK,UAAU,OAAO,OAAO,CAAC;AAAA;AAAA,IAC5D;AAGA,QAAI,OAAO,QAAQ,MAAM,QAAQ,OAAO,IAAI,GAAG;AAC7C,YAAM,UAAU,OAAO,KAAK,IAAI,CAAC,QAAgB,KAAK,UAAU,GAAG,CAAC,EAAE,KAAK,IAAI;AAC/E,qBAAe,WAAW,OAAO;AAAA;AAAA,IACnC;AAGA,QAAI,OAAO,OAAO,OAAO,OAAO,QAAQ,UAAU;AAChD,YAAM,aAAa,OAAO,QAAQ,OAAO,GAAG;AAC5C,UAAI,WAAW,SAAS,GAAG;AACzB,cAAM,SAAS,WACZ,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,MAAM,KAAK,UAAU,KAAK,CAAC,EAAE,EACzD,KAAK,IAAI;AACZ,uBAAe,WAAW,MAAM;AAAA;AAAA,MAClC;AAAA,IACF;AAEA,mBAAe;AAAA,EACjB;AAEA,SAAO;AACT;AAKA,SAAS,iBAAiB,MAAsB;AAC9C,SAAO,KACJ,QAAQ,iBAAiB,GAAG,EAC5B,QAAQ,QAAQ,GAAG,EACnB,QAAQ,OAAO,GAAG,EAClB,YAAY;AACjB;;;AH/OO,IAAM,eAAe,IAAIE,SAAQ,OAAO,EAC5C,YAAY,0EAAc,EAC1B,OAAO,qBAAqB,wDAAoC,UAAU,EAC1E,OAAO,mBAAmB,uDAA6C,EACvE,OAAO,oBAAoB,4BAAQ,QAAQ,IAAI,CAAC,EAChD,OAAO,OAAO,YAAY;AACzB,MAAI;AAEF,QAAI,CAAE,MAAM,WAAW,GAAI;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA,CAAC,iDAAmB;AAAA,MACtB;AAAA,IACF;AAEA,WAAO,MAAM,wCAAa;AAG1B,UAAM,eAAe,MAAM,mBAAmB,QAAQ,IAAI;AAG1D,QAAI,mBAAoC;AAExC,QAAI,iBAAiB,YAAY;AAC/B,yBAAmB,MAAM,uBAAuB;AAAA,IAClD,OAAO;AACL,YAAM,IAAI,SAAS,iHAA2C;AAAA,IAChE;AAEA,QAAI,CAAC,kBAAkB;AACrB,aAAO,KAAK,4CAAS;AACrB;AAAA,IACF;AAGA,UAAM,MAAM,QAAQ,OAAQ,MAAM,UAAU;AAG5C,UAAM,cAAc,kBAAkB;AAAA,MACpC;AAAA,MACA,WAAW,QAAQ;AAAA,IACrB,CAAC;AAED,YAAQ,IAAIC,OAAM,KAAK;AAAA,wCAAaA,OAAM,KAAK,QAAQ,GAAG,CAAC;AAAA,CAAI,CAAC;AAAA,EAClE,SAAS,OAAO;AACd,QAAI,iBAAiB,OAAO;AAC1B,aAAO,MAAM,MAAM,OAAO;AAAA,IAC5B;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAKH,eAAe,mBAAmB,aAA6C;AAC7E,MAAI,eAAe,CAAC,YAAY,SAAS,UAAU,KAAK,EAAE,SAAS,WAAW,GAAG;AAC/E,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,KAAK,IAAI,MAAMC,UAAS,OAAO;AAAA,IACrC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAMD,OAAM,KAAK,qCAAiB,GAAG,OAAO,WAAW;AAAA,QACzD,EAAE,MAAMA,OAAM,KAAK,+CAAiB,GAAG,OAAO,SAAS,UAAU,KAAK;AAAA,QACtE,EAAE,MAAMA,OAAM,KAAK,mCAAe,GAAG,OAAO,UAAU,UAAU,KAAK;AAAA,QACrE,EAAE,MAAMA,OAAM,KAAK,6CAAe,GAAG,OAAO,OAAO,UAAU,KAAK;AAAA,MACpE;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAKA,eAAe,yBAAmD;AAChE,QAAM,UAAU,IAAI,iEAAe,EAAE,MAAM;AAE3C,MAAI;AAEF,UAAM,WAAW,MAAM,UAAU,aAAa;AAC9C,YAAQ,KAAK;AAEb,QAAI,CAAC,SAAS,QAAQ,SAAS,KAAK,WAAW,GAAG;AAChD,aAAO,QAAQ,wDAAW;AAC1B,aAAO;AAAA,IACT;AAEA,WAAO,QAAQ,sBAAO,SAAS,KAAK,MAAM,iCAAQ;AAGlD,UAAM,EAAE,YAAY,IAAI,MAAMC,UAAS,OAAO;AAAA,MAC5C;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AAED,QAAI,oBAAoB,aAAa,SAAS,MAAM,WAAW;AAE/D,QAAI,kBAAkB,WAAW,GAAG;AAClC,aAAO,QAAQ,8DAAY;AAC3B,aAAO;AAAA,IACT;AAGA,UAAM,YAAY;AAClB,QAAI,cAAc;AAClB,QAAI,mBAAoC;AAExC,WAAO,CAAC,kBAAkB;AACxB,YAAM,kBAAkB,SAAS,mBAAmB;AAAA,QAClD,MAAM;AAAA,QACN,UAAU;AAAA,MACZ,CAAC;AAGD,YAAM,UAAU,gBAAgB,MAAM,IAAI,CAAC,cAAc;AAAA,QACvD,MAAM,GAAGD,OAAM,KAAK,SAAS,IAAI,CAAC,MAAMA,OAAM,KAAK,SAAS,WAAW,CAAC;AAAA,QACxE,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,MAClB,EAAE;AAGF,UAAI,gBAAgB,SAAS;AAC3B,gBAAQ,KAAK;AAAA,UACX,MAAMA,OAAM,OAAO,wBAAS;AAAA,UAC5B,OAAO;AAAA,UACP,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,UAAI,gBAAgB,SAAS;AAC3B,gBAAQ,QAAQ;AAAA,UACd,MAAMA,OAAM,OAAO,wBAAS;AAAA,UAC5B,OAAO;AAAA,UACP,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,cAAQ,KAAK;AAAA,QACX,MAAMA,OAAM,IAAI,cAAI;AAAA,QACpB,OAAO;AAAA,QACP,OAAO;AAAA,MACT,CAAC;AAED,YAAM,EAAE,SAAS,IAAI,MAAMC,UAAS,OAAO;AAAA,QACzC;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS,gDAAa,WAAW,IAAI,gBAAgB,UAAU;AAAA,UAC/D;AAAA,UACA,UAAU;AAAA,QACZ;AAAA,MACF,CAAC;AAED,UAAI,aAAa,cAAc;AAC7B,eAAO;AAAA,MACT,WAAW,aAAa,iBAAiB;AACvC;AAAA,MACF,WAAW,aAAa,iBAAiB;AACvC;AAAA,MACF,OAAO;AAEL,cAAM,gBAAgB,IAAI,iEAAe,EAAE,MAAM;AACjD,cAAM,iBAAiB,MAAM,UAAU,gBAAgB,QAAQ;AAC/D,sBAAc,KAAK;AAEnB,2BAAmB,eAAe;AAAA,MACpC;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,KAAK,kDAAU;AACvB,UAAM;AAAA,EACR;AACF;AAKA,eAAe,YAAgC;AAC7C,QAAM,EAAE,IAAI,IAAI,MAAMA,UAAS,OAAO;AAAA,IACpC;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,MAAMD,OAAM,KAAK,SAAS,GAAG,OAAO,SAAS;AAAA,QAC/C,EAAE,MAAMA,OAAM,KAAK,QAAQ,GAAG,OAAO,SAAS;AAAA,QAC9C,EAAE,MAAMA,OAAM,KAAK,OAAO,GAAG,OAAO,QAAQ;AAAA,QAC5C,EAAE,MAAMA,OAAM,KAAK,aAAa,GAAG,OAAO,cAAc;AAAA,MAC1D;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AJrNA,IAAM,UAAU,OAAqC,UAAc;AAEnE,IAAM,UAAU,IAAIE,SAAQ;AAE5B,QACG,KAAK,KAAK,EACV;AAAA,EACCC,OAAM,KAAK,wFAAsC;AACnD,EACC,QAAQ,SAAS,iBAAiB,gCAAO,EACzC,WAAW,cAAc,sCAAQ;AAGpC,QAAQ,WAAW,YAAY;AAC/B,QAAQ,WAAW,YAAY;AAG/B,QAAQ,GAAG,UAAU,MAAM;AACzB,UAAQ,IAAIA,OAAM,KAAK,mBAAS,CAAC;AACjC,UAAQ,IAAIA,OAAM,KAAK,eAAe,CAAC;AACvC,UAAQ,IAAIA,OAAM,KAAK,eAAe,CAAC;AACvC,UAAQ,IAAIA,OAAM,KAAK,+CAA+C,CAAC;AACvE,UAAQ,IAAI;AACd,CAAC;AAGD,IAAI;AACF,QAAM,QAAQ,WAAW,QAAQ,IAAI;AACvC,SAAS,OAAO;AACd,cAAY,KAAK;AACjB,UAAQ,KAAK,CAAC;AAChB;","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/config/locale.ts","../src/i18n/zh-CN.ts","../src/i18n/en-US.ts","../src/i18n/index.ts","../src/commands/apply.ts","../src/api/client.ts","../src/utils/pagination.ts","../src/apply/writer.ts","../src/utils/ide-mapper.ts","../src/commands/locale.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 { localeCommand } from './commands/locale.js'\r\nimport { handleError } from './utils/logger.js'\r\nimport { t } from './i18n/index.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\nasync function main() {\r\n const program = new Command()\r\n\r\n program\r\n .name('acp')\r\n .description(\r\n chalk.gray(await t('cli.description'))\r\n )\r\n .version(version, '-v, --version', await t('cli.version'))\r\n .helpOption('-h, --help', await t('cli.help'))\r\n\r\n // 注册命令\r\n program.addCommand(loginCommand)\r\n program.addCommand(applyCommand)\r\n program.addCommand(localeCommand)\r\n\r\n // 自定义帮助显示\r\n program.on('--help', async () => {\r\n console.log(chalk.bold('\\n' + await t('cli.exampleTitle') + '\\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(chalk.gray(' $ acp locale'))\r\n console.log()\r\n })\r\n\r\n // 解析命令\r\n try {\r\n await program.parseAsync(process.argv)\r\n } catch (error) {\r\n await handleError(error)\r\n process.exit(1)\r\n }\r\n}\r\n\r\nmain()\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\nimport { t } from '../i18n/index.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,保存访问令牌 / Login to ACP CLI and save access token')\r\n .action(async () => {\r\n try {\r\n logger.title(await t('login.title'))\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: await t('login.alreadyLoggedIn'),\r\n default: false\r\n }\r\n ])\r\n\r\n if (!overwrite) {\r\n logger.info(await t('login.cancelled'))\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: await t('login.inputToken'),\r\n validate: async (input: string) => {\r\n if (!input.trim()) {\r\n return await t('login.tokenEmpty')\r\n }\r\n if (input.trim().length < 10) {\r\n return await t('login.tokenInvalid')\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(await t('login.success'))\r\n console.log(chalk.gray('\\n' + await t('login.hint') + '\\n'))\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n logger.error(`${await t('login.failed')}: ${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\nimport { t } from '../i18n/index.js'\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 async function handleError(error: unknown): Promise<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 const errorCodeText = await t('error.errorCode')\r\n console.log(chalk.gray(`${errorCodeText} ${error.code}`))\r\n }\r\n\r\n if (error.suggestions?.length) {\r\n const suggestionsText = await t('error.suggestions')\r\n console.log(chalk.yellow.bold(`\\n${suggestionsText}\\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(await t('error.unknownError'))\r\n }\r\n\r\n const needHelpText = await t('error.needHelp')\r\n console.log(\r\n chalk.gray(`\\n${needHelpText} `) +\r\n chalk.blue.underline('https://github.com/AIConfigPlaza/acp-cli')\r\n )\r\n console.log()\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 * 语言配置管理\r\n * 支持的语言: zh-CN (中文), en-US (英文)\r\n */\r\n\r\nexport type Locale = 'zh-CN' | 'en-US'\r\n\r\nconst LOCALE_ENV_KEY = 'ACP_CLI_LOCALE'\r\nconst DEFAULT_LOCALE: Locale = 'zh-CN'\r\n\r\nconst CONFIG_DIR = path.join(os.homedir(), '.acp')\r\nconst LOCALE_FILE = path.join(CONFIG_DIR, 'locale')\r\n\r\n/**\r\n * 读取当前语言配置\r\n */\r\nexport async function getLocale(): Promise<Locale> {\r\n // 1. 优先读取环境变量\r\n const envLocale = process.env[LOCALE_ENV_KEY]\r\n if (envLocale && isValidLocale(envLocale)) {\r\n return envLocale as Locale\r\n }\r\n\r\n // 2. 读取本地配置文件\r\n try {\r\n if (await fs.pathExists(LOCALE_FILE)) {\r\n const locale = (await fs.readFile(LOCALE_FILE, 'utf-8')).trim()\r\n if (isValidLocale(locale)) {\r\n return locale as Locale\r\n }\r\n }\r\n } catch (error) {\r\n // 读取失败使用默认值\r\n }\r\n\r\n // 3. 返回默认语言\r\n return DEFAULT_LOCALE\r\n}\r\n\r\n/**\r\n * 保存语言配置到本地文件\r\n */\r\nexport async function saveLocale(locale: Locale): Promise<void> {\r\n if (!isValidLocale(locale)) {\r\n throw new Error(`不支持的语言: ${locale}`)\r\n }\r\n\r\n // 确保配置目录存在\r\n await fs.ensureDir(CONFIG_DIR)\r\n\r\n // 保存语言配置\r\n await fs.writeFile(LOCALE_FILE, locale, 'utf-8')\r\n}\r\n\r\n/**\r\n * 验证语言代码是否有效\r\n */\r\nfunction isValidLocale(locale: string): boolean {\r\n return locale === 'zh-CN' || locale === 'en-US'\r\n}\r\n\r\n/**\r\n * 获取所有支持的语言列表\r\n */\r\nexport function getSupportedLocales(): Locale[] {\r\n return ['zh-CN', 'en-US']\r\n}\r\n\r\n/**\r\n * 获取语言显示名称\r\n */\r\nexport function getLocaleName(locale: Locale): string {\r\n const names: Record<Locale, string> = {\r\n 'zh-CN': '简体中文',\r\n 'en-US': 'English'\r\n }\r\n return names[locale]\r\n}\r\n","/**\r\n * 中文语言包\r\n */\r\n\r\nexport const zhCN = {\r\n // 通用\r\n common: {\r\n confirm: '确认',\r\n cancel: '取消',\r\n yes: '是',\r\n no: '否',\r\n success: '成功',\r\n failed: '失败',\r\n error: '错误',\r\n warning: '警告',\r\n info: '提示'\r\n },\r\n\r\n // CLI 主程序\r\n cli: {\r\n name: 'acp',\r\n description: 'AI-Config-Plaza CLI - 统一 AI 编程工具配置管理',\r\n version: '显示版本号',\r\n help: '显示帮助信息',\r\n exampleTitle: '示例:'\r\n },\r\n\r\n // login 命令\r\n login: {\r\n command: 'login',\r\n description: '登录 ACP CLI,保存访问令牌',\r\n title: '🔐 ACP CLI 登录',\r\n alreadyLoggedIn: '检测到已登录,是否重新登录?',\r\n cancelled: '已取消登录',\r\n inputToken: '请输入 CLI Token:',\r\n tokenEmpty: 'Token 不能为空',\r\n tokenInvalid: 'Token 格式不正确(至少 10 个字符)',\r\n success: '登录成功!Token 已保存到 ~/.acp/token',\r\n hint: '提示: 现在可以使用 acp apply 命令拉取配置',\r\n failed: '登录失败'\r\n },\r\n\r\n // apply 命令\r\n apply: {\r\n command: 'apply',\r\n description: '拉取并应用配置到本地项目',\r\n title: '🚀 ACP 配置应用',\r\n optionType: '资源类型 (solution|agent|prompt|mcp)',\r\n optionIde: 'AI IDE 类型 (vscode|cursor|codex|claude-code)',\r\n optionDir: '目标目录',\r\n notLoggedIn: '未登录,请先执行 acp login',\r\n loginFirst: '运行 acp login 命令登录',\r\n selectResourceType: '请选择资源类型:',\r\n resourceTypes: {\r\n solution: '解决方案 (Solution)',\r\n agent: 'Agent 配置 (暂不支持)',\r\n prompt: 'Prompt (暂不支持)',\r\n mcp: 'MCP 配置 (暂不支持)'\r\n },\r\n notSupported: '暂不支持独立应用 agent/prompt/mcp,请使用 solution 类型',\r\n noSelection: '未选择任何配置',\r\n selectIde: '请选择 AI IDE 类型:',\r\n applied: '配置已应用到:',\r\n searchPlaceholder: '搜索解决方案(输入名称或描述)',\r\n noResults: '没有找到解决方案',\r\n loadingMore: '加载更多...',\r\n noMore: '没有更多了',\r\n selected: '已选择',\r\n selectSolution: '请选择一个解决方案:',\r\n fetching: '正在获取解决方案列表...',\r\n fetchSuccess: '获取到 {count} 个解决方案',\r\n noSolutions: '暂无可用的解决方案',\r\n searchPrompt: '搜索解决方案 (按名称搜索,留空显示全部):',\r\n noMatch: '未找到匹配的解决方案',\r\n selectSolutionPage: '选择解决方案 (第 {current}/{total} 页):',\r\n nextPage: '>>> 下一页',\r\n prevPage: '<<< 上一页',\r\n cancel: '取消',\r\n fetchingDetail: '正在获取解决方案详情...',\r\n fetchDetailFailed: '获取解决方案失败',\r\n ideTypes: {\r\n vscode: 'VS Code',\r\n cursor: 'Cursor',\r\n codex: 'Codex',\r\n claudeCode: 'Claude Code'\r\n }\r\n },\r\n\r\n // locale 命令\r\n locale: {\r\n command: 'locale',\r\n description: '切换 CLI 语言',\r\n title: '🌐 语言设置',\r\n current: '当前语言',\r\n selectLanguage: '请选择语言:',\r\n success: '语言已切换为',\r\n failed: '语言切换失败',\r\n restartHint: '提示: 已生效,新命令将使用所选语言'\r\n },\r\n\r\n // 错误处理\r\n error: {\r\n errorCode: '错误代码:',\r\n suggestions: '💡 建议:',\r\n needHelp: '需要帮助? 访问:',\r\n unknownError: '未知错误'\r\n }\r\n}\r\n","/**\r\n * English Language Pack\r\n */\r\n\r\nexport const enUS = {\r\n // Common\r\n common: {\r\n confirm: 'Confirm',\r\n cancel: 'Cancel',\r\n yes: 'Yes',\r\n no: 'No',\r\n success: 'Success',\r\n failed: 'Failed',\r\n error: 'Error',\r\n warning: 'Warning',\r\n info: 'Info'\r\n },\r\n\r\n // CLI Main\r\n cli: {\r\n name: 'acp',\r\n description: 'AI-Config-Plaza CLI - Unified AI Programming Tool Configuration Management',\r\n version: 'Show version number',\r\n help: 'Show help information',\r\n exampleTitle: 'Examples:'\r\n },\r\n\r\n // login command\r\n login: {\r\n command: 'login',\r\n description: 'Login to ACP CLI and save access token',\r\n title: '🔐 ACP CLI Login',\r\n alreadyLoggedIn: 'Already logged in. Do you want to login again?',\r\n cancelled: 'Login cancelled',\r\n inputToken: 'Please enter CLI Token:',\r\n tokenEmpty: 'Token cannot be empty',\r\n tokenInvalid: 'Invalid token format (at least 10 characters)',\r\n success: 'Login successful! Token saved to ~/.acp/token',\r\n hint: 'Tip: You can now use acp apply command to fetch configurations',\r\n failed: 'Login failed'\r\n },\r\n\r\n // apply command\r\n apply: {\r\n command: 'apply',\r\n description: 'Fetch and apply configurations to local project',\r\n title: '🚀 ACP Configuration Apply',\r\n optionType: 'Resource type (solution|agent|prompt|mcp)',\r\n optionIde: 'AI IDE type (vscode|cursor|codex|claude-code)',\r\n optionDir: 'Target directory',\r\n notLoggedIn: 'Not logged in. Please run acp login first',\r\n loginFirst: 'Run acp login command to login',\r\n selectResourceType: 'Please select resource type:',\r\n resourceTypes: {\r\n solution: 'Solution',\r\n agent: 'Agent Configuration (Not supported yet)',\r\n prompt: 'Prompt (Not supported yet)',\r\n mcp: 'MCP Configuration (Not supported yet)'\r\n },\r\n notSupported: 'Standalone application of agent/prompt/mcp is not supported yet. Please use solution type',\r\n noSelection: 'No configuration selected',\r\n selectIde: 'Please select AI IDE type:',\r\n applied: 'Configuration applied to:',\r\n searchPlaceholder: 'Search solutions (enter name or description)',\r\n noResults: 'No solutions found',\r\n loadingMore: 'Loading more...',\r\n noMore: 'No more items',\r\n selected: 'Selected',\r\n selectSolution: 'Please select a solution:',\r\n fetching: 'Fetching solution list...',\r\n fetchSuccess: 'Fetched {count} solutions',\r\n noSolutions: 'No solutions available',\r\n searchPrompt: 'Search solutions (search by name, leave empty to show all):',\r\n noMatch: 'No matching solutions found',\r\n selectSolutionPage: 'Select solution (Page {current}/{total}):',\r\n nextPage: '>>> Next Page',\r\n prevPage: '<<< Previous Page',\r\n cancel: 'Cancel',\r\n fetchingDetail: 'Fetching solution details...',\r\n fetchDetailFailed: 'Failed to fetch solutions',\r\n ideTypes: {\r\n vscode: 'VS Code',\r\n cursor: 'Cursor',\r\n codex: 'Codex',\r\n claudeCode: 'Claude Code'\r\n }\r\n },\r\n\r\n // locale command\r\n locale: {\r\n command: 'locale',\r\n description: 'Switch CLI language',\r\n title: '🌐 Language Settings',\r\n current: 'Current Language',\r\n selectLanguage: 'Please select language:',\r\n success: 'Language switched to',\r\n failed: 'Failed to switch language',\r\n restartHint: 'Tip: Changes take effect immediately for new commands'\r\n },\r\n\r\n // Error handling\r\n error: {\r\n errorCode: 'Error Code:',\r\n suggestions: '💡 Suggestions:',\r\n needHelp: 'Need help? Visit:',\r\n unknownError: 'Unknown error'\r\n }\r\n}\r\n","import { getLocale, type Locale } from '../config/locale.js'\r\nimport { zhCN } from './zh-CN.js'\r\nimport { enUS } from './en-US.js'\r\n\r\n/**\r\n * 国际化工具 - 提供多语言支持\r\n */\r\n\r\n// 语言包映射\r\nconst messages: Record<Locale, typeof zhCN> = {\r\n 'zh-CN': zhCN,\r\n 'en-US': enUS\r\n}\r\n\r\n// 当前语言缓存\r\nlet currentLocale: Locale | null = null\r\nlet currentMessages: typeof zhCN | null = null\r\n\r\n/**\r\n * 初始化 i18n\r\n */\r\nasync function initI18n(): Promise<void> {\r\n if (!currentLocale) {\r\n currentLocale = await getLocale()\r\n currentMessages = messages[currentLocale]\r\n }\r\n}\r\n\r\n/**\r\n * 翻译函数 - 根据键路径获取翻译文本\r\n * @param key - 翻译键,支持点分隔的路径,如 'login.title'\r\n * @param params - 替换参数对象\r\n * @returns 翻译后的文本\r\n */\r\nexport async function t(key: string, params?: Record<string, string | number>): Promise<string> {\r\n await initI18n()\r\n\r\n // 通过点分隔的路径获取嵌套值\r\n const keys = key.split('.')\r\n let value: any = currentMessages\r\n\r\n for (const k of keys) {\r\n if (value && typeof value === 'object' && k in value) {\r\n value = value[k]\r\n } else {\r\n // 如果找不到翻译,返回 key 本身\r\n return key\r\n }\r\n }\r\n\r\n // 如果不是字符串,返回 key\r\n if (typeof value !== 'string') {\r\n return key\r\n }\r\n\r\n // 替换参数\r\n if (params) {\r\n return value.replace(/\\{(\\w+)\\}/g, (match, paramKey) => {\r\n return paramKey in params ? String(params[paramKey]) : match\r\n })\r\n }\r\n\r\n return value\r\n}\r\n\r\n/**\r\n * 同步翻译函数(需要先初始化)\r\n * @param key - 翻译键\r\n * @param params - 替换参数对象\r\n * @returns 翻译后的文本\r\n */\r\nexport function tSync(key: string, params?: Record<string, string | number>): string {\r\n if (!currentMessages) {\r\n // 如果未初始化,返回 key\r\n return key\r\n }\r\n\r\n const keys = key.split('.')\r\n let value: any = currentMessages\r\n\r\n for (const k of keys) {\r\n if (value && typeof value === 'object' && k in value) {\r\n value = value[k]\r\n } else {\r\n return key\r\n }\r\n }\r\n\r\n if (typeof value !== 'string') {\r\n return key\r\n }\r\n\r\n if (params) {\r\n return value.replace(/\\{(\\w+)\\}/g, (match, paramKey) => {\r\n return paramKey in params ? String(params[paramKey]) : match\r\n })\r\n }\r\n\r\n return value\r\n}\r\n\r\n/**\r\n * 获取当前语言\r\n */\r\nexport async function getCurrentLocale(): Promise<Locale> {\r\n await initI18n()\r\n return currentLocale!\r\n}\r\n\r\n/**\r\n * 重新加载语言配置(切换语言后调用)\r\n */\r\nexport async function reloadLocale(): Promise<void> {\r\n currentLocale = null\r\n currentMessages = null\r\n await initI18n()\r\n}\r\n\r\n/**\r\n * 获取完整的语言包(用于类型提示)\r\n */\r\nexport function getMessages() {\r\n return currentMessages || zhCN\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\nimport { t } from '../i18n/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('拉取并应用配置到本地项目 / Fetch and apply configurations to local project')\r\n .option('-t, --type <type>', '资源类型 (solution|agent|prompt|mcp) / Resource type', 'solution')\r\n .option('-i, --ide <ide>', 'AI IDE 类型 / AI IDE type (vscode|cursor|codex|claude-code)')\r\n .option('-d, --dir <path>', '目标目录 / Target directory', process.cwd())\r\n .action(async (options) => {\r\n try {\r\n // 检查登录状态\r\n if (!(await isLoggedIn())) {\r\n throw new CLIError(\r\n await t('apply.notLoggedIn'),\r\n 'NOT_LOGGED_IN',\r\n [await t('apply.loginFirst')]\r\n )\r\n }\r\n\r\n logger.title(await t('apply.title'))\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(await t('apply.notSupported'))\r\n }\r\n\r\n if (!selectedSolution) {\r\n logger.info(await t('apply.noSelection'))\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 const appliedMsg = await t('apply.applied')\r\n console.log(chalk.gray(`\\n${appliedMsg} ${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: await t('apply.selectResourceType'),\r\n choices: [\r\n { name: chalk.cyan(await t('apply.resourceTypes.solution')), value: 'solution' },\r\n { name: chalk.gray(await t('apply.resourceTypes.agent')), value: 'agent', disabled: true },\r\n { name: chalk.gray(await t('apply.resourceTypes.prompt')), value: 'prompt', disabled: true },\r\n { name: chalk.gray(await t('apply.resourceTypes.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(await t('apply.fetching')).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(await t('apply.noSolutions'))\r\n return null\r\n }\r\n\r\n logger.success(await t('apply.fetchSuccess', { count: 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: await t('apply.searchPrompt'),\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(await t('apply.noMatch'))\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.yellow(`@${solution.author.username}`)} - ${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(await t('apply.nextPage')),\r\n value: '__NEXT_PAGE__',\r\n short: await t('apply.nextPage')\r\n })\r\n }\r\n\r\n if (paginatedResult.hasPrev) {\r\n choices.unshift({\r\n name: chalk.yellow(await t('apply.prevPage')),\r\n value: '__PREV_PAGE__',\r\n short: await t('apply.prevPage')\r\n })\r\n }\r\n\r\n choices.push({\r\n name: chalk.red(await t('apply.cancel')),\r\n value: '__CANCEL__',\r\n short: await t('apply.cancel')\r\n })\r\n\r\n const { selected } = await inquirer.prompt([\r\n {\r\n type: 'list',\r\n name: 'selected',\r\n message: await t('apply.selectSolutionPage', { \r\n current: currentPage, \r\n total: paginatedResult.totalPages \r\n }),\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(await t('apply.fetchingDetail')).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(await t('apply.fetchDetailFailed'))\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: await t('apply.selectIde'),\r\n choices: [\r\n { name: chalk.cyan(await t('apply.ideTypes.vscode')), value: 'vscode' },\r\n { name: chalk.cyan(await t('apply.ideTypes.cursor')), value: 'cursor' },\r\n { name: chalk.cyan(await t('apply.ideTypes.codex')), value: 'codex' },\r\n { name: chalk.cyan(await t('apply.ideTypes.claudeCode')), 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","import { Command } from 'commander'\r\nimport inquirer from 'inquirer'\r\nimport chalk from 'chalk'\r\nimport { getLocale, saveLocale, getSupportedLocales, getLocaleName, type Locale } from '../config/locale.js'\r\nimport { t } from '../i18n/index.js'\r\nimport { logger } from '../utils/logger.js'\r\n\r\n/**\r\n * acp locale 命令\r\n * 切换 CLI 语言\r\n */\r\n\r\nexport const localeCommand = new Command('locale')\r\n .description('切换 CLI 语言 / Switch CLI language')\r\n .action(async () => {\r\n try {\r\n // 获取当前语言\r\n const currentLocale = await getLocale()\r\n \r\n // 显示标题\r\n const title = await t('locale.title')\r\n logger.title(title)\r\n\r\n // 显示当前语言\r\n const currentText = await t('locale.current')\r\n console.log(chalk.gray(`${currentText}: `) + chalk.cyan(getLocaleName(currentLocale)))\r\n console.log()\r\n\r\n // 选择新语言\r\n const supportedLocales = getSupportedLocales()\r\n const selectText = await t('locale.selectLanguage')\r\n \r\n const { newLocale } = await inquirer.prompt([\r\n {\r\n type: 'list',\r\n name: 'newLocale',\r\n message: selectText,\r\n choices: supportedLocales.map(locale => ({\r\n name: locale === currentLocale \r\n ? chalk.cyan(`${getLocaleName(locale)} (当前 / Current)`)\r\n : getLocaleName(locale),\r\n value: locale\r\n })),\r\n default: currentLocale\r\n }\r\n ])\r\n\r\n // 如果选择的是当前语言,则不做任何操作\r\n if (newLocale === currentLocale) {\r\n logger.info(`${await t('locale.current')}: ${getLocaleName(currentLocale)}`)\r\n return\r\n }\r\n\r\n // 保存新语言\r\n await saveLocale(newLocale as Locale)\r\n\r\n // 显示成功消息(使用新语言)\r\n // 注意:这里需要手动构造消息,因为 t() 函数还在使用旧语言缓存\r\n if (newLocale === 'zh-CN') {\r\n logger.success(`语言已切换为 ${getLocaleName(newLocale)}`)\r\n console.log(chalk.gray('\\n提示: 已生效,新命令将使用所选语言\\n'))\r\n } else {\r\n logger.success(`Language switched to ${getLocaleName(newLocale)}`)\r\n console.log(chalk.gray('\\nTip: Changes take effect immediately for new commands\\n'))\r\n }\r\n\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n logger.error(`${await t('locale.failed')}: ${error.message}`)\r\n }\r\n process.exit(1)\r\n }\r\n })\r\n"],"mappings":"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","names":["Command","chalk","chalk","fs","path","os","CONFIG_DIR","chalk","Command","inquirer","chalk","fs","path","chalk","inquirer","chalk","path","fs","inquirer","Command","chalk","inquirer","Command","inquirer","chalk","Command","currentLocale","chalk","inquirer","Command","chalk"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-config-plaza/acp-cli",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "AI-Config-Plaza CLI 工具 - 统一 AI 编程工具配置管理",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",