zcf 2.0.1 → 2.1.2

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 UfoMiao
3
+ Copyright (c) 2025 UfoMiao & WitMiao
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -6,22 +6,23 @@
6
6
 
7
7
  **中文** | [English](README_EN.md)
8
8
 
9
- > 零配置,一键搞定 Claude Code 环境设置 - 支持中英文双语配置、智能代理系统和个性化AI助手
9
+ > 零配置,一键搞定 Claude Code 环境设置 - 支持中英文双语配置、智能代理系统和个性化 AI 助手
10
10
 
11
11
  ![效果图](./src/assets/screenshot.webp)
12
12
 
13
13
  ## 🚀 快速开始
14
14
 
15
- ### 🎯 推荐:使用交互式菜单(v2.0新增)
15
+ ### 🎯 推荐:使用交互式菜单(v2.0 新增)
16
16
 
17
17
  ```bash
18
18
  npx zcf # 打开交互式菜单,根据你的需求选择操作
19
19
  ```
20
20
 
21
21
  菜单选项包括:
22
+
22
23
  - `1` 完整初始化(等同于 `zcf i`)
23
24
  - `2` 导入工作流(等同于 `zcf u`)
24
- - `3-6` 配置管理(API、MCP、模型、AI个性等)
25
+ - `3-6` 配置管理(API、MCP、模型、AI 个性等)
25
26
  - 更多功能选项...
26
27
 
27
28
  ### 或者,直接使用命令:
@@ -43,6 +44,7 @@ npx zcf → 选择 2 # 通过菜单执行工作流更新
43
44
  ```
44
45
 
45
46
  > **提示**:
47
+ >
46
48
  > - v2.0 起,`zcf` 默认打开交互式菜单,提供可视化操作界面
47
49
  > - 你可以通过菜单选择操作,也可以直接使用命令快捷执行
48
50
  > - `zcf i` = 完整初始化,`zcf u` = 仅更新工作流
@@ -86,7 +88,7 @@ npx zcf → 选择 2 # 通过菜单执行工作流更新
86
88
  - 使用 npm 进行自动安装(确保兼容性)
87
89
  - 跨平台支持(Windows/macOS/Linux)
88
90
  - 自动配置 MCP 服务
89
- - 智能配置合并和部分修改支持(v2.0新增)
91
+ - 智能配置合并和部分修改支持(v2.0 新增)
90
92
 
91
93
  ### 📦 完整配置
92
94
 
@@ -102,17 +104,17 @@ npx zcf → 选择 2 # 通过菜单执行工作流更新
102
104
  - **API Key**:适用于从 Anthropic Console 获取的 API 密钥
103
105
  - 自定义 API URL 支持
104
106
  - 支持稍后在 claude 命令中配置
105
- - 部分修改功能:仅更新需要的配置项(v2.0新增)
107
+ - 部分修改功能:仅更新需要的配置项(v2.0 新增)
106
108
 
107
109
  ### 💾 配置管理
108
110
 
109
111
  - 智能备份现有配置(所有备份保存在 ~/.claude/backup/)
110
- - 配置合并选项(v2.0增强:支持深度合并)
112
+ - 配置合并选项(v2.0 增强:支持深度合并)
111
113
  - 安全的覆盖机制
112
114
  - MCP 配置修改前自动备份
113
- - 默认模型配置(v2.0新增)
114
- - AI 记忆管理(v2.0新增)
115
- - ZCF 缓存清理(v2.0新增)
115
+ - 默认模型配置(v2.0 新增)
116
+ - AI 记忆管理(v2.0 新增)
117
+ - ZCF 缓存清理(v2.0 新增)
116
118
 
117
119
  ## 📖 使用说明
118
120
 
@@ -135,7 +137,7 @@ $ npx zcf
135
137
  4. 配置 MCP 服务 - 管理 MCP 集成
136
138
  5. 配置默认模型 - 设置默认 AI 模型
137
139
  6. 配置 AI 个性 - 设置 AI 助手人格
138
-
140
+
139
141
  ------------ ZCF ------------
140
142
  0. 更改语言 - 切换界面语言
141
143
  -. 清理缓存 - 清理 ZCF 缓存文件
@@ -144,7 +146,7 @@ $ npx zcf
144
146
  请输入选择: _
145
147
  ```
