zcf 3.2.2 → 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,3 @@
1
- # ZCF - Zero-Config Code Flow
2
-
3
1
  [![npm version][npm-version-src]][npm-version-href]
4
2
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
3
  [![License][license-src]][license-href]
@@ -8,13 +6,26 @@
8
6
  [![JSDocs][jsdocs-src]][jsdocs-href]
9
7
  [![Ask DeepWiki][deepwiki-src]][deepwiki-href]
10
8
 
11
- [中文](README_zh-CN.md) | **English** | [日本語](README_ja-JP.md) | [Changelog](CHANGELOG.md)
9
+ <div align="center">
10
+ <img src="./src/assets/banner.webp" alt="Banner"/>
11
+
12
+ <h1>
13
+ ZCF - Zero-Config Code Flow
14
+ </h1>
15
+
16
+ <p align="center">
17
+ <b>English</b> | <a href="README_zh-CN.md">中文</a> | <a href="README_ja-JP.md">日本語</a> | <a href="CHANGELOG.md">Changelog</a>
12
18
 
13
19
  **✨ Quick Links**: [Codex Support](#-codex-support-v300-new) | [BMad Workflow](#-bmad-workflow-v27-new-feature) | [Spec Workflow](#-spec-workflow-v2124-new-feature) | [Open Web Search](#-open-web-search-v2129-new-feature) | [CCR Router](#-ccr-claude-code-router-support-v28-enhanced) | [CCometixLine](#-ccometixline-support-status-bar-tool-v299-new) | [Output Styles](#-ai-output-styles-v212-new-feature) | [Multi-Configuration Management](#-multi-configuration-management-v320-new)
14
20
 
15
21
  > Zero-config, one-click setup for Claude Code & Codex with bilingual support, intelligent agent system and personalized AI assistant
22
+ </p>
23
+ </div>
16
24
 
17
- ![Rendering](./src/assets/screenshot-en.webp)
25
+ ## ♥️ Sponsor AI API
26
+
27
+ [![Sponsor AI API](./src/assets/302.ai-en.jpg)](https://share.302.ai/gAT9VG)
28
+ [302.AI](https://share.302.ai/gAT9VG) is a pay-as-you-go enterprise AI resource hub that offers the latest and most comprehensive AI models and APIs on the market, along with a variety of ready-to-use online AI applications.
18
29
 
19
30
  ## 🚀 Quick Start
20
31
 
@@ -211,6 +222,13 @@ ZCF allows seamless switching between Claude Code and Codex while preserving you
211
222
 
212
223
  ZCF now supports customizable AI output styles to personalize your Claude Code experience:
213
224
 
225
+ <p align="center">
226
+ <a href="https://github.com/Haleclipse">
227
+ <img src="./src/assets/Haleclipse.gif" alt="Halley-chan" width="200"/>
228
+ </a>
229
+ <div align="center">Tsundere <a href="https://github.com/Haleclipse">Halley-chan</a> Ojou-sama ( ̄▽ ̄)ゞ</div>
230
+ </p>
231
+
214
232
  **Available Output Styles:**
215
233
 
216
234
  - `engineer-professional`: Professional software engineer following SOLID, KISS, DRY, YAGNI principles
@@ -823,15 +841,26 @@ If you find this project helpful, please consider sponsoring its development. Yo
823
841
  ### Our Sponsors
824
842
 
825
843
  A huge thank you to all our sponsors for their generous support!
826
-
844
+ - [302.AI](https://share.302.ai/gAT9VG) (first corporate sponsorship 🤠)
827
845
  - Tc (first sponsor)
828
846
  - Argolinhas (first ko-fi sponsor ٩(•̤̀ᵕ•̤́๑))
829
- - r\*r (first anonymous sponsor🤣)
830
- - \*\*康 (first KFC sponsor🍗)
831
- - \*东 (first coffee sponsor☕️)
832
- - 炼\*3 (first Termux user sponsor📱)
847
+ - r\*r (first anonymous sponsor 🤣)
848
+ - \*\*康 (first KFC sponsor 🍗)
849
+ - \*东 (first coffee sponsor ☕️)
850
+ - 炼\*3 (first Termux user sponsor 📱)
833
851
  - [chamo101](https://github.com/chamo101) (first GitHub issue sponsor 🎉)
834
- - 16°C coffee (My best friend🤪, offered ChatGPT Pro $200 package)
852
+ - 初屿贤 (first Codex user sponsor 🙅🏻‍♂️)
853
+ - Protein (first 1688 sponsor 😏)
854
+ - [BeatSeat](https://github.com/BeatSeat) (community expert 😎, provided $1000 Claude credits)
855
+ - [wenwen](https://github.com/wenwen12345) (community expert 🤓, provided daily $100 Claude&GPT credits)
856
+ - 16°C coffee (My best friend 🤪, offered ChatGPT Pro $200 package)
857
+
858
+ ### Promotion Thanks
859
+
860
+ Thanks to the following authors for promoting this project:
861
+
862
+ - 逛逛 GitHub, article: https://mp.weixin.qq.com/s/phqwSRb16MKCHHVozTFeiQ
863
+ - Geek, tweet: https://x.com/geekbb/status/1955174718618866076
835
864
 
836
865
  ## 📄 License
837
866
 
@@ -839,6 +868,15 @@ A huge thank you to all our sponsors for their generous support!
839
868
 
840
869
  ---
841
870
 
871
+ ## 🚀 Contributors
872
+
873
+ <a href="https://github.com/UfoMiao/zcf/graphs/contributors">
874
+ <img src="https://contrib.rocks/image?repo=UfoMiao/zcf" />
875
+ </a>
876
+ <br /><br />
877
+
878
+ ## ⭐️ Star History
879
+
842
880
  If this project helps you, please give me a ⭐️ Star!
843
881
 
844
882
  [![Star History Chart](https://api.star-history.com/svg?repos=UfoMiao/zcf&type=Date)](https://star-history.com/#UfoMiao/zcf&Date)
@@ -131,9 +131,9 @@ ${i18n.t("multi-config:addingNewProfile")}`));
131
131
  }
132
132
  },
133
133
  {
134
- type: "password",
134
+ type: "input",
135
135
  name: "apiKey",
136
- message: i18n.t("multi-config:apiKeyPrompt") + i18n.t("common:inputHidden"),
136
+ message: i18n.t("multi-config:apiKeyPrompt"),
137
137
  when: (answers2) => answers2.authType !== "ccr_proxy",
138
138
  validate: (input) => {
139
139
  const trimmed = input.trim();
@@ -288,9 +288,9 @@ ${i18n.t("multi-config:editingProfile", { name: selectedProfile.name })}`));
288
288
  }
289
289
  },
290
290
  {
291
- type: "password",
291
+ type: "input",
292
292
  name: "apiKey",
293
- message: i18n.t("multi-config:apiKeyPrompt") + i18n.t("common:inputHidden"),
293
+ message: i18n.t("multi-config:apiKeyPrompt"),
294
294
  default: selectedProfile.apiKey,
295
295
  when: () => selectedProfile.authType !== "ccr_proxy",
296
296
  validate: (input) => {
@@ -91,9 +91,9 @@ async function handleAddProvider() {
91
91
  default: "responses"
92
92
  },
93
93
  {
94
- type: "password",
94
+ type: "input",
95
95
  name: "apiKey",
96
- message: i18n.t("codex:providerApiKeyPrompt") + i18n.t("common:inputHidden"),
96
+ message: i18n.t("codex:providerApiKeyPrompt"),
97
97
  validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
98
98
  }
99
99
  ]);
@@ -169,9 +169,9 @@ async function handleEditProvider(providers) {
169
169
  default: provider.wireApi
170
170
  },
171
171
  {
172
- type: "password",
172
+ type: "input",
173
173
  name: "apiKey",
174
- message: i18n.t("codex:providerApiKeyPrompt") + i18n.t("common:inputHidden"),
174
+ message: i18n.t("codex:providerApiKeyPrompt"),
175
175
  validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
176
176
  }
177
177
  ]);
@@ -16,7 +16,7 @@ import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
16
16
  import i18next from 'i18next';
17
17
  import Backend from 'i18next-fs-backend';
18
18
 
19
- const version = "3.2.2";
19
+ const version = "3.2.3";
20
20
  const homepage = "https://github.com/UfoMiao/zcf";
21
21
 
22
22
  const i18n = i18next.createInstance();
@@ -1666,9 +1666,9 @@ async function configureCcrWithPreset(preset) {
1666
1666
  if (preset.requiresApiKey) {
1667
1667
  try {
1668
1668
  const { apiKey } = await inquirer.prompt({
1669
- type: "password",
1669
+ type: "input",
1670
1670
  name: "apiKey",
1671
- message: i18n.t("ccr:enterApiKeyForProvider").replace("{provider}", preset.name) + i18n.t("common:inputHidden"),
1671
+ message: i18n.t("ccr:enterApiKeyForProvider").replace("{provider}", preset.name),
1672
1672
  validate: async (value) => !!value || i18n.t("api:keyRequired")
1673
1673
  });
1674
1674
  provider.api_key = apiKey;
@@ -2867,9 +2867,9 @@ async function configureCodexMcp(options) {
2867
2867
  if (configInfo.requiresApiKey && configInfo.apiKeyEnvVar) {
2868
2868
  const promptMessage = serviceMeta?.apiKeyPrompt || i18n.t("mcp:apiKeyPrompt");
2869
2869
  const { apiKey } = await inquirer.prompt([{
2870
- type: "password",
2870
+ type: "input",
2871
2871
  name: "apiKey",
2872
- message: promptMessage + i18n.t("common:inputHidden"),
2872
+ message: promptMessage,
2873
2873
  validate: (input) => !!input || i18n.t("api:keyRequired")
2874
2874
  }]);
2875
2875
  if (!apiKey)
@@ -3743,9 +3743,9 @@ async function configureCodexApi(options) {
3743
3743
  default: (answers2) => existingMap.get(sanitizeProviderName(answers2.providerName))?.wireApi || "responses"
3744
3744
  },
3745
3745
  {
3746
- type: "password",
3746
+ type: "input",
3747
3747
  name: "apiKey",
3748
- message: i18n.t("codex:providerApiKeyPrompt") + i18n.t("common:inputHidden"),
3748
+ message: i18n.t("codex:providerApiKeyPrompt"),
3749
3749
  validate: (input) => !!input || i18n.t("codex:providerApiKeyRequired")
3750
3750
  }
3751
3751
  ]);
@@ -4147,12 +4147,16 @@ async function resolveCodeType(codeTypeParam) {
4147
4147
  const validAbbreviations = Object.keys(CODE_TYPE_ABBREVIATIONS);
4148
4148
  const validFullTypes = Object.values(CODE_TYPE_ABBREVIATIONS);
4149
4149
  const validOptions = [...validAbbreviations, ...validFullTypes].join(", ");
4150
+ let defaultValue = DEFAULT_CODE_TOOL_TYPE;
4151
+ try {
4152
+ const config = await readZcfConfigAsync();
4153
+ if (config?.codeToolType && isValidCodeType(config.codeToolType)) {
4154
+ defaultValue = config.codeToolType;
4155
+ }
4156
+ } catch {
4157
+ }
4150
4158
  throw new Error(
4151
- i18n.t(
4152
- "errors:invalidCodeType",
4153
- `Invalid code type: "${codeTypeParam}". Valid options are: ${validOptions}.`,
4154
- { value: codeTypeParam, validOptions }
4155
- )
4159
+ i18n.t("errors:invalidCodeType", { value: codeTypeParam, validOptions, defaultValue })
4156
4160
  );
4157
4161
  }
4158
4162
  try {
@@ -4544,9 +4548,9 @@ async function configureApiCompletely(preselectedAuthType) {
4544
4548
  console.log(ansis.yellow(i18n.t("common:cancelled")));
4545
4549
  return null;
4546
4550
  }
4547
- const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") + i18n.t("common:inputHidden") : i18n.t("api:enterApiKey") + i18n.t("common:inputHidden");
4551
+ const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") : i18n.t("api:enterApiKey");
4548
4552
  const { key } = await inquirer.prompt({
4549
- type: "password",
4553
+ type: "input",
4550
4554
  name: "key",
4551
4555
  message: keyMessage,
4552
4556
  validate: async (value) => {
@@ -4617,9 +4621,9 @@ async function modifyApiConfigPartially(existingConfig) {
4617
4621
  }
4618
4622
  } else if (item === "key") {
4619
4623
  const authType = currentConfig.authType || "auth_token";
4620
- const keyMessage = authType === "auth_token" ? i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) + i18n.t("common:inputHidden") : i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) + i18n.t("common:inputHidden");
4624
+ const keyMessage = authType === "auth_token" ? i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) : i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none"));
4621
4625
  const { key } = await inquirer.prompt({
4622
- type: "password",
4626
+ type: "input",
4623
4627
  name: "key",
4624
4628
  message: keyMessage,
4625
4629
  validate: async (value) => {
@@ -5613,9 +5617,9 @@ async function init(options = {}) {
5613
5617
  continue;
5614
5618
  } else {
5615
5619
  const response = await inquirer.prompt({
5616
- type: "password",
5620
+ type: "input",
5617
5621
  name: "apiKey",
5618
- message: service.apiKeyPrompt + i18n.t("common:inputHidden"),
5622
+ message: service.apiKeyPrompt,
5619
5623
  validate: (value) => !!value || i18n.t("api:keyRequired")
5620
5624
  });
5621
5625
  if (!response.apiKey) {
package/dist/cli.mjs CHANGED
@@ -328,9 +328,9 @@ async function configureMcpFeature() {
328
328
  let config = service.config;
329
329
  if (service.requiresApiKey) {
330
330
  const { apiKey } = await inquirer.prompt({
331
- type: "password",
331
+ type: "input",
332
332
  name: "apiKey",
333
- message: service.apiKeyPrompt + i18n.t("common:inputHidden"),
333
+ message: service.apiKeyPrompt,
334
334
  validate: async (value) => !!value || i18n.t("api:keyRequired")
335
335
  });
336
336
  if (apiKey) {
@@ -2113,8 +2113,21 @@ async function showCodexMenu() {
2113
2113
  }
2114
2114
  return void 0;
2115
2115
  }
2116
- async function showMainMenu() {
2116
+ async function showMainMenu(options = {}) {
2117
2117
  try {
2118
+ if (options.codeType) {
2119
+ try {
2120
+ const resolvedType = await resolveCodeType$1(options.codeType);
2121
+ const currentType = getCurrentCodeTool();
2122
+ if (resolvedType !== currentType) {
2123
+ updateZcfConfig({ codeToolType: resolvedType });
2124
+ console.log(ansis.green(`\u2714 ${i18n.t("menu:codeToolSwitched", { tool: getCodeToolLabel(resolvedType) })}`));
2125
+ }
2126
+ } catch (err) {
2127
+ const errorMessage = err instanceof Error ? err.message : String(err);
2128
+ console.error(ansis.yellow(errorMessage));
2129
+ }
2130
+ }
2118
2131
  let exitMenu = false;
2119
2132
  while (!exitMenu) {
2120
2133
  const codeTool = getCurrentCodeTool();
@@ -2546,8 +2559,8 @@ async function setupCommands(cli) {
2546
2559
  await initI18n(defaultLang);
2547
2560
  } catch {
2548
2561
  }
2549
- cli.command("", "Show interactive menu (default)").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--force, -f", "Force overwrite existing configuration").option("--code-type, -T <codeType>", "Select code tool type (claude-code, codex, cc, cx)").action(await withLanguageResolution(async () => {
2550
- await showMainMenu();
2562
+ cli.command("", "Show interactive menu (default)").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--force, -f", "Force overwrite existing configuration").option("--code-type, -T <codeType>", "Select code tool type (claude-code, codex, cc, cx)").action(await withLanguageResolution(async (options) => {
2563
+ await showMainMenu({ codeType: options.codeType });
2551
2564
  }));
2552
2565
  cli.command("init", "Initialize Claude Code configuration").alias("i").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--ai-output-lang, -a <lang>", "AI output language").option("--force, -f", "Force overwrite existing configuration").option("--skip-prompt, -s", "Skip all interactive prompts (non-interactive mode)").option("--config-action, -r <action>", `Config handling (new/backup/merge/docs-only/skip), ${i18n.t("cli:help.defaults.prefix")} backup`).option("--api-type, -t <type>", "API type (auth_token/api_key/ccr_proxy/skip)").option("--api-key, -k <key>", "API key (used for both API key and auth token types)").option("--api-url, -u <url>", "Custom API URL").option("--api-model, -M <model>", "Primary API model (e.g., claude-sonnet-4-5)").option("--api-fast-model, -F <model>", "Fast API model (e.g., claude-haiku-4-5)").option("--mcp-services, -m <services>", `Comma-separated MCP services to install (context7,mcp-deepwiki,Playwright,exa), "skip" to skip all, "all" for all non-key services, ${i18n.t("cli:help.defaults.prefix")} all`).option("--workflows, -w <workflows>", `Comma-separated workflows to install (sixStepsWorkflow,featPlanUx,gitWorkflow,bmadWorkflow), "skip" to skip all, "all" for all workflows, ${i18n.t("cli:help.defaults.prefix")} all`).option("--output-styles, -o <styles>", `Comma-separated output styles (engineer-professional,nekomata-engineer,laowang-engineer,default,explanatory,learning), "skip" to skip all, "all" for all custom styles, ${i18n.t("cli:help.defaults.prefix")} all`).option("--default-output-style, -d <style>", `Default output style, ${i18n.t("cli:help.defaults.prefix")} engineer-professional`).option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--code-type, -T <codeType>", "Select code tool type (claude-code, codex, cc, cx)").option("--install-cometix-line, -x <value>", `Install CCometixLine statusline tool (true/false), ${i18n.t("cli:help.defaults.prefix")} true`).option("--api-configs <configs>", "API configurations as JSON string for multiple profiles").option("--api-configs-file <file>", "Path to JSON file containing API configurations").action(await withLanguageResolution(async (options) => {
2553
2566
  await init(options);
@@ -11,7 +11,6 @@
11
11
  "goodbye": "👋 Thanks for using ZCF! Goodbye!",
12
12
  "returnToMenu": "Return to main menu?",
13
13
  "back": "Back",
14
- "inputHidden": " (input will be hidden)",
15
14
  "operationFailed": "Operation failed",
16
15
  "backupCreated": "📁 Configuration backup created: {{path}}",
17
16
  "current": "current"
@@ -19,7 +19,7 @@
19
19
  "invalidAuthTokenConfig": "Invalid ANTHROPIC_AUTH_TOKEN: expected string",
20
20
  "invalidPermissionsConfig": "Invalid permissions configuration: expected object",
21
21
  "invalidPermissionsAllow": "Invalid permissions.allow: expected array",
22
- "invalidCodeType": "Invalid code type: \"{value}\". Valid options are: {validOptions}",
22
+ "invalidCodeType": "Invalid code type: \"{value}\". Valid options are: {validOptions}. Using default: {defaultValue}.",
23
23
  "generalError": "Error",
24
24
  "stackTrace": "Stack"
25
25
  }
@@ -11,7 +11,6 @@
11
11
  "goodbye": "👋 感谢使用 ZCF!再见!",
12
12
  "returnToMenu": "返回主菜单?",
13
13
  "back": "返回",
14
- "inputHidden": "(输入会被隐藏)",
15
14
  "operationFailed": "操作失败",
16
15
  "backupCreated": "📁 已创建配置备份:{{path}}",
17
16
  "current": "当前"
@@ -19,7 +19,7 @@
19
19
  "invalidAuthTokenConfig": "无效的 ANTHROPIC_AUTH_TOKEN:期望字符串类型",
20
20
  "invalidPermissionsConfig": "无效的权限配置:期望对象类型",
21
21
  "invalidPermissionsAllow": "无效的 permissions.allow:期望数组类型",
22
- "invalidCodeType": "无效的代码类型:\"{value}\"。可用的类型:{validOptions}",
22
+ "invalidCodeType": "无效的代码类型:\"{value}\"。可用的类型:{validOptions}。使用默认值:{defaultValue}。",
23
23
  "generalError": "错误",
24
24
  "stackTrace": "堆栈跟踪"
25
25
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zcf",
3
3
  "type": "module",
4
- "version": "3.2.2",
4
+ "version": "3.2.3",
5
5
  "description": "Zero-Config Code Flow - One-click configuration tool for Claude Code",
6
6
  "author": {
7
7
  "name": "Miao Da",