146
148
 
147
- ### 完整初始化流程(选择1或使用 `zcf i`)
149
+ ### 完整初始化流程(选择 1 或使用 `zcf i`)
148
150
 
149
151
  ```bash
150
152
  ? 选择 Claude Code 配置语言:
@@ -209,11 +211,11 @@ $ npx zcf
209
211
 
210
212
  #### 命令速查表
211
213
 
212
- | 命令 | 缩写 | 说明 |
213
- | ------------ | --------- | --------------------------------------- |
214
- | `zcf` | - | 显示交互式菜单(v2.0默认命令) |
215
- | `zcf init` | `zcf i` | 初始化 Claude Code 配置 |
216
- | `zcf update` | `zcf u` | 更新 Prompt 文档并备份旧配置 |
214
+ | 命令 | 缩写 | 说明 |
215
+ | ------------ | ------- | ------------------------------- |
216
+ | `zcf` | - | 显示交互式菜单(v2.0 默认命令) |
217
+ | `zcf init` | `zcf i` | 初始化 Claude Code 配置 |
218
+ | `zcf update` | `zcf u` | 更新 Prompt 文档并备份旧配置 |
217
219
 
218
220
  #### 常用选项
219
221
 
@@ -289,13 +291,13 @@ claude-code-config/
289
291
  └── dist/ # 构建输出
290
292
  ```
291
293
 
292
- ## ✨ 核心特性(v2.0增强)
294
+ ## ✨ 核心特性(v2.0 增强)
293
295
 
294
296
  ### 🤖 专业代理
295
297
 
296
298
  - **任务规划师**:将复杂任务拆解为可执行步骤
297
299
  - **UI/UX 设计师**:提供专业界面设计指导
298
- - **AI 个性化**:支持多种预设人格和自定义(v2.0新增)
300
+ - **AI 个性化**:支持多种预设人格和自定义(v2.0 新增)
299
301
 
300
302
  ### ⚡ 命令系统
301
303
 
@@ -307,19 +309,19 @@ claude-code-config/
307
309
  - API 密钥管理(支持部分修改)
308
310
  - 细粒度权限控制
309
311
  - 多种 Claude 模型支持(可配置默认模型)
310
- - 交互式菜单系统(v2.0新增)
311
- - AI 记忆管理(v2.0新增)
312
+ - 交互式菜单系统(v2.0 新增)
313
+ - AI 记忆管理(v2.0 新增)
312
314
 
313
315
  ## 🎯 开发工作流
314
316
 
315
317
  ### 六阶段工作流
316
318
 
317
- 1. **[模式:研究]** - 理解需求
318
- 2. **[模式:构思]** - 设计方案
319
- 3. **[模式:计划]** - 制定详细计划
320
- 4. **[模式:执行]** - 实施开发
321
- 5. **[模式:优化]** - 提升质量
322
- 6. **[模式:评审]** - 最终评估
319
+ 1. [模式:研究] - 理解需求
320
+ 2. [模式:构思] - 设计方案
321
+ 3. [模式:计划] - 制定详细计划
322
+ 4. [模式:执行] - 实施开发
323
+ 5. [模式:优化] - 提升质量
324
+ 6. [模式:评审] - 最终评估
323
325
 
324
326
  ## 🛠️ 开发
325
327
 
package/dist/cli.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import cac from 'cac';
3
2
  import ansis from 'ansis';
4
- import { z as displayBanner, B as selectScriptLanguage, D as readZcfConfig, I as I18N, S as SETTINGS_FILE, d as SUPPORTED_LANGS, L as LANG_LABELS, E as resolveAiOutputLanguage, F as updatePromptOnly, G as updateZcfConfig, H as version, Z as ZCF_CONFIG_FILE, p as applyAiLanguageDirective, J as configureAiPersonality, u as updateDefaultModel, K as isWindows, r as readMcpConfig, x as fixWindowsMcpConfig, w as writeMcpConfig, M as MCP_SERVICES, s as backupMcpConfig, v as buildMcpServerConfig, t as mergeMcpServers, o as getExistingApiConfig, N as formatApiKeyDisplay, O as modifyApiConfigPartially, P as validateApiKey, l as configureApi, Q as displayBannerWithInfo, i as init } from './shared/zcf.DAPPHkhV.mjs';
5
- import prompts from '@posva/prompts';
3
+ import cac from 'cac';
4
+ import { d as SUPPORTED_LANGS, I as I18N, L as LANG_LABELS, z as updateZcfConfig, Z as ZCF_CONFIG_FILE, B as readZcfConfig, D as resolveAiOutputLanguage, p as applyAiLanguageDirective, E as configureAiPersonality, u as updateDefaultModel, F as isWindows, r as readMcpConfig, x as fixWindowsMcpConfig, w as writeMcpConfig, G as selectMcpServices, s as backupMcpConfig, M as MCP_SERVICES, v as buildMcpServerConfig, t as mergeMcpServers, o as getExistingApiConfig, H as formatApiKeyDisplay, J as modifyApiConfigPartially, K as validateApiKey, l as configureApi, N as displayBanner, O as selectScriptLanguage, S as SETTINGS_FILE, P as updatePromptOnly, Q as version, R as handleExitPromptError, T as handleGeneralError, U as displayBannerWithInfo, i as init } from './shared/zcf.BAnSslet.mjs';
5
+ import inquirer from 'inquirer';
6
6
  import { existsSync, unlinkSync } from 'node:fs';
7
7
  import 'node:os';
8
8
  import 'pathe';
@@ -10,57 +10,6 @@ import 'dayjs';
10
10
  import 'node:url';
11
11
  import 'tinyexec';
12
12
 
13
- async function update(options = {}) {
14
- try {
15
- if (!options.skipBanner) {
16
- displayBanner("Update configuration for Claude Code");
17
- }
18
- const scriptLang = await selectScriptLanguage();
19
- const zcfConfig = readZcfConfig();
20
- const i18n = I18N[scriptLang];
21
- if (!existsSync(SETTINGS_FILE)) {
22
- console.log(ansis.yellow(i18n.noExistingConfig));
23
- process.exit(1);
24
- }
25
- let configLang = options.configLang;
26
- if (!configLang) {
27
- console.log(ansis.dim(` ${i18n.configLangHint["zh-CN"]}`));
28
- console.log(ansis.dim(` ${i18n.configLangHint["en"]}
29
- `));
30
- const configResponse = await prompts({
31
- type: "select",
32
- name: "lang",
33
- message: i18n.updateConfigLangPrompt,
34
- choices: SUPPORTED_LANGS.map((l) => ({
35
- title: `${LANG_LABELS[l]} - ${i18n.configLangHint[l]}`,
36
- value: l
37
- }))
38
- });
39
- if (!configResponse.lang) {
40
- console.log(ansis.yellow(i18n.cancelled));
41
- process.exit(0);
42
- }
43
- configLang = configResponse.lang;
44
- }
45
- const aiOutputLang = await resolveAiOutputLanguage(scriptLang, options.aiOutputLang, zcfConfig);
46
- console.log(ansis.cyan(`
47
- ${i18n.updatingPrompts}
48
- `));
49
- await updatePromptOnly(configLang, scriptLang, aiOutputLang);
50
- updateZcfConfig({
51
- version,
52
- preferredLang: scriptLang,
53
- aiOutputLang
54
- });
55
- } catch (error) {
56
- const zcfConfig = readZcfConfig();
57
- const defaultLang = zcfConfig?.preferredLang || "en";
58
- const errorMsg = I18N[defaultLang].error;
59
- console.error(ansis.red(`${errorMsg}:`), error);
60
- process.exit(1);
61
- }
62
- }
63
-
64
13
  function handleCancellation(scriptLang) {
65
14
  console.log(ansis.yellow(I18N[scriptLang].cancelled));
66
15
  }
@@ -73,55 +22,51 @@ async function configureApiFeature(scriptLang) {
73
22
  console.log(ansis.gray(` ${i18n.apiConfigKey}: ${existingApiConfig.key ? formatApiKeyDisplay(existingApiConfig.key) : i18n.notConfigured}`));
74
23
  console.log(ansis.gray(` ${i18n.apiConfigAuthType}: ${existingApiConfig.authType || i18n.notConfigured}
75
24
  `));
76
- const actionResponse = await prompts({
77
- type: "select",
25
+ const { action } = await inquirer.prompt({
26
+ type: "list",
78
27
  name: "action",
79
28
  message: i18n.selectApiAction,
80
29
  choices: [
81
- { title: i18n.keepExistingConfig, value: "keep" },
82
- { title: i18n.modifyAllConfig, value: "modify-all" },
83
- { title: i18n.modifyPartialConfig, value: "modify-partial" }
30
+ { name: i18n.keepExistingConfig, value: "keep" },
31
+ { name: i18n.modifyAllConfig, value: "modify-all" },
32
+ { name: i18n.modifyPartialConfig, value: "modify-partial" }
84
33
  ]
85
34
  });
86
- if (!actionResponse.action) {
35
+ if (!action) {
87
36
  handleCancellation(scriptLang);
88
37
  return;
89
38
  }
90
- if (actionResponse.action === "keep") {
39
+ if (action === "keep") {
91
40
  console.log(ansis.green(`\u2714 ${i18n.keepExistingConfig}`));
92
41
  return;
93
- } else if (actionResponse.action === "modify-partial") {
42
+ } else if (action === "modify-partial") {
94
43
  await modifyApiConfigPartially(existingApiConfig, i18n, scriptLang);
95
44
  return;
96
45
  }
97
46
  }
98
- const apiResponse = await prompts({
99
- type: "select",
47
+ const { apiChoice } = await inquirer.prompt({
48
+ type: "list",
100
49
  name: "apiChoice",
101
50
  message: i18n.configureApi,
102
51
  choices: [
103
52
  {
104
- title: i18n.useAuthToken,
53
+ name: `${i18n.useAuthToken} - ${ansis.gray(i18n.authTokenDesc)}`,
105
54
  value: "auth_token",
106
- description: ansis.gray(i18n.authTokenDesc)
55
+ short: i18n.useAuthToken
107
56
  },
108
57
  {
109
- title: i18n.useApiKey,
58
+ name: `${i18n.useApiKey} - ${ansis.gray(i18n.apiKeyDesc)}`,
110
59
  value: "api_key",
111
- description: ansis.gray(i18n.apiKeyDesc)
60
+ short: i18n.useApiKey
112
61
  },
113
- {
114
- title: i18n.skipApi,
115
- value: "skip"
116
- }
62
+ { name: i18n.skipApi, value: "skip" }
117
63
  ]
118
64
  });
119
- if (!apiResponse.apiChoice || apiResponse.apiChoice === "skip") {
65
+ if (!apiChoice || apiChoice === "skip") {
120
66
  return;
121
67
  }
122
- const apiChoice = apiResponse.apiChoice;
123
- const urlResponse = await prompts({
124
- type: "text",
68
+ const { url } = await inquirer.prompt({
69
+ type: "input",
125
70
  name: "url",
126
71
  message: i18n.enterApiUrl,
127
72
  validate: (value) => {
@@ -134,13 +79,13 @@ async function configureApiFeature(scriptLang) {
134
79
  }
135
80
  }
136
81
  });
137
- if (!urlResponse.url) {
82
+ if (!url) {
138
83
  handleCancellation(scriptLang);
139
84
  return;
140
85
  }
141
86
  const keyMessage = apiChoice === "auth_token" ? i18n.enterAuthToken : i18n.enterApiKey;
142
- const keyResponse = await prompts({
143
- type: "text",
87
+ const { key } = await inquirer.prompt({
88
+ type: "input",
144
89
  name: "key",
145
90
  message: keyMessage,
146
91
  validate: (value) => {
@@ -154,11 +99,11 @@ async function configureApiFeature(scriptLang) {
154
99
  return true;
155
100
  }
156
101
  });
157
- if (!keyResponse.key) {
102
+ if (!key) {
158
103
  handleCancellation(scriptLang);
159
104
  return;
160
105
  }
161
- const apiConfig = { url: urlResponse.url, key: keyResponse.key, authType: apiChoice };
106
+ const apiConfig = { url, key, authType: apiChoice };
162
107
  const configuredApi = configureApi(apiConfig);
163
108
  if (configuredApi) {
164
109
  console.log(ansis.green(`\u2714 ${i18n.apiConfigSuccess}`));
@@ -169,46 +114,23 @@ async function configureApiFeature(scriptLang) {
169
114
  async function configureMcpFeature(scriptLang) {
170
115
  const i18n = I18N[scriptLang];
171
116
  if (isWindows()) {
172
- const fixResponse = await prompts({
117
+ const { fixWindows } = await inquirer.prompt({
173
118
  type: "confirm",
174
119
  name: "fixWindows",
175
120
  message: i18n.fixWindowsMcp || "Fix Windows MCP configuration?",
176
- initial: true
121
+ default: true
177
122
  });
178
- if (fixResponse.fixWindows) {
123
+ if (fixWindows) {
179
124
  const existingConfig = readMcpConfig() || { mcpServers: {} };
180
125
  const fixedConfig = fixWindowsMcpConfig(existingConfig);
181
126
  writeMcpConfig(fixedConfig);
182
127
  console.log(ansis.green(`\u2714 ${i18n.windowsMcpFixed || "Windows MCP configuration fixed"}`));
183
128
  }
184
129
  }
185
- const choices = [
186
- {
187
- title: ansis.bold(i18n.allServices),
188
- value: "ALL",
189
- selected: false
190
- },
191
- ...MCP_SERVICES.map((service) => ({
192
- title: `${service.name[scriptLang]} - ${ansis.gray(service.description[scriptLang])}`,
193
- value: service.id,
194
- selected: false
195
- }))
196
- ];
197
- const selectedResponse = await prompts({
198
- type: "multiselect",
199
- name: "services",
200
- message: i18n.selectMcpServices,
201
- choices,
202
- instructions: false,
203
- hint: i18n.spaceToSelectReturn
204
- });
205
- if (!selectedResponse.services) {
130
+ const selectedServices = await selectMcpServices(scriptLang);
131
+ if (!selectedServices) {
206
132
  return;
207
133
  }
208
- let selectedServices = selectedResponse.services || [];
209
- if (selectedServices.includes("ALL")) {
210
- selectedServices = MCP_SERVICES.map((s) => s.id);
211
- }
212
134
  if (selectedServices.length > 0) {
213
135
  const mcpBackupPath = backupMcpConfig();
214
136
  if (mcpBackupPath) {
@@ -220,14 +142,14 @@ async function configureMcpFeature(scriptLang) {
220
142
  if (!service) continue;
221
143
  let config = service.config;
222
144
  if (service.requiresApiKey) {
223
- const apiKeyResponse = await prompts({
224
- type: "text",
145
+ const { apiKey } = await inquirer.prompt({
146
+ type: "input",
225
147
  name: "apiKey",
226
148
  message: service.apiKeyPrompt[scriptLang],
227
149
  validate: (value) => !!value || i18n.keyRequired
228
150
  });
229
- if (apiKeyResponse.apiKey) {
230
- config = buildMcpServerConfig(service.config, apiKeyResponse.apiKey, service.apiKeyPlaceholder);
151
+ if (apiKey) {
152
+ config = buildMcpServerConfig(service.config, apiKey, service.apiKeyPlaceholder);
231
153
  } else {
232
154
  continue;
233
155
  }
@@ -243,43 +165,43 @@ async function configureMcpFeature(scriptLang) {
243
165
  }
244
166
  async function configureDefaultModelFeature(scriptLang) {
245
167
  const i18n = I18N[scriptLang];
246
- const modelResponse = await prompts({
247
- type: "select",
168
+ const { model } = await inquirer.prompt({
169
+ type: "list",
248
170
  name: "model",
249
171
  message: i18n.selectDefaultModel || "Select default model",
250
172
  choices: [
251
- { title: "Opus", value: "opus" },
252
- { title: "Sonnet", value: "sonnet" }
173
+ { name: "Opus", value: "opus" },
174
+ { name: "Sonnet", value: "sonnet" }
253
175
  ]
254
176
  });
255
- if (!modelResponse.model) {
177
+ if (!model) {
256
178
  handleCancellation(scriptLang);
257
179
  return;
258
180
  }
259
- updateDefaultModel(modelResponse.model);
181
+ updateDefaultModel(model);
260
182
  console.log(ansis.green(`\u2714 ${i18n.modelConfigSuccess || "Default model configured"}`));
261
183
  }
262
184
  async function configureAiMemoryFeature(scriptLang) {
263
185
  const i18n = I18N[scriptLang];
264
- const memoryResponse = await prompts({
265
- type: "select",
186
+ const { option } = await inquirer.prompt({
187
+ type: "list",
266
188
  name: "option",
267
189
  message: i18n.selectMemoryOption || "Select configuration option",
268
190
  choices: [
269
191
  {
270
- title: i18n.configureAiLanguage || "Configure AI output language",
192
+ name: i18n.configureAiLanguage || "Configure AI output language",
271
193
  value: "language"
272
194
  },
273
195
  {
274
- title: i18n.configureAiPersonality || "Configure AI personality",
196
+ name: i18n.configureAiPersonality || "Configure AI personality",
275
197
  value: "personality"
276
198
  }
277
199
  ]
278
200
  });
279
- if (!memoryResponse.option) {
201
+ if (!option) {
280
202
  return;
281
203
  }
282
- if (memoryResponse.option === "language") {
204
+ if (option === "language") {
283
205
  const zcfConfig = readZcfConfig();
284
206
  const aiOutputLang = await resolveAiOutputLanguage(scriptLang, void 0, zcfConfig);
285
207
  applyAiLanguageDirective(aiOutputLang);
@@ -291,13 +213,13 @@ async function configureAiMemoryFeature(scriptLang) {
291
213
  }
292
214
  async function clearZcfCacheFeature(scriptLang) {
293
215
  const i18n = I18N[scriptLang];
294
- const confirmResponse = await prompts({
216
+ const { confirm } = await inquirer.prompt({
295
217
  type: "confirm",
296
218
  name: "confirm",
297
219
  message: i18n.confirmClearCache || "Clear all ZCF preferences cache?",
298
- initial: false
220
+ default: false
299
221
  });
300
- if (!confirmResponse.confirm) {
222
+ if (!confirm) {
301
223
  handleCancellation(scriptLang);
302
224
  return;
303
225
  }
@@ -310,22 +232,68 @@ async function clearZcfCacheFeature(scriptLang) {
310
232
  }
311
233
  async function changeScriptLanguageFeature(currentLang) {
312
234
  const i18n = I18N[currentLang];
313
- const langResponse = await prompts({
314
- type: "select",
235
+ const { lang } = await inquirer.prompt({
236
+ type: "list",
315
237
  name: "lang",
316
238
  message: i18n.selectScriptLang,
317
239
  choices: SUPPORTED_LANGS.map((l) => ({
318
- title: LANG_LABELS[l],
240
+ name: LANG_LABELS[l],
319
241
  value: l
320
242
  })),
321
- initial: SUPPORTED_LANGS.indexOf(currentLang)
243
+ default: SUPPORTED_LANGS.indexOf(currentLang)
322
244
  });
323
- if (!langResponse.lang) {
245
+ if (!lang) {
324
246
  return currentLang;
325
247
  }
326
- updateZcfConfig({ preferredLang: langResponse.lang });
327
- console.log(ansis.green(`\u2714 ${I18N[langResponse.lang].languageChanged || "Language changed"}`));
328
- return langResponse.lang;
248
+ updateZcfConfig({ preferredLang: lang });
249
+ console.log(ansis.green(`\u2714 ${I18N[lang].languageChanged || "Language changed"}`));
250
+ return lang;
251
+ }
252
+
253
+ async function update(options = {}) {
254
+ try {
255
+ if (!options.skipBanner) {
256
+ displayBanner("Update configuration for Claude Code");
257
+ }
258
+ const scriptLang = await selectScriptLanguage();
259
+ const zcfConfig = readZcfConfig();
260
+ const i18n = I18N[scriptLang];
261
+ if (!existsSync(SETTINGS_FILE)) {
262
+ console.log(ansis.yellow(i18n.noExistingConfig));
263
+ process.exit(1);
264
+ }
265
+ let configLang = options.configLang;
266
+ if (!configLang) {
267
+ const { lang } = await inquirer.prompt({
268
+ type: "list",
269
+ name: "lang",
270
+ message: i18n.updateConfigLangPrompt,
271
+ choices: SUPPORTED_LANGS.map((l) => ({
272
+ name: `${LANG_LABELS[l]} - ${i18n.configLangHint[l]}`,
273
+ value: l
274
+ }))
275
+ });
276
+ if (!lang) {
277
+ console.log(ansis.yellow(i18n.cancelled));
278
+ process.exit(0);
279
+ }
280
+ configLang = lang;
281
+ }
282
+ const aiOutputLang = await resolveAiOutputLanguage(scriptLang, options.aiOutputLang, zcfConfig);
283
+ console.log(ansis.cyan(`
284
+ ${i18n.updatingPrompts}
285
+ `));
286
+ await updatePromptOnly(configLang, scriptLang, aiOutputLang);
287
+ updateZcfConfig({
288
+ version,
289
+ preferredLang: scriptLang,
290
+ aiOutputLang
291
+ });
292
+ } catch (error) {
293
+ if (!handleExitPromptError(error)) {
294
+ handleGeneralError(error);
295
+ }
296
+ }
329
297
  }
330
298
 
331
299
  async function showMainMenu() {
@@ -378,8 +346,8 @@ async function showMainMenu() {
378
346
  );
379
347
  console.log(` ${ansis.red("q.")} ${ansis.red(i18n.menuOptions.exit)}`);
380
348
  console.log("");
381
- const response = await prompts({
382
- type: "text",
349
+ const { choice } = await inquirer.prompt({
350
+ type: "input",
383
351
  name: "choice",
384
352
  message: i18n.enterChoice || "Enter your choice",
385
353
  validate: (value) => {
@@ -387,12 +355,12 @@ async function showMainMenu() {
387
355
  return valid.includes(value) || i18n.invalidChoice;
388
356
  }
389
357
  });
390
- if (!response.choice) {
358
+ if (!choice) {
391
359
  console.log(ansis.yellow(i18n.cancelled));
392
360
  exitMenu = true;
393
361
  break;
394
362
  }
395
- switch (response.choice.toLowerCase()) {
363
+ switch (choice.toLowerCase()) {
396
364
  case "1":
397
365
  await init({ lang: scriptLang, skipBanner: true });
398
366
  break;
@@ -418,19 +386,6 @@ async function showMainMenu() {
418
386
  const newLang = await changeScriptLanguageFeature(scriptLang);
419
387
  if (newLang !== scriptLang) {
420
388
  scriptLang = newLang;
421
- console.log("\n" + ansis.dim("\u2500".repeat(50)) + "\n");
422
- const newI18n = I18N[scriptLang];
423
- const continueResponse = await prompts({
424
- type: "confirm",
425
- name: "continue",
426
- message: newI18n.returnToMenu,
427
- initial: true
428
- });
429
- if (!continueResponse.continue) {
430
- exitMenu = true;
431
- console.log(ansis.cyan(newI18n.goodbye));
432
- }
433
- continue;
434
389
  }
435
390
  break;
436
391
  case "q":
@@ -438,29 +393,28 @@ async function showMainMenu() {
438
393
  console.log(ansis.cyan(i18n.goodbye));
439
394
  break;
440
395
  }
441
- if (!exitMenu && response.choice.toLowerCase() !== "q") {
396
+ if (!exitMenu && choice.toLowerCase() !== "q") {
397
+ if (choice === "0" || choice === "-") {
398
+ console.log("\n" + ansis.dim("\u2500".repeat(50)) + "\n");
399
+ continue;
400
+ }
442
401
  console.log("\n" + ansis.dim("\u2500".repeat(50)) + "\n");
443
- const continueResponse = await prompts({
402
+ const { continue: shouldContinue } = await inquirer.prompt({
444
403
  type: "confirm",
445
404
  name: "continue",
446
405
  message: i18n.returnToMenu,
447
- initial: true
406
+ default: true
448
407
  });
449
- if (!continueResponse.continue) {
408
+ if (!shouldContinue) {
450
409
  exitMenu = true;
451
410
  console.log(ansis.cyan(i18n.goodbye));
452
411
  }
453
412
  }
454
413
  }
455
414
  } catch (error) {
456
- const zcfConfig = readZcfConfig();
457
- const defaultLang = zcfConfig?.preferredLang || "en";
458
- const errorMsg = I18N[defaultLang].error;
459
- console.error(ansis.red(`${errorMsg}:`), error);
460
- if (error instanceof Error) {
461
- console.error(ansis.gray(`Stack: ${error.stack}`));
415
+ if (!handleExitPromptError(error)) {
416
+ handleGeneralError(error);
462
417
  }
463
- process.exit(1);
464
418
  }
465
419
  }
466
420
 
@@ -496,7 +450,9 @@ cli.help((sections) => {
496
450
  title: ansis.yellow("Commands / \u547D\u4EE4:"),
497
451
  body: [
498
452
  ` ${ansis.cyan("zcf")} Show interactive menu (default) / \u663E\u793A\u4EA4\u4E92\u5F0F\u83DC\u5355\uFF08\u9ED8\u8BA4\uFF09`,
499
- ` ${ansis.cyan("zcf init")} | ${ansis.cyan("i")} Initialize Claude Code configuration / \u521D\u59CB\u5316 Claude Code \u914D\u7F6E`,
453
+ ` ${ansis.cyan("zcf init")} | ${ansis.cyan(
454
+ "i"
455
+ )} Initialize Claude Code configuration / \u521D\u59CB\u5316 Claude Code \u914D\u7F6E`,
500
456
  ` ${ansis.cyan("zcf update")} | ${ansis.cyan("u")} Update workflow-related md files / \u4EC5\u66F4\u65B0\u5DE5\u4F5C\u6D41\u76F8\u5173md`,
501
457
  "",
502
458
  ansis.gray(" Shortcuts / \u5FEB\u6377\u65B9\u5F0F:"),
package/dist/index.d.mts CHANGED
@@ -70,6 +70,10 @@ declare const I18N: {
70
70
  installSuccess: string;
71
71
  installFailed: string;
72
72
  npmNotFound: string;
73
+ termuxDetected: string;
74
+ termuxInstallHint: string;
75
+ termuxPathInfo: string;
76
+ termuxEnvironmentInfo: string;
73
77
  configureApi: string;
74
78
  useAuthToken: string;
75
79
  authTokenDesc: string;
@@ -224,6 +228,10 @@ declare const I18N: {
224
228
  installSuccess: string;
225
229
  installFailed: string;
226
230
  npmNotFound: string;
231
+ termuxDetected: string;
232
+ termuxInstallHint: string;
233
+ termuxPathInfo: string;
234
+ termuxEnvironmentInfo: string;
227
235
  configureApi: string;
228
236
  useAuthToken: string;
229
237
  authTokenDesc: string;
package/dist/index.d.ts CHANGED
@@ -70,6 +70,10 @@ declare const I18N: {
70
70
  installSuccess: string;
71
71
  installFailed: string;
72
72
  npmNotFound: string;
73
+ termuxDetected: string;
74
+ termuxInstallHint: string;
75
+ termuxPathInfo: string;
76
+ termuxEnvironmentInfo: string;
73
77
  configureApi: string;
74
78
  useAuthToken: string;
75
79
  authTokenDesc: string;
@@ -224,6 +228,10 @@ declare const I18N: {
224
228
  installSuccess: string;
225
229
  installFailed: string;
226
230
  npmNotFound: string;
231
+ termuxDetected: string;
232
+ termuxInstallHint: string;
233
+ termuxPathInfo: string;
234
+ termuxEnvironmentInfo: string;
227
235
  configureApi: string;
228
236
  useAuthToken: string;
229
237
  authTokenDesc: string;