zcf 3.3.0 → 3.3.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/README.md CHANGED
@@ -27,6 +27,15 @@
27
27
  [![Sponsor AI API](./src/assets/302.ai-en.jpg)](https://share.302.ai/gAT9VG)
28
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.
29
29
 
30
+ ---
31
+
32
+ <table>
33
+ <tr>
34
+ <td width="180"><a href="https://www.packyapi.com/register?aff=zcf"><img src="./src/assets/packycode.png" alt="PackyCode" width="150"></a></td>
35
+ <td>Thanks to PackyCode for sponsoring this project! PackyCode is a reliable and efficient API relay service provider, offering relay services for Claude Code, Codex, Gemini, and more. PackyCode provides special discounts for our software users: register using <a href="https://www.packyapi.com/register?aff=zcf">this link</a> and enter the "zcf" promo code during recharge to get 10% off.</td>
36
+ </tr>
37
+ </table>
38
+
30
39
  ## 🚀 Quick Start
31
40
 
32
41
  ### 🎯 Recommended: Use Interactive Menu (v2.0 New)
@@ -130,6 +139,22 @@ npx zcf i --skip-prompt \
130
139
  --api-url "https://xxx.xxx" \
131
140
  --api-model "claude-sonnet-4-5" \
132
141
  --api-fast-model "claude-haiku-4-5"
142
+
143
+ # Multiple API configurations (JSON string)
144
+ npx zcf i -s --api-configs '[
145
+ {"provider":"302ai","key":"sk-xxx"},
146
+ {"provider":"glm","key":"sk-yyy"},
147
+ {"name":"custom","type":"api_key","key":"sk-zzz","url":"https://custom.api.com","primaryModel":"claude-sonnet-4-5","fastModel":"claude-haiku-4-5","default":true}
148
+ ]'
149
+
150
+ # Multiple API configurations (JSON file)
151
+ npx zcf i -s --api-configs-file ./api-configs.json
152
+
153
+ # For Codex with multiple providers
154
+ npx zcf i -s -T cx --api-configs '[
155
+ {"provider":"302ai","key":"sk-xxx"},
156
+ {"name":"custom","type":"api_key","key":"sk-yyy","url":"https://custom.api.com","primaryModel":"gpt-5","default":true}
157
+ ]'
133
158
  ```
134
159
 
135
160
  #### 🎯 API Provider Presets (v3.3.0+ New)
@@ -138,6 +163,7 @@ ZCF now supports API provider presets that automatically configure baseUrl and m
138
163
 
139
164
  **Supported Providers:**
140
165
  - `302ai` - [302.AI](https://share.302.ai/gAT9VG) API Service
166
+ - `packycode` - [PackyCode](https://www.packyapi.com/register?aff=zcf) API Service
141
167
  - `glm` - GLM (z.ai)
142
168
  - `minimax` - MiniMax API Service
143
169
  - `kimi` - Kimi (Moonshot AI)
@@ -151,6 +177,9 @@ npx zcf i --skip-prompt --provider 302ai --api-key "sk-xxx"
151
177
  # or shorthand
152
178
  npx zcf i -s -p 302ai -k "sk-xxx"
153
179
 
180
+ # Using PackyCode provider
181
+ npx zcf i -s -p packycode -k "sk-xxx"
182
+
154
183
  # Using GLM provider
155
184
  npx zcf i -s -p glm -k "sk-xxx"
156
185
 
@@ -181,7 +210,7 @@ When using `--skip-prompt`, the following parameters are available:
181
210
  | Parameter | Description | Values | Required | Default |
182
211
  | ---------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
183
212
  | `--skip-prompt, -s` | Skip all interactive prompts | - | Yes (for non-interactive mode) | - |
184
- | `--provider, -p` | API provider preset (v3.3.0+ New) | `302ai`, `glm`, `minimax`, `kimi`, `custom` | No | - (Simplifies configuration by auto-filling baseUrl and models) |
213
+ | `--provider, -p` | API provider preset (v3.3.0+ New) | `302ai`, `packycode`, `glm`, `minimax`, `kimi`, `custom` | No | - (Simplifies configuration by auto-filling baseUrl and models) |
185
214
  | `--lang, -l` | ZCF display language (applies to all commands) | `zh-CN`, `en` | No | `en` or user's saved preference |
186
215
  | `--config-lang, -c` | Configuration language (template files language) | `zh-CN`, `en` | No | `en` |
187
216
  | `--ai-output-lang, -a` | AI output language | `zh-CN`, `en`, custom string | No | `en` |
@@ -197,6 +226,9 @@ When using `--skip-prompt`, the following parameters are available:
197
226
  | `--output-styles, -o` | Output styles to install (multi-select, comma-separated) | `engineer-professional`, `nekomata-engineer`, `laowang-engineer`, `ojousama-engineer`, or `skip` for none | No | `all` |
198
227
  | `--default-output-style, -d` | Default output style | Same as output styles plus built-in: `default`, `explanatory`, `learning` | No | `engineer-professional` |
199
228
  | `--install-cometix-line, -x` | Install CCometixLine statusline tool | `true`, `false` | No | `true` |
229
+ | `--code-type, -T` | Target code tool type | `claude-code`, `codex`, `cc`, `cx` | No | Current active tool type from ZCF config |
230
+ | `--api-configs` | Multiple API configurations (JSON string) | JSON array string of API configuration objects | No | - (Mutually exclusive with `--api-configs-file`) |
231
+ | `--api-configs-file` | Multiple API configurations (JSON file path) | Path to JSON file containing API configuration array | No | - (Mutually exclusive with `--api-configs`) |
200
232
 
201
233
  #### 🤖 Codex Support (v3.0.0+ New)
202
234
 
@@ -270,7 +302,7 @@ ZCF now supports customizable AI output styles to personalize your Claude Code e
270
302
 
271
303
  <p align="center">
272
304
  <a href="https://github.com/Haleclipse">
273
- <img src="./src/assets/Haleclipse.gif" alt="Halley-chan" width="200"/>
305
+ <img src="./src/assets/Haleclipse.webp" alt="Halley-chan" width="200"/>
274
306
  </a>
275
307
  <div align="center">Tsundere <a href="https://github.com/Haleclipse">Halley-chan</a> Ojou-sama ( ̄▽ ̄)ゞ</div>
276
308
  </p>
@@ -454,6 +486,7 @@ ZCF provides flexible API configuration options for both Claude Code and Codex:
454
486
 
455
487
  Choose from popular API providers with pre-configured settings:
456
488
  - **302.AI** - Pay-as-you-go AI service with comprehensive model support
489
+ - **PackyCode** - PackyCode API Service
457
490
  - **GLM (智谱AI)** - Zhipu AI's GLM models
458
491
  - **MiniMax** - MiniMax AI service
459
492
  - **Kimi (Moonshot AI)** - Moonshot's Kimi models
@@ -911,6 +944,7 @@ If you find this project helpful, please consider sponsoring its development. Yo
911
944
 
912
945
  A huge thank you to all our sponsors for their generous support!
913
946
  - [302.AI](https://share.302.ai/gAT9VG) (first corporate sponsorship 🤠)
947
+ - [PackyCode](https://www.packyapi.com/register?aff=zcf) (first API proxy service sponsor 🧝🏻‍♀️)
914
948
  - Tc (first sponsor)
915
949
  - Argolinhas (first ko-fi sponsor ٩(•̤̀ᵕ•̤́๑))
916
950
  - r\*r (first anonymous sponsor 🤣)
@@ -920,6 +954,7 @@ A huge thank you to all our sponsors for their generous support!
920
954
  - [chamo101](https://github.com/chamo101) (first GitHub issue sponsor 🎉)
921
955
  - 初屿贤 (first Codex user sponsor 🙅🏻‍♂️)
922
956
  - Protein (first 1688 sponsor 😏)
957
+ - [musistudio](https://github.com/musistudio) (first open source project author sponsor, the author of [CCR](https://github.com/musistudio/claude-code-router) 🤩)
923
958
  - [BeatSeat](https://github.com/BeatSeat) (community expert 😎, provided $1000 Claude credits)
924
959
  - [wenwen](https://github.com/wenwen12345) (community expert 🤓, provided daily $100 Claude&GPT credits)
925
960
  - 16°C coffee (My best friend 🤪, offered ChatGPT Pro $200 package)
@@ -13,6 +13,20 @@ const API_PROVIDER_PRESETS = [
13
13
  },
14
14
  description: "302.AI API Service"
15
15
  },
16
+ {
17
+ id: "packycode",
18
+ name: "PackyCode",
19
+ supportedCodeTools: ["claude-code", "codex"],
20
+ claudeCode: {
21
+ baseUrl: "https://www.packyapi.com",
22
+ authType: "auth_token"
23
+ },
24
+ codex: {
25
+ baseUrl: "https://www.packyapi.com/v1",
26
+ wireApi: "responses"
27
+ },
28
+ description: "PackyCode API Service"
29
+ },
16
30
  {
17
31
  id: "glm",
18
32
  name: "GLM",
@@ -49,14 +63,13 @@ const API_PROVIDER_PRESETS = [
49
63
  name: "Kimi",
50
64
  supportedCodeTools: ["claude-code", "codex"],
51
65
  claudeCode: {
52
- baseUrl: "https://api.moonshot.cn/anthropic",
53
- authType: "auth_token",
54
- defaultModels: ["kimi-k2-0905-preview", "kimi-k2-turbo-preview"]
66
+ baseUrl: "https://api.kimi.com/coding/",
67
+ authType: "auth_token"
55
68
  },
56
69
  codex: {
57
- baseUrl: "https://api.moonshot.cn/v1",
70
+ baseUrl: "https://api.kimi.com/coding/v1",
58
71
  wireApi: "chat",
59
- defaultModel: "kimi-k2-0905-preview"
72
+ defaultModel: "kimi-for-coding"
60
73
  },
61
74
  description: "Kimi (Moonshot AI)"
62
75
  }
@@ -1,6 +1,6 @@
1
1
  import dayjs from 'dayjs';
2
2
  import { join } from 'pathe';
3
- import { j as ZCF_CONFIG_FILE, Z as ZCF_CONFIG_DIR, a9 as ensureDir, aa as readDefaultTomlConfig, ab as createDefaultTomlConfig, ac as exists, ad as readJsonConfig, ae as writeTomlConfig, S as SETTINGS_FILE, af as copyFile } from './simple-config.mjs';
3
+ import { q as ZCF_CONFIG_FILE, Z as ZCF_CONFIG_DIR, ae as ensureDir, af as readDefaultTomlConfig, ag as createDefaultTomlConfig, ah as exists, ai as readJsonConfig, aj as writeTomlConfig, S as SETTINGS_FILE, ak as copyFile } from './simple-config.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:process';
6
6
  import 'ansis';
@@ -182,15 +182,15 @@ class ClaudeCodeConfigManager {
182
182
  * Apply profile settings to Claude Code runtime
183
183
  */
184
184
  static async applyProfileSettings(profile) {
185
- const { ensureI18nInitialized, i18n } = await import('./simple-config.mjs').then(function (n) { return n.a$; });
185
+ const { ensureI18nInitialized, i18n } = await import('./simple-config.mjs').then(function (n) { return n.b4; });
186
186
  ensureI18nInitialized();
187
187
  try {
188
188
  if (!profile) {
189
- const { switchToOfficialLogin } = await import('./simple-config.mjs').then(function (n) { return n.b3; });
189
+ const { switchToOfficialLogin } = await import('./simple-config.mjs').then(function (n) { return n.b8; });
190
190
  switchToOfficialLogin();
191
191
  return;
192
192
  }
193
- const { readJsonConfig: readJsonConfig2, writeJsonConfig } = await import('./simple-config.mjs').then(function (n) { return n.b1; });
193
+ const { readJsonConfig: readJsonConfig2, writeJsonConfig } = await import('./simple-config.mjs').then(function (n) { return n.b6; });
194
194
  const settings = readJsonConfig2(SETTINGS_FILE) || {};
195
195
  if (!settings.env)
196
196
  settings.env = {};
@@ -202,7 +202,7 @@ class ClaudeCodeConfigManager {
202
202
  settings.env.ANTHROPIC_AUTH_TOKEN = profile.apiKey;
203
203
  delete settings.env.ANTHROPIC_API_KEY;
204
204
  } else if (profile.authType === "ccr_proxy") {
205
- const { readCcrConfig } = await import('./simple-config.mjs').then(function (n) { return n.b4; });
205
+ const { readCcrConfig } = await import('./simple-config.mjs').then(function (n) { return n.b9; });
206
206
  const ccrConfig = readCcrConfig();
207
207
  if (!ccrConfig) {
208
208
  throw new Error(i18n.t("ccr:ccrNotConfigured") || "CCR proxy configuration not found");
@@ -232,7 +232,7 @@ class ClaudeCodeConfigManager {
232
232
  delete settings.env.ANTHROPIC_SMALL_FAST_MODEL;
233
233
  }
234
234
  writeJsonConfig(SETTINGS_FILE, settings);
235
- const { setPrimaryApiKey, addCompletedOnboarding } = await import('./simple-config.mjs').then(function (n) { return n.b2; });
235
+ const { setPrimaryApiKey, addCompletedOnboarding } = await import('./simple-config.mjs').then(function (n) { return n.b7; });
236
236
  setPrimaryApiKey();
237
237
  addCompletedOnboarding();
238
238
  if (shouldRestartCcr) {
@@ -589,7 +589,7 @@ class ClaudeCodeConfigManager {
589
589
  */
590
590
  static async syncCcrProfile() {
591
591
  try {
592
- const { readCcrConfig } = await import('./simple-config.mjs').then(function (n) { return n.b4; });
592
+ const { readCcrConfig } = await import('./simple-config.mjs').then(function (n) { return n.b9; });
593
593
  const ccrConfig = readCcrConfig();
594
594
  if (!ccrConfig) {
595
595
  await this.ensureCcrProfileExists(ccrConfig);
@@ -1,6 +1,6 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
- import { a5 as ensureI18nInitialized, a6 as i18n, a7 as addNumbersToChoices, a8 as validateApiKey } from './simple-config.mjs';
3
+ import { aa as ensureI18nInitialized, ab as i18n, ac as addNumbersToChoices, ad as validateApiKey } from './simple-config.mjs';
4
4
  import { ClaudeCodeConfigManager } from './claude-code-config-manager.mjs';
5
5
  import 'node:fs';
6
6
  import 'node:process';
@@ -48,6 +48,7 @@ async function configureIncrementalManagement() {
48
48
  const choices = [
49
49
  { name: i18n.t("multi-config:addProfile"), value: "add" },
50
50
  { name: i18n.t("multi-config:editProfile"), value: "edit" },
51
+ { name: i18n.t("multi-config:copyProfile"), value: "copy" },
51
52
  { name: i18n.t("multi-config:deleteProfile"), value: "delete" },
52
53
  { name: i18n.t("common:skip"), value: "skip" }
53
54
  ];
@@ -68,6 +69,9 @@ async function configureIncrementalManagement() {
68
69
  case "edit":
69
70
  await handleEditProfile(profiles);
70
71
  break;
72
+ case "copy":
73
+ await handleCopyProfile(profiles);
74
+ break;
71
75
  case "delete":
72
76
  await handleDeleteProfile(profiles);
73
77
  break;
@@ -99,11 +103,13 @@ ${i18n.t("multi-config:addingNewProfile")}`));
99
103
  }]);
100
104
  let prefilledBaseUrl;
101
105
  let prefilledAuthType;
106
+ let prefilledDefaultModels;
102
107
  if (selectedProvider !== "custom") {
103
108
  const provider = providers.find((p) => p.id === selectedProvider);
104
109
  if (provider?.claudeCode) {
105
110
  prefilledBaseUrl = provider.claudeCode.baseUrl;
106
111
  prefilledAuthType = provider.claudeCode.authType;
112
+ prefilledDefaultModels = provider.claudeCode.defaultModels;
107
113
  console.log(ansis.gray(i18n.t("api:providerSelected", { name: provider.name })));
108
114
  }
109
115
  }
@@ -204,6 +210,13 @@ ${i18n.t("multi-config:addingNewProfile")}`));
204
210
  if (modelConfig.fastModel.trim()) {
205
211
  profile.fastModel = modelConfig.fastModel.trim();
206
212
  }
213
+ } else if (prefilledDefaultModels?.length) {
214
+ if (prefilledDefaultModels[0]?.trim()) {
215
+ profile.primaryModel = prefilledDefaultModels[0].trim();
216
+ }
217
+ if (prefilledDefaultModels[1]?.trim()) {
218
+ profile.fastModel = prefilledDefaultModels[1].trim();
219
+ }
207
220
  }
208
221
  const existingProfile = ClaudeCodeConfigManager.getProfileByName(profile.name);
209
222
  if (existingProfile) {
@@ -348,12 +361,28 @@ ${i18n.t("multi-config:editingProfile", { name: selectedProfile.name })}`));
348
361
  }
349
362
  }
350
363
  ]);
364
+ let modelConfig = null;
365
+ if (selectedProfile.authType !== "ccr_proxy") {
366
+ const { promptCustomModels } = await import('./features.mjs');
367
+ modelConfig = await promptCustomModels(
368
+ selectedProfile.primaryModel,
369
+ selectedProfile.fastModel
370
+ );
371
+ }
351
372
  const updateData = {
352
373
  name: answers.profileName.trim()
353
374
  };
354
375
  if (selectedProfile.authType !== "ccr_proxy") {
355
376
  updateData.apiKey = answers.apiKey.trim();
356
377
  updateData.baseUrl = answers.baseUrl.trim();
378
+ if (modelConfig) {
379
+ if (modelConfig.primaryModel.trim()) {
380
+ updateData.primaryModel = modelConfig.primaryModel.trim();
381
+ }
382
+ if (modelConfig.fastModel.trim()) {
383
+ updateData.fastModel = modelConfig.fastModel.trim();
384
+ }
385
+ }
357
386
  }
358
387
  const result = await ClaudeCodeConfigManager.updateProfile(selectedProfile.id, updateData);
359
388
  if (result.success) {
@@ -373,6 +402,140 @@ ${i18n.t("multi-config:editingProfile", { name: selectedProfile.name })}`));
373
402
  console.log(ansis.red(i18n.t("multi-config:profileUpdateFailed", { error: result.error })));
374
403
  }
375
404
  }
405
+ async function handleCopyProfile(profiles) {
406
+ const choices = profiles.map((profile) => ({
407
+ name: `${profile.name} (${getAuthTypeLabel(profile.authType)})`,
408
+ value: profile.id
409
+ }));
410
+ const { selectedProfileId } = await inquirer.prompt([{
411
+ type: "list",
412
+ name: "selectedProfileId",
413
+ message: i18n.t("multi-config:selectProfileToCopy"),
414
+ choices: addNumbersToChoices(choices)
415
+ }]);
416
+ if (!selectedProfileId) {
417
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
418
+ return;
419
+ }
420
+ const selectedProfile = profiles.find((p) => p.id === selectedProfileId);
421
+ if (!selectedProfile) {
422
+ console.log(ansis.red(i18n.t("multi-config:profileNotFound")));
423
+ return;
424
+ }
425
+ console.log(ansis.cyan(`
426
+ ${i18n.t("multi-config:copyingProfile", { name: selectedProfile.name })}`));
427
+ const copiedName = `${selectedProfile.name}-copy`;
428
+ const questions = [
429
+ {
430
+ type: "input",
431
+ name: "profileName",
432
+ message: i18n.t("multi-config:profileNamePrompt"),
433
+ default: copiedName,
434
+ validate: (input) => {
435
+ const trimmed = input.trim();
436
+ if (!trimmed) {
437
+ return i18n.t("multi-config:profileNameRequired");
438
+ }
439
+ if (!/^[\w\-\s.\u4E00-\u9FA5]+$/.test(trimmed)) {
440
+ return i18n.t("multi-config:profileNameInvalid");
441
+ }
442
+ return true;
443
+ }
444
+ }
445
+ ];
446
+ if (selectedProfile.authType !== "ccr_proxy") {
447
+ questions.push(
448
+ {
449
+ type: "input",
450
+ name: "baseUrl",
451
+ message: i18n.t("multi-config:baseUrlPrompt"),
452
+ default: selectedProfile.baseUrl || "https://api.anthropic.com",
453
+ validate: (input) => {
454
+ const trimmed = input.trim();
455
+ if (!trimmed) {
456
+ return i18n.t("multi-config:baseUrlRequired");
457
+ }
458
+ try {
459
+ new URL(trimmed);
460
+ return true;
461
+ } catch {
462
+ return i18n.t("multi-config:baseUrlInvalid");
463
+ }
464
+ }
465
+ },
466
+ {
467
+ type: "input",
468
+ name: "apiKey",
469
+ message: i18n.t("multi-config:apiKeyPrompt"),
470
+ default: selectedProfile.apiKey,
471
+ validate: (input) => {
472
+ const trimmed = input.trim();
473
+ if (!trimmed) {
474
+ return i18n.t("multi-config:apiKeyRequired");
475
+ }
476
+ const validation = validateApiKey(trimmed);
477
+ if (!validation.isValid) {
478
+ return validation.error || "Invalid API key format";
479
+ }
480
+ return true;
481
+ }
482
+ }
483
+ );
484
+ }
485
+ const answers = await inquirer.prompt(questions);
486
+ let modelConfig = null;
487
+ if (selectedProfile.authType !== "ccr_proxy") {
488
+ const { promptCustomModels } = await import('./features.mjs');
489
+ modelConfig = await promptCustomModels(
490
+ selectedProfile.primaryModel,
491
+ selectedProfile.fastModel
492
+ );
493
+ }
494
+ const { setAsDefault } = await inquirer.prompt([
495
+ {
496
+ type: "confirm",
497
+ name: "setAsDefault",
498
+ message: i18n.t("multi-config:setAsDefaultPrompt"),
499
+ default: false
500
+ }
501
+ ]);
502
+ const profileName = answers.profileName.trim();
503
+ const profileId = ClaudeCodeConfigManager.generateProfileId(profileName);
504
+ const copiedProfile = {
505
+ id: profileId,
506
+ name: profileName,
507
+ authType: selectedProfile.authType
508
+ };
509
+ if (selectedProfile.authType !== "ccr_proxy") {
510
+ copiedProfile.apiKey = answers.apiKey.trim();
511
+ copiedProfile.baseUrl = answers.baseUrl.trim();
512
+ if (modelConfig) {
513
+ if (modelConfig.primaryModel.trim()) {
514
+ copiedProfile.primaryModel = modelConfig.primaryModel.trim();
515
+ }
516
+ if (modelConfig.fastModel.trim()) {
517
+ copiedProfile.fastModel = modelConfig.fastModel.trim();
518
+ }
519
+ }
520
+ }
521
+ const result = await ClaudeCodeConfigManager.addProfile(copiedProfile);
522
+ if (result.success) {
523
+ const runtimeProfile = result.addedProfile || { ...copiedProfile, id: profileId };
524
+ console.log(ansis.green(i18n.t("multi-config:profileCopied", { name: runtimeProfile.name })));
525
+ if (result.backupPath) {
526
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
527
+ }
528
+ if (setAsDefault) {
529
+ const switchResult = await ClaudeCodeConfigManager.switchProfile(runtimeProfile.id);
530
+ if (switchResult.success) {
531
+ console.log(ansis.green(i18n.t("multi-config:profileSetAsDefault", { name: runtimeProfile.name })));
532
+ await ClaudeCodeConfigManager.applyProfileSettings(runtimeProfile);
533
+ }
534
+ }
535
+ } else {
536
+ console.log(ansis.red(i18n.t("multi-config:profileCopyFailed", { error: result.error })));
537
+ }
538
+ }
376
539
  async function handleDeleteProfile(profiles) {
377
540
  if (profiles.length <= 1) {
378
541
  console.log(ansis.yellow(i18n.t("multi-config:cannotDeleteLast")));
@@ -1,7 +1,7 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
- import { a5 as ensureI18nInitialized, ag as detectConfigManagementMode, a6 as i18n, a7 as addNumbersToChoices } from './simple-config.mjs';
4
- import { deleteProviders, editExistingProvider, addProviderToExisting } from './codex-provider-manager.mjs';
3
+ import { aa as ensureI18nInitialized, al as detectConfigManagementMode, ab as i18n, ac as addNumbersToChoices, ai as readJsonConfig, l as CODEX_AUTH_FILE } from './simple-config.mjs';
4
+ import { deleteProviders, addProviderToExisting, editExistingProvider } from './codex-provider-manager.mjs';
5
5
  import 'node:fs';
6
6
  import 'node:process';
7
7
  import 'node:child_process';
@@ -33,6 +33,7 @@ async function configureIncrementalManagement() {
33
33
  const choices = [
34
34
  { name: i18n.t("codex:addProvider"), value: "add" },
35
35
  { name: i18n.t("codex:editProvider"), value: "edit" },
36
+ { name: i18n.t("codex:copyProvider"), value: "copy" },
36
37
  { name: i18n.t("codex:deleteProvider"), value: "delete" },
37
38
  { name: i18n.t("common:skip"), value: "skip" }
38
39
  ];
@@ -53,6 +54,9 @@ async function configureIncrementalManagement() {
53
54
  case "edit":
54
55
  await handleEditProvider(managementMode.providers);
55
56
  break;
57
+ case "copy":
58
+ await handleCopyProvider(managementMode.providers);
59
+ break;
56
60
  case "delete":
57
61
  await handleDeleteProvider(managementMode.providers);
58
62
  break;
@@ -165,7 +169,7 @@ async function handleAddProvider() {
165
169
  default: true
166
170
  }]);
167
171
  if (setAsDefault) {
168
- const { switchToProvider } = await import('./simple-config.mjs').then(function (n) { return n.b6; });
172
+ const { switchToProvider } = await import('./simple-config.mjs').then(function (n) { return n.bb; });
169
173
  const switched = await switchToProvider(provider.id);
170
174
  if (switched) {
171
175
  console.log(ansis.green(i18n.t("multi-config:profileSetAsDefault", { name: provider.name })));
@@ -195,6 +199,8 @@ async function handleEditProvider(providers) {
195
199
  console.log(ansis.red(i18n.t("codex:providerNotFound")));
196
200
  return;
197
201
  }
202
+ const existingAuth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
203
+ const existingApiKey = existingAuth[provider.envKey] || "";
198
204
  const answers = await inquirer.prompt([
199
205
  {
200
206
  type: "input",
@@ -231,14 +237,26 @@ async function handleEditProvider(providers) {
231
237
  type: "input",
232
238
  name: "apiKey",
233
239
  message: i18n.t("codex:providerApiKeyPrompt"),
240
+ default: existingApiKey,
241
+ // Show old API key from auth.json
234
242
  validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
235
243
  }
236
244
  ]);
245
+ const { model } = await inquirer.prompt([
246
+ {
247
+ type: "input",
248
+ name: "model",
249
+ message: i18n.t("codex:providerModelPrompt"),
250
+ default: provider.model || "gpt-5-codex",
251
+ validate: (input) => !!input.trim() || i18n.t("codex:providerModelRequired")
252
+ }
253
+ ]);
237
254
  const updates = {
238
255
  name: answers.providerName.trim(),
239
256
  baseUrl: answers.baseUrl.trim(),
240
257
  wireApi: answers.wireApi,
241
- apiKey: answers.apiKey.trim()
258
+ apiKey: answers.apiKey.trim(),
259
+ model: model.trim()
242
260
  };
243
261
  const result = await editExistingProvider(selectedProviderId, updates);
244
262
  if (result.success) {
@@ -250,6 +268,114 @@ async function handleEditProvider(providers) {
250
268
  console.log(ansis.red(i18n.t("codex:providerUpdateFailed", { error: result.error })));
251
269
  }
252
270
  }
271
+ async function handleCopyProvider(providers) {
272
+ const choices = providers.map((provider2) => ({
273
+ name: `${provider2.name} (${provider2.baseUrl})`,
274
+ value: provider2.id
275
+ }));
276
+ const { selectedProviderId } = await inquirer.prompt([{
277
+ type: "list",
278
+ name: "selectedProviderId",
279
+ message: i18n.t("codex:selectProviderToCopy"),
280
+ choices: addNumbersToChoices(choices)
281
+ }]);
282
+ if (!selectedProviderId) {
283
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
284
+ return;
285
+ }
286
+ const provider = providers.find((p) => p.id === selectedProviderId);
287
+ if (!provider) {
288
+ console.log(ansis.red(i18n.t("codex:providerNotFound")));
289
+ return;
290
+ }
291
+ console.log(ansis.cyan(`
292
+ ${i18n.t("codex:copyingProvider", { name: provider.name })}`));
293
+ const existingAuth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
294
+ const existingApiKey = existingAuth[provider.envKey] || "";
295
+ const copiedName = `${provider.name}-copy`;
296
+ const answers = await inquirer.prompt([
297
+ {
298
+ type: "input",
299
+ name: "providerName",
300
+ message: i18n.t("codex:providerNamePrompt"),
301
+ default: copiedName,
302
+ validate: (input) => {
303
+ const trimmed = input.trim();
304
+ if (!trimmed)
305
+ return i18n.t("codex:providerNameRequired");
306
+ if (!/^[\w\-\s.]+$/.test(trimmed))
307
+ return i18n.t("codex:providerNameInvalid");
308
+ return true;
309
+ }
310
+ },
311
+ {
312
+ type: "input",
313
+ name: "baseUrl",
314
+ message: i18n.t("codex:providerBaseUrlPrompt"),
315
+ default: provider.baseUrl,
316
+ validate: (input) => !!input.trim() || i18n.t("codex:providerBaseUrlRequired")
317
+ },
318
+ {
319
+ type: "list",
320
+ name: "wireApi",
321
+ message: i18n.t("codex:providerProtocolPrompt"),
322
+ choices: [
323
+ { name: i18n.t("codex:protocolResponses"), value: "responses" },
324
+ { name: i18n.t("codex:protocolChat"), value: "chat" }
325
+ ],
326
+ default: provider.wireApi
327
+ },
328
+ {
329
+ type: "input",
330
+ name: "apiKey",
331
+ message: i18n.t("codex:providerApiKeyPrompt"),
332
+ default: existingApiKey,
333
+ // Show old API key from auth.json
334
+ validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
335
+ }
336
+ ]);
337
+ const { model } = await inquirer.prompt([
338
+ {
339
+ type: "input",
340
+ name: "model",
341
+ message: i18n.t("codex:providerModelPrompt"),
342
+ default: provider.model || "gpt-5-codex",
343
+ validate: (input) => !!input.trim() || i18n.t("codex:providerModelRequired")
344
+ }
345
+ ]);
346
+ const providerId = answers.providerName.trim().toLowerCase().replace(/\s+/g, "-").replace(/\./g, "-").replace(/[^a-z0-9\-]/g, "");
347
+ const copiedProvider = {
348
+ id: providerId,
349
+ name: answers.providerName.trim(),
350
+ baseUrl: answers.baseUrl.trim(),
351
+ wireApi: answers.wireApi,
352
+ envKey: `${providerId.toUpperCase().replace(/-/g, "_")}_API_KEY`,
353
+ requiresOpenaiAuth: provider.requiresOpenaiAuth ?? true,
354
+ model: model.trim()
355
+ };
356
+ const result = await addProviderToExisting(copiedProvider, answers.apiKey.trim(), false);
357
+ if (result.success) {
358
+ console.log(ansis.green(i18n.t("codex:providerCopied", { name: result.addedProvider?.name })));
359
+ if (result.backupPath) {
360
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
361
+ }
362
+ const { setAsDefault } = await inquirer.prompt([{
363
+ type: "confirm",
364
+ name: "setAsDefault",
365
+ message: i18n.t("multi-config:setAsDefaultPrompt"),
366
+ default: false
367
+ }]);
368
+ if (setAsDefault) {
369
+ const { switchToProvider } = await import('./simple-config.mjs').then(function (n) { return n.bb; });
370
+ const switched = await switchToProvider(copiedProvider.id);
371
+ if (switched) {
372
+ console.log(ansis.green(i18n.t("multi-config:profileSetAsDefault", { name: copiedProvider.name })));
373
+ }
374
+ }
375
+ } else {
376
+ console.log(ansis.red(i18n.t("codex:providerCopyFailed", { error: result.error })));
377
+ }
378
+ }
253
379
  async function handleDeleteProvider(providers) {
254
380
  const choices = providers.map((provider) => ({
255
381
  name: `${provider.name} (${provider.baseUrl})`,
@@ -1,4 +1,4 @@
1
- import { ah as readCodexConfig, ai as backupCodexComplete, aj as writeCodexConfig, ak as writeAuthFile } from './simple-config.mjs';
1
+ import { am as readCodexConfig, an as backupCodexComplete, ao as writeCodexConfig, ap as writeAuthFile } from './simple-config.mjs';
2
2
  import 'node:fs';
3
3
  import 'node:process';
4
4
  import 'ansis';
@@ -106,7 +106,8 @@ async function editExistingProvider(providerId, updates) {
106
106
  ...existingConfig.providers[providerIndex],
107
107
  ...updates.name && { name: updates.name },
108
108
  ...updates.baseUrl && { baseUrl: updates.baseUrl },
109
- ...updates.wireApi && { wireApi: updates.wireApi }
109
+ ...updates.wireApi && { wireApi: updates.wireApi },
110
+ ...updates.model && { model: updates.model }
110
111
  };
111
112
  const updatedProviders = [...existingConfig.providers];
112
113
  updatedProviders[providerIndex] = updatedProvider;
@@ -1,14 +1,14 @@
1
- import { homedir } from 'node:os';
2
1
  import { pathExists } from 'fs-extra';
3
2
  import { join } from 'pathe';
4
3
  import { exec } from 'tinyexec';
5
- import { a6 as i18n } from './simple-config.mjs';
4
+ import { j as CODEX_DIR, k as CODEX_CONFIG_FILE, ab as i18n, l as CODEX_AUTH_FILE, n as CODEX_AGENTS_FILE, p as CODEX_PROMPTS_DIR } from './simple-config.mjs';
6
5
  import { m as moveToTrash } from '../shared/zcf.DGjQxTq_.mjs';
7
6
  import 'node:fs';
8
7
  import 'node:process';
9
8
  import 'ansis';
10
9
  import 'inquirer';
11
10
  import 'node:child_process';
11
+ import 'node:os';
12
12
  import 'node:util';
13
13
  import 'dayjs';
14
14
  import 'node:url';
@@ -23,12 +23,7 @@ import 'trash';
23
23
  class CodexUninstaller {
24
24
  _lang;
25
25
  conflictResolution = /* @__PURE__ */ new Map();
26
- CODEX_DIR = join(homedir(), ".codex");
27
- CODEX_CONFIG_FILE = join(this.CODEX_DIR, "config.toml");
28
- CODEX_AUTH_FILE = join(this.CODEX_DIR, "auth.json");
29
- CODEX_AGENTS_FILE = join(this.CODEX_DIR, "AGENTS.md");
30
- CODEX_PROMPTS_DIR = join(this.CODEX_DIR, "prompts");
31
- CODEX_BACKUP_DIR = join(this.CODEX_DIR, "backup");
26
+ CODEX_BACKUP_DIR = join(CODEX_DIR, "backup");
32
27
  constructor(lang = "en") {
33
28
  this._lang = lang;
34
29
  this.conflictResolution.set("cli-package", ["config", "auth"]);
@@ -47,8 +42,8 @@ class CodexUninstaller {
47
42
  warnings: []
48
43
  };
49
44
  try {
50
- if (await pathExists(this.CODEX_CONFIG_FILE)) {
51
- const trashResult = await moveToTrash(this.CODEX_CONFIG_FILE);
45
+ if (await pathExists(CODEX_CONFIG_FILE)) {
46
+ const trashResult = await moveToTrash(CODEX_CONFIG_FILE);
52
47
  if (!trashResult[0]?.success) {
53
48
  result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
54
49
  }
@@ -75,8 +70,8 @@ class CodexUninstaller {
75
70
  warnings: []
76
71
  };
77
72
  try {
78
- if (await pathExists(this.CODEX_AUTH_FILE)) {
79
- const trashResult = await moveToTrash(this.CODEX_AUTH_FILE);
73
+ if (await pathExists(CODEX_AUTH_FILE)) {
74
+ const trashResult = await moveToTrash(CODEX_AUTH_FILE);
80
75
  if (!trashResult[0]?.success) {
81
76
  result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
82
77
  }
@@ -103,8 +98,8 @@ class CodexUninstaller {
103
98
  warnings: []
104
99
  };
105
100
  try {
106
- if (await pathExists(this.CODEX_AGENTS_FILE)) {
107
- const trashResult = await moveToTrash(this.CODEX_AGENTS_FILE);
101
+ if (await pathExists(CODEX_AGENTS_FILE)) {
102
+ const trashResult = await moveToTrash(CODEX_AGENTS_FILE);
108
103
  if (!trashResult[0]?.success) {
109
104
  result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
110
105
  }
@@ -131,8 +126,8 @@ class CodexUninstaller {
131
126
  warnings: []
132
127
  };
133
128
  try {
134
- if (await pathExists(this.CODEX_PROMPTS_DIR)) {
135
- const trashResult = await moveToTrash(this.CODEX_PROMPTS_DIR);
129
+ if (await pathExists(CODEX_PROMPTS_DIR)) {
130
+ const trashResult = await moveToTrash(CODEX_PROMPTS_DIR);
136
131
  if (!trashResult[0]?.success) {
137
132
  result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
138
133
  }
@@ -184,9 +179,9 @@ class CodexUninstaller {
184
179
  warnings: []
185
180
  };
186
181
  try {
187
- if (await pathExists(this.CODEX_CONFIG_FILE)) {
182
+ if (await pathExists(CODEX_CONFIG_FILE)) {
188
183
  const { readFileSync, writeFileSync } = await import('node:fs');
189
- const content = readFileSync(this.CODEX_CONFIG_FILE, "utf-8");
184
+ const content = readFileSync(CODEX_CONFIG_FILE, "utf-8");
190
185
  const lines = content.split("\n");
191
186
  const newLines = [];
192
187
  let inProviderSection = false;
@@ -210,7 +205,7 @@ class CodexUninstaller {
210
205
  newLines.push(line);
211
206
  }
212
207
  if (configModified) {
213
- writeFileSync(this.CODEX_CONFIG_FILE, newLines.join("\n"));
208
+ writeFileSync(CODEX_CONFIG_FILE, newLines.join("\n"));
214
209
  result.removedConfigs.push(i18n.t("codex:apiConfigRemoved"));
215
210
  }
216
211
  result.success = true;
@@ -263,9 +258,9 @@ class CodexUninstaller {
263
258
  warnings: []
264
259
  };
265
260
  try {
266
- if (await pathExists(this.CODEX_CONFIG_FILE)) {
261
+ if (await pathExists(CODEX_CONFIG_FILE)) {
267
262
  const { readFileSync, writeFileSync } = await import('node:fs');
268
- const content = readFileSync(this.CODEX_CONFIG_FILE, "utf-8");
263
+ const content = readFileSync(CODEX_CONFIG_FILE, "utf-8");
269
264
  const lines = content.split("\n");
270
265
  const newLines = [];
271
266
  let inMcpSection = false;
@@ -285,7 +280,7 @@ class CodexUninstaller {
285
280
  newLines.push(line);
286
281
  }
287
282
  if (configModified) {
288
- writeFileSync(this.CODEX_CONFIG_FILE, newLines.join("\n"));
283
+ writeFileSync(CODEX_CONFIG_FILE, newLines.join("\n"));
289
284
  result.removedConfigs.push(i18n.t("codex:mcpConfigRemoved"));
290
285
  }
291
286
  result.success = true;
@@ -310,8 +305,8 @@ class CodexUninstaller {
310
305
  warnings: []
311
306
  };
312
307
  try {
313
- if (await pathExists(this.CODEX_DIR)) {
314
- const trashResult = await moveToTrash(this.CODEX_DIR);
308
+ if (await pathExists(CODEX_DIR)) {
309
+ const trashResult = await moveToTrash(CODEX_DIR);
315
310
  if (!trashResult[0]?.success) {
316
311
  result.warnings.push(`Failed to move ~/.codex/ to trash: ${trashResult[0]?.error || "Unknown error"}`);
317
312
  }
@@ -1,7 +1,7 @@
1
1
  import { exec } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
3
  import ansis from 'ansis';
4
- import { a5 as ensureI18nInitialized, a6 as i18n } from './simple-config.mjs';
4
+ import { aa as ensureI18nInitialized, ab as i18n } from './simple-config.mjs';
5
5
  import 'node:fs';
6
6
  import 'node:process';
7
7
  import 'inquirer';
@@ -1,6 +1,6 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
- import { a6 as i18n, a5 as ensureI18nInitialized, s as SUPPORTED_LANGS, a7 as addNumbersToChoices, t as LANG_LABELS, al as updateZcfConfig, am as changeLanguage, an as readZcfConfig, o as openSettingsJson, d as importRecommendedPermissions, b as importRecommendedEnv, X as applyAiLanguageDirective, ao as configureOutputStyle, V as getExistingModelConfig, R as updateCustomModel, T as updateDefaultModel, ap as isWindows, x as readMcpConfig, F as fixWindowsMcpConfig, y as writeMcpConfig, aq as selectMcpServices, z as backupMcpConfig, ar as getMcpServices, E as buildMcpServerConfig, B as mergeMcpServers, as as isCcrInstalled, at as installCcr, au as setupCcrConfiguration, W as getExistingApiConfig, _ as promptApiConfigurationAction, av as modifyApiConfigPartially, a8 as validateApiKey, P as configureApi, aw as formatApiKeyDisplay, Y as switchToOfficialLogin } from './simple-config.mjs';
3
+ import { ab as i18n, aa as ensureI18nInitialized, x as SUPPORTED_LANGS, ac as addNumbersToChoices, y as LANG_LABELS, aq as updateZcfConfig, ar as changeLanguage, as as readZcfConfig, o as openSettingsJson, d as importRecommendedPermissions, b as importRecommendedEnv, a1 as applyAiLanguageDirective, at as configureOutputStyle, $ as getExistingModelConfig, X as updateCustomModel, Y as updateDefaultModel, au as isWindows, F as readMcpConfig, K as fixWindowsMcpConfig, G as writeMcpConfig, av as selectMcpServices, H as backupMcpConfig, aw as getMcpServices, J as buildMcpServerConfig, I as mergeMcpServers, ax as isCcrInstalled, ay as installCcr, az as setupCcrConfiguration, a0 as getExistingApiConfig, a3 as promptApiConfigurationAction, aA as modifyApiConfigPartially, ad as validateApiKey, V as configureApi, aB as formatApiKeyDisplay, a2 as switchToOfficialLogin } from './simple-config.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:process';
6
6
  import 'node:child_process';
@@ -288,18 +288,18 @@ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingModelConfig") || "Existing
288
288
  updateDefaultModel(model);
289
289
  console.log(ansis.green(`\u2714 ${i18n.t("configuration:modelConfigured") || "Default model configured"}`));
290
290
  }
291
- async function promptCustomModels() {
291
+ async function promptCustomModels(defaultPrimaryModel, defaultFastModel) {
292
292
  const { primaryModel } = await inquirer.prompt({
293
293
  type: "input",
294
294
  name: "primaryModel",
295
295
  message: `${i18n.t("configuration:enterPrimaryModel")}${i18n.t("common:emptyToSkip")}`,
296
- default: ""
296
+ default: defaultPrimaryModel || ""
297
297
  });
298
298
  const { fastModel } = await inquirer.prompt({
299
299
  type: "input",
300
300
  name: "fastModel",
301
301
  message: `${i18n.t("configuration:enterFastModel")}${i18n.t("common:emptyToSkip")}`,
302
- default: ""
302
+ default: defaultFastModel || ""
303
303
  });
304
304
  return { primaryModel, fastModel };
305
305
  }
@@ -344,7 +344,7 @@ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existi
344
344
  return;
345
345
  }
346
346
  }
347
- const { selectAiOutputLanguage } = await import('./simple-config.mjs').then(function (n) { return n.b5; });
347
+ const { selectAiOutputLanguage } = await import('./simple-config.mjs').then(function (n) { return n.ba; });
348
348
  const aiOutputLang = await selectAiOutputLanguage();
349
349
  applyAiLanguageDirective(aiOutputLang);
350
350
  updateZcfConfig({ aiOutputLang });
@@ -377,7 +377,7 @@ async function changeScriptLanguageFeature(currentLang) {
377
377
  }
378
378
  async function configureCodexDefaultModelFeature() {
379
379
  ensureI18nInitialized();
380
- const { readCodexConfig } = await import('./simple-config.mjs').then(function (n) { return n.b6; });
380
+ const { readCodexConfig } = await import('./simple-config.mjs').then(function (n) { return n.bb; });
381
381
  const existingConfig = readCodexConfig();
382
382
  const currentModel = existingConfig?.model;
383
383
  if (currentModel) {
@@ -482,7 +482,7 @@ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existi
482
482
  return;
483
483
  }
484
484
  }
485
- const { selectAiOutputLanguage } = await import('./simple-config.mjs').then(function (n) { return n.b5; });
485
+ const { selectAiOutputLanguage } = await import('./simple-config.mjs').then(function (n) { return n.ba; });
486
486
  const aiOutputLang = await selectAiOutputLanguage();
487
487
  await updateCodexLanguageDirective(aiOutputLang);
488
488
  updateZcfConfig({ aiOutputLang });
@@ -490,14 +490,14 @@ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existi
490
490
  } else if (option === "systemPrompt") {
491
491
  const zcfConfig = readZcfConfig();
492
492
  const currentLang = zcfConfig?.aiOutputLang || "English";
493
- const { runCodexSystemPromptSelection } = await import('./simple-config.mjs').then(function (n) { return n.b6; });
493
+ const { runCodexSystemPromptSelection } = await import('./simple-config.mjs').then(function (n) { return n.bb; });
494
494
  await runCodexSystemPromptSelection();
495
495
  await ensureLanguageDirectiveInAgents(currentLang);
496
496
  console.log(ansis.green(`\u2714 ${i18n.t("configuration:systemPromptConfigured")}`));
497
497
  }
498
498
  }
499
499
  async function updateCodexModelProvider(modelProvider) {
500
- const { readCodexConfig, writeCodexConfig, backupCodexConfig, getBackupMessage } = await import('./simple-config.mjs').then(function (n) { return n.b6; });
500
+ const { readCodexConfig, writeCodexConfig, backupCodexConfig, getBackupMessage } = await import('./simple-config.mjs').then(function (n) { return n.bb; });
501
501
  const backupPath = backupCodexConfig();
502
502
  if (backupPath) {
503
503
  console.log(ansis.gray(getBackupMessage(backupPath)));
@@ -518,7 +518,7 @@ async function updateCodexModelProvider(modelProvider) {
518
518
  writeCodexConfig(updatedConfig);
519
519
  }
520
520
  async function ensureLanguageDirectiveInAgents(aiOutputLang) {
521
- const { readFile, writeFile, exists } = await import('./simple-config.mjs').then(function (n) { return n.b0; });
521
+ const { readFile, writeFile, exists } = await import('./simple-config.mjs').then(function (n) { return n.b5; });
522
522
  const { homedir } = await import('node:os');
523
523
  const { join } = await import('pathe');
524
524
  const CODEX_AGENTS_FILE = join(homedir(), ".codex", "AGENTS.md");
@@ -536,7 +536,7 @@ async function ensureLanguageDirectiveInAgents(aiOutputLang) {
536
536
  const langLabel = languageLabels[aiOutputLang] || aiOutputLang;
537
537
  const hasLanguageDirective = /\*\*Most Important:\s*Always respond in [^*]+\*\*/i.test(content);
538
538
  if (!hasLanguageDirective) {
539
- const { backupCodexAgents, getBackupMessage } = await import('./simple-config.mjs').then(function (n) { return n.b6; });
539
+ const { backupCodexAgents, getBackupMessage } = await import('./simple-config.mjs').then(function (n) { return n.bb; });
540
540
  const backupPath = backupCodexAgents();
541
541
  if (backupPath) {
542
542
  console.log(ansis.gray(getBackupMessage(backupPath)));
@@ -553,8 +553,8 @@ async function ensureLanguageDirectiveInAgents(aiOutputLang) {
553
553
  }
554
554
  }
555
555
  async function updateCodexLanguageDirective(aiOutputLang) {
556
- const { readFile, writeFile, exists } = await import('./simple-config.mjs').then(function (n) { return n.b0; });
557
- const { backupCodexAgents, getBackupMessage } = await import('./simple-config.mjs').then(function (n) { return n.b6; });
556
+ const { readFile, writeFile, exists } = await import('./simple-config.mjs').then(function (n) { return n.b5; });
557
+ const { backupCodexAgents, getBackupMessage } = await import('./simple-config.mjs').then(function (n) { return n.bb; });
558
558
  const { homedir } = await import('node:os');
559
559
  const { join } = await import('pathe');
560
560
  const CODEX_AGENTS_FILE = join(homedir(), ".codex", "AGENTS.md");
@@ -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.3.0";
19
+ const version = "3.3.2";
20
20
  const homepage = "https://github.com/UfoMiao/zcf";
21
21
 
22
22
  const i18n = i18next.createInstance();
@@ -381,6 +381,11 @@ const SETTINGS_FILE = join(CLAUDE_DIR, "settings.json");
381
381
  const CLAUDE_MD_FILE = join(CLAUDE_DIR, "CLAUDE.md");
382
382
  const ClAUDE_CONFIG_FILE = join(homedir(), ".claude.json");
383
383
  const CLAUDE_VSC_CONFIG_FILE = join(CLAUDE_DIR, "config.json");
384
+ const CODEX_DIR = join(homedir(), ".codex");
385
+ const CODEX_CONFIG_FILE = join(CODEX_DIR, "config.toml");
386
+ const CODEX_AUTH_FILE = join(CODEX_DIR, "auth.json");
387
+ const CODEX_AGENTS_FILE = join(CODEX_DIR, "AGENTS.md");
388
+ const CODEX_PROMPTS_DIR = join(CODEX_DIR, "prompts");
384
389
  const ZCF_CONFIG_DIR = join(homedir(), ".ufomiao", "zcf");
385
390
  const ZCF_CONFIG_FILE = join(ZCF_CONFIG_DIR, "config.toml");
386
391
  const LEGACY_ZCF_CONFIG_FILES = [
@@ -442,6 +447,11 @@ const constants = {
442
447
  CLAUDE_DIR: CLAUDE_DIR,
443
448
  CLAUDE_MD_FILE: CLAUDE_MD_FILE,
444
449
  CLAUDE_VSC_CONFIG_FILE: CLAUDE_VSC_CONFIG_FILE,
450
+ CODEX_AGENTS_FILE: CODEX_AGENTS_FILE,
451
+ CODEX_AUTH_FILE: CODEX_AUTH_FILE,
452
+ CODEX_CONFIG_FILE: CODEX_CONFIG_FILE,
453
+ CODEX_DIR: CODEX_DIR,
454
+ CODEX_PROMPTS_DIR: CODEX_PROMPTS_DIR,
445
455
  CODE_TOOL_ALIASES: CODE_TOOL_ALIASES,
446
456
  CODE_TOOL_BANNERS: CODE_TOOL_BANNERS,
447
457
  CODE_TOOL_TYPES: CODE_TOOL_TYPES,
@@ -1350,11 +1360,6 @@ function switchToOfficialLogin$1() {
1350
1360
  delete vscConfig.primaryApiKey;
1351
1361
  writeJsonConfig(CLAUDE_VSC_CONFIG_FILE, vscConfig);
1352
1362
  }
1353
- const mcpConfig = readMcpConfig();
1354
- if (mcpConfig) {
1355
- delete mcpConfig.hasCompletedOnboarding;
1356
- writeMcpConfig(mcpConfig);
1357
- }
1358
1363
  console.log(i18n.t("api:officialLoginConfigured"));
1359
1364
  return true;
1360
1365
  } catch (error) {
@@ -2915,11 +2920,6 @@ async function configureCodexMcp(options) {
2915
2920
  console.log(ansis.green(i18n.t("codex:mcpConfigured")));
2916
2921
  }
2917
2922
 
2918
- const CODEX_DIR = join(homedir(), ".codex");
2919
- const CODEX_CONFIG_FILE = join(CODEX_DIR, "config.toml");
2920
- const CODEX_AUTH_FILE = join(CODEX_DIR, "auth.json");
2921
- const CODEX_AGENTS_FILE = join(CODEX_DIR, "AGENTS.md");
2922
- const CODEX_PROMPTS_DIR = join(CODEX_DIR, "prompts");
2923
2923
  function getRootDir$1() {
2924
2924
  const currentFilePath = fileURLToPath(import.meta.url);
2925
2925
  let dir = dirname(currentFilePath);
@@ -6045,4 +6045,4 @@ async function openSettingsJson() {
6045
6045
  }
6046
6046
  }
6047
6047
 
6048
- export { isClaudeCodeInstalled as $, API_DEFAULT_URL as A, mergeMcpServers as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, buildMcpServerConfig as E, fixWindowsMcpConfig as F, addCompletedOnboarding as G, ensureApiKeyApproved as H, removeApiKeyFromRejected as I, manageApiKeyApproval as J, setPrimaryApiKey as K, LEGACY_ZCF_CONFIG_FILES as L, ensureClaudeDir as M, backupExistingConfig as N, copyConfigFiles as O, configureApi as P, mergeConfigs as Q, updateCustomModel as R, SETTINGS_FILE as S, updateDefaultModel as T, mergeSettingsFile as U, getExistingModelConfig as V, getExistingApiConfig as W, applyAiLanguageDirective as X, switchToOfficialLogin$1 as Y, ZCF_CONFIG_DIR as Z, promptApiConfigurationAction as _, commandExists as a, index as a$, installClaudeCode as a0, isLocalClaudeCodeInstalled as a1, getInstallationStatus as a2, removeLocalClaudeCode as a3, setInstallMethod as a4, ensureI18nInitialized as a5, i18n as a6, addNumbersToChoices as a7, validateApiKey as a8, ensureDir as a9, handleGeneralError as aA, COMETIX_COMMAND_NAME as aB, COMETIX_COMMANDS as aC, installCometixLine as aD, checkAndUpdateTools as aE, runCodexUpdate as aF, resolveCodeType as aG, writeJsonConfig as aH, displayBanner as aI, version as aJ, resolveAiOutputLanguage as aK, updatePromptOnly as aL, selectAndInstallWorkflows as aM, checkClaudeCodeVersionAndPrompt as aN, displayBannerWithInfo as aO, runCodexUninstall as aP, configureCodexMcp as aQ, configureCodexApi as aR, runCodexWorkflowImportWithLanguageSelection as aS, runCodexFullInit as aT, switchCodexProvider as aU, listCodexProviders as aV, switchToOfficialLogin as aW, switchToProvider as aX, readZcfConfigAsync as aY, initI18n as aZ, selectScriptLanguage as a_, readDefaultTomlConfig as aa, createDefaultTomlConfig as ab, exists as ac, readJsonConfig as ad, writeTomlConfig as ae, copyFile as af, detectConfigManagementMode as ag, readCodexConfig as ah, backupCodexComplete as ai, writeCodexConfig as aj, writeAuthFile as ak, updateZcfConfig as al, changeLanguage as am, readZcfConfig as an, configureOutputStyle as ao, isWindows as ap, selectMcpServices as aq, getMcpServices as ar, isCcrInstalled as as, installCcr as at, setupCcrConfiguration as au, modifyApiConfigPartially as av, formatApiKeyDisplay as aw, readCcrConfig as ax, configureCcrFeature as ay, handleExitPromptError as az, importRecommendedEnv as b, fsOperations as b0, jsonConfig as b1, claudeConfig as b2, config$1 as b3, config as b4, prompts as b5, codex as b6, cleanupPermissions as c, importRecommendedPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, CLAUDE_VSC_CONFIG_FILE as h, init as i, ZCF_CONFIG_FILE as j, CODE_TOOL_TYPES as k, CODE_TOOL_BANNERS as l, mergeAndCleanPermissions as m, CODE_TOOL_ALIASES as n, openSettingsJson as o, isCodeToolType as p, API_ENV_KEY as q, resolveCodeToolType as r, SUPPORTED_LANGS as s, LANG_LABELS as t, AI_OUTPUT_LANGUAGES as u, getAiOutputLanguageLabel as v, getMcpConfigPath as w, readMcpConfig as x, writeMcpConfig as y, backupMcpConfig as z };
6048
+ export { getExistingModelConfig as $, API_DEFAULT_URL as A, getAiOutputLanguageLabel as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, getMcpConfigPath as E, readMcpConfig as F, writeMcpConfig as G, backupMcpConfig as H, mergeMcpServers as I, buildMcpServerConfig as J, fixWindowsMcpConfig as K, LEGACY_ZCF_CONFIG_FILES as L, addCompletedOnboarding as M, ensureApiKeyApproved as N, removeApiKeyFromRejected as O, manageApiKeyApproval as P, setPrimaryApiKey as Q, ensureClaudeDir as R, SETTINGS_FILE as S, backupExistingConfig as T, copyConfigFiles as U, configureApi as V, mergeConfigs as W, updateCustomModel as X, updateDefaultModel as Y, ZCF_CONFIG_DIR as Z, mergeSettingsFile as _, commandExists as a, switchToOfficialLogin as a$, getExistingApiConfig as a0, applyAiLanguageDirective as a1, switchToOfficialLogin$1 as a2, promptApiConfigurationAction as a3, isClaudeCodeInstalled as a4, installClaudeCode as a5, isLocalClaudeCodeInstalled as a6, getInstallationStatus as a7, removeLocalClaudeCode as a8, setInstallMethod as a9, modifyApiConfigPartially as aA, formatApiKeyDisplay as aB, readCcrConfig as aC, configureCcrFeature as aD, handleExitPromptError as aE, handleGeneralError as aF, COMETIX_COMMAND_NAME as aG, COMETIX_COMMANDS as aH, installCometixLine as aI, checkAndUpdateTools as aJ, runCodexUpdate as aK, resolveCodeType as aL, writeJsonConfig as aM, displayBanner as aN, version as aO, resolveAiOutputLanguage as aP, updatePromptOnly as aQ, selectAndInstallWorkflows as aR, checkClaudeCodeVersionAndPrompt as aS, displayBannerWithInfo as aT, runCodexUninstall as aU, configureCodexMcp as aV, configureCodexApi as aW, runCodexWorkflowImportWithLanguageSelection as aX, runCodexFullInit as aY, switchCodexProvider as aZ, listCodexProviders as a_, ensureI18nInitialized as aa, i18n as ab, addNumbersToChoices as ac, validateApiKey as ad, ensureDir as ae, readDefaultTomlConfig as af, createDefaultTomlConfig as ag, exists as ah, readJsonConfig as ai, writeTomlConfig as aj, copyFile as ak, detectConfigManagementMode as al, readCodexConfig as am, backupCodexComplete as an, writeCodexConfig as ao, writeAuthFile as ap, updateZcfConfig as aq, changeLanguage as ar, readZcfConfig as as, configureOutputStyle as at, isWindows as au, selectMcpServices as av, getMcpServices as aw, isCcrInstalled as ax, installCcr as ay, setupCcrConfiguration as az, importRecommendedEnv as b, switchToProvider as b0, readZcfConfigAsync as b1, initI18n as b2, selectScriptLanguage as b3, index as b4, fsOperations as b5, jsonConfig as b6, claudeConfig as b7, config$1 as b8, config as b9, prompts as ba, codex as bb, cleanupPermissions as c, importRecommendedPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, CLAUDE_VSC_CONFIG_FILE as h, init as i, CODEX_DIR as j, CODEX_CONFIG_FILE as k, CODEX_AUTH_FILE as l, mergeAndCleanPermissions as m, CODEX_AGENTS_FILE as n, openSettingsJson as o, CODEX_PROMPTS_DIR as p, ZCF_CONFIG_FILE as q, CODE_TOOL_TYPES as r, CODE_TOOL_BANNERS as s, CODE_TOOL_ALIASES as t, isCodeToolType as u, API_ENV_KEY as v, resolveCodeToolType as w, SUPPORTED_LANGS as x, LANG_LABELS as y, AI_OUTPUT_LANGUAGES as z };
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from 'cac';
3
3
  import ansis from 'ansis';
4
- import { a5 as ensureI18nInitialized, a6 as i18n, ax as readCcrConfig, as as isCcrInstalled, at as installCcr, ay as configureCcrFeature, az as handleExitPromptError, aA as handleGeneralError, aB as COMETIX_COMMAND_NAME, aC as COMETIX_COMMANDS, aD as installCometixLine, a7 as addNumbersToChoices, aE as checkAndUpdateTools, aF as runCodexUpdate, aG as resolveCodeType$1, ad as readJsonConfig, aH as writeJsonConfig, j as ZCF_CONFIG_FILE, aI as displayBanner, an as readZcfConfig, al as updateZcfConfig, aJ as version, aK as resolveAiOutputLanguage, aL as updatePromptOnly, aM as selectAndInstallWorkflows, aN as checkClaudeCodeVersionAndPrompt, r as resolveCodeToolType$1, D as DEFAULT_CODE_TOOL_TYPE, p as isCodeToolType, aO as displayBannerWithInfo, l as CODE_TOOL_BANNERS, aP as runCodexUninstall, aQ as configureCodexMcp, aR as configureCodexApi, aS as runCodexWorkflowImportWithLanguageSelection, aT as runCodexFullInit, i as init, aU as switchCodexProvider, aV as listCodexProviders, ah as readCodexConfig, aW as switchToOfficialLogin, aX as switchToProvider, aY as readZcfConfigAsync, aZ as initI18n, a_ as selectScriptLanguage, am as changeLanguage } from './chunks/simple-config.mjs';
4
+ import { aa as ensureI18nInitialized, ab as i18n, aC as readCcrConfig, ax as isCcrInstalled, ay as installCcr, aD as configureCcrFeature, aE as handleExitPromptError, aF as handleGeneralError, aG as COMETIX_COMMAND_NAME, aH as COMETIX_COMMANDS, aI as installCometixLine, ac as addNumbersToChoices, aJ as checkAndUpdateTools, aK as runCodexUpdate, aL as resolveCodeType$1, ai as readJsonConfig, aM as writeJsonConfig, q as ZCF_CONFIG_FILE, aN as displayBanner, as as readZcfConfig, aq as updateZcfConfig, aO as version, aP as resolveAiOutputLanguage, aQ as updatePromptOnly, aR as selectAndInstallWorkflows, aS as checkClaudeCodeVersionAndPrompt, w as resolveCodeToolType$1, D as DEFAULT_CODE_TOOL_TYPE, u as isCodeToolType, aT as displayBannerWithInfo, s as CODE_TOOL_BANNERS, aU as runCodexUninstall, aV as configureCodexMcp, aW as configureCodexApi, aX as runCodexWorkflowImportWithLanguageSelection, aY as runCodexFullInit, i as init, aZ as switchCodexProvider, a_ as listCodexProviders, am as readCodexConfig, a$ as switchToOfficialLogin, b0 as switchToProvider, b1 as readZcfConfigAsync, b2 as initI18n, b3 as selectScriptLanguage, ar as changeLanguage } from './chunks/simple-config.mjs';
5
5
  import { existsSync } from 'node:fs';
6
6
  import { homedir } from 'node:os';
7
7
  import inquirer from 'inquirer';
@@ -1177,7 +1177,7 @@ async function update(options = {}) {
1177
1177
  }
1178
1178
  return;
1179
1179
  }
1180
- const { resolveTemplateLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.b5; });
1180
+ const { resolveTemplateLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.ba; });
1181
1181
  const configLang = await resolveTemplateLanguage(
1182
1182
  options.configLang,
1183
1183
  // Command line option
@@ -1733,7 +1733,7 @@ async function handleClaudeCodeInteractiveSwitch() {
1733
1733
  });
1734
1734
  const isCcrMode = currentProfileId2 === "ccr-proxy";
1735
1735
  choices2.push({
1736
- name: isCcrMode ? `${ansis.green("\u25CF ")}CCR Proxy ${ansis.yellow("(current)")}` : ` CCR Proxy`,
1736
+ name: isCcrMode ? `${ansis.green("\u25CF ")}${i18n.t("multi-config:ccrProxyOption")} ${ansis.yellow(`(${i18n.t("common:current")})`)}` : ` ${i18n.t("multi-config:ccrProxyOption")}`,
1737
1737
  value: "ccr"
1738
1738
  });
1739
1739
  Object.values(profiles).filter((profile) => profile.id !== "ccr-proxy").forEach((profile) => {
@@ -70,8 +70,15 @@
70
70
  "selectAction": "Select action",
71
71
  "addProvider": "Add provider",
72
72
  "editProvider": "Edit provider",
73
+ "copyProvider": "Copy provider",
73
74
  "deleteProvider": "Delete provider",
74
75
  "selectProviderToEdit": "Select provider to edit",
76
+ "selectProviderToCopy": "Select provider to copy",
77
+ "copyingProvider": "Copying provider: {{name}}",
78
+ "providerCopied": "✔ Successfully copied provider: {{name}}",
79
+ "providerCopyFailed": "❌ Failed to copy provider: {{error}}",
80
+ "providerModelPrompt": "Model name (e.g. gpt-5-codex)",
81
+ "providerModelRequired": "Model name is required",
75
82
  "selectProvidersToDelete": "Select providers to delete (multiple)",
76
83
  "selectAtLeastOne": "Please select at least one provider",
77
84
  "cannotDeleteAll": "Cannot delete all providers, at least one must remain",
@@ -19,6 +19,7 @@
19
19
  "currentDefaultProfile": "Current default profile: {{profile}}",
20
20
  "addProfile": "Add Profile",
21
21
  "editProfile": "Edit Profile",
22
+ "copyProfile": "Copy Profile",
22
23
  "deleteProfile": "Delete Profile",
23
24
  "selectAction": "Select action",
24
25
  "addingNewProfile": "Adding New Profile",
@@ -35,6 +36,7 @@
35
36
  "authType.api_key": "API Key",
36
37
  "authType.auth_token": "Auth Token",
37
38
  "authType.ccr_proxy": "CCR Proxy",
39
+ "ccrProxyOption": "Use CCR Proxy",
38
40
  "profileAdded": "✔ Successfully added profile: {{name}}",
39
41
  "profileAddFailed": "❌ Failed to add profile: {{error}}",
40
42
  "profileDuplicatePrompt": "Profile '{{name}}' already exists in {{source}}, overwrite it?",
@@ -47,6 +49,10 @@
47
49
  "profileUpdated": "✔ Successfully updated profile: {{name}}",
48
50
  "profileUpdateFailed": "❌ Failed to update profile: {{error}}",
49
51
  "selectProfileToEdit": "Select profile to edit",
52
+ "selectProfileToCopy": "Select profile to copy",
53
+ "copyingProfile": "Copying profile: {{name}}",
54
+ "profileCopied": "✔ Successfully copied profile: {{name}}",
55
+ "profileCopyFailed": "❌ Failed to copy profile: {{error}}",
50
56
  "selectProfilesToDelete": "Select profiles to delete (multiple)",
51
57
  "selectAtLeastOne": "Please select at least one profile",
52
58
  "cannotDeleteAll": "Cannot delete all profiles, at least one must remain",
@@ -70,8 +70,15 @@
70
70
  "selectAction": "请选择操作",
71
71
  "addProvider": "添加供应商",
72
72
  "editProvider": "编辑供应商",
73
+ "copyProvider": "复制供应商",
73
74
  "deleteProvider": "删除供应商",
74
75
  "selectProviderToEdit": "选择要编辑的供应商",
76
+ "selectProviderToCopy": "选择要复制的供应商",
77
+ "copyingProvider": "正在复制供应商:{{name}}",
78
+ "providerCopied": "✔ 已成功复制供应商:{{name}}",
79
+ "providerCopyFailed": "❌ 复制供应商失败:{{error}}",
80
+ "providerModelPrompt": "模型名称(如 gpt-5-codex)",
81
+ "providerModelRequired": "必须填写模型名称",
75
82
  "selectProvidersToDelete": "选择要删除的供应商(多选)",
76
83
  "selectAtLeastOne": "请至少选择一个供应商",
77
84
  "cannotDeleteAll": "不能删除所有供应商,至少需要保留一个",
@@ -19,6 +19,7 @@
19
19
  "currentDefaultProfile": "当前默认配置:{{profile}}",
20
20
  "addProfile": "添加配置",
21
21
  "editProfile": "编辑配置",
22
+ "copyProfile": "复制配置",
22
23
  "deleteProfile": "删除配置",
23
24
  "selectAction": "请选择操作",
24
25
  "addingNewProfile": "添加新配置",
@@ -35,6 +36,7 @@
35
36
  "authType.api_key": "API Key",
36
37
  "authType.auth_token": "Auth Token",
37
38
  "authType.ccr_proxy": "CCR 代理",
39
+ "ccrProxyOption": "使用 CCR 代理",
38
40
  "profileAdded": "✔ 已成功添加配置:{{name}}",
39
41
  "profileAddFailed": "❌ 添加配置失败:{{error}}",
40
42
  "profileDuplicatePrompt": "配置「{{name}}」已经存在于{{source}},是否覆盖?",
@@ -47,6 +49,10 @@
47
49
  "profileUpdated": "✔ 已成功更新配置:{{name}}",
48
50
  "profileUpdateFailed": "❌ 更新配置失败:{{error}}",
49
51
  "selectProfileToEdit": "选择要编辑的配置",
52
+ "selectProfileToCopy": "选择要复制的配置",
53
+ "copyingProfile": "正在复制配置:{{name}}",
54
+ "profileCopied": "✔ 已成功复制配置:{{name}}",
55
+ "profileCopyFailed": "❌ 复制配置失败:{{error}}",
50
56
  "selectProfilesToDelete": "选择要删除的配置(多选)",
51
57
  "selectAtLeastOne": "请至少选择一个配置",
52
58
  "cannotDeleteAll": "不能删除所有配置,至少需要保留一个",
package/dist/index.d.mts CHANGED
@@ -3,6 +3,11 @@ declare const SETTINGS_FILE: string;
3
3
  declare const CLAUDE_MD_FILE: string;
4
4
  declare const ClAUDE_CONFIG_FILE: string;
5
5
  declare const CLAUDE_VSC_CONFIG_FILE: string;
6
+ declare const CODEX_DIR: string;
7
+ declare const CODEX_CONFIG_FILE: string;
8
+ declare const CODEX_AUTH_FILE: string;
9
+ declare const CODEX_AGENTS_FILE: string;
10
+ declare const CODEX_PROMPTS_DIR: string;
6
11
  declare const ZCF_CONFIG_DIR: string;
7
12
  declare const ZCF_CONFIG_FILE: string;
8
13
  declare const LEGACY_ZCF_CONFIG_FILES: string[];
@@ -168,7 +173,6 @@ declare function applyAiLanguageDirective(aiOutputLang: AiOutputLanguage | strin
168
173
  * Switch to official login mode - remove all third-party API configurations
169
174
  * Removes: ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY from settings.json
170
175
  * Removes: primaryApiKey from ~/.claude/config.json
171
- * Removes: hasCompletedOnboarding from ~/.claude.json
172
176
  */
173
177
  declare function switchToOfficialLogin(): boolean;
174
178
  /**
@@ -229,5 +233,5 @@ declare function importRecommendedEnv(): Promise<void>;
229
233
  declare function importRecommendedPermissions(): Promise<void>;
230
234
  declare function openSettingsJson(): Promise<void>;
231
235
 
232
- export { AI_OUTPUT_LANGUAGES, API_DEFAULT_URL, API_ENV_KEY, CLAUDE_DIR, CLAUDE_MD_FILE, CLAUDE_VSC_CONFIG_FILE, CODE_TOOL_ALIASES, CODE_TOOL_BANNERS, CODE_TOOL_TYPES, ClAUDE_CONFIG_FILE, DEFAULT_CODE_TOOL_TYPE, LANG_LABELS, LEGACY_ZCF_CONFIG_FILES, SETTINGS_FILE, SUPPORTED_LANGS, ZCF_CONFIG_DIR, ZCF_CONFIG_FILE, addCompletedOnboarding, applyAiLanguageDirective, backupExistingConfig, backupMcpConfig, buildMcpServerConfig, cleanupPermissions, commandExists, configureApi, copyConfigFiles, ensureApiKeyApproved, ensureClaudeDir, fixWindowsMcpConfig, getAiOutputLanguageLabel, getExistingApiConfig, getExistingModelConfig, getInstallationStatus, getMcpConfigPath, getPlatform, importRecommendedEnv, importRecommendedPermissions, init, installClaudeCode, isClaudeCodeInstalled, isCodeToolType, isLocalClaudeCodeInstalled, manageApiKeyApproval, mergeAndCleanPermissions, mergeConfigs, mergeMcpServers, mergeSettingsFile, openSettingsJson, promptApiConfigurationAction, readMcpConfig, removeApiKeyFromRejected, removeLocalClaudeCode, resolveCodeToolType, setInstallMethod, setPrimaryApiKey, switchToOfficialLogin, updateCustomModel, updateDefaultModel, writeMcpConfig };
236
+ export { AI_OUTPUT_LANGUAGES, API_DEFAULT_URL, API_ENV_KEY, CLAUDE_DIR, CLAUDE_MD_FILE, CLAUDE_VSC_CONFIG_FILE, CODEX_AGENTS_FILE, CODEX_AUTH_FILE, CODEX_CONFIG_FILE, CODEX_DIR, CODEX_PROMPTS_DIR, CODE_TOOL_ALIASES, CODE_TOOL_BANNERS, CODE_TOOL_TYPES, ClAUDE_CONFIG_FILE, DEFAULT_CODE_TOOL_TYPE, LANG_LABELS, LEGACY_ZCF_CONFIG_FILES, SETTINGS_FILE, SUPPORTED_LANGS, ZCF_CONFIG_DIR, ZCF_CONFIG_FILE, addCompletedOnboarding, applyAiLanguageDirective, backupExistingConfig, backupMcpConfig, buildMcpServerConfig, cleanupPermissions, commandExists, configureApi, copyConfigFiles, ensureApiKeyApproved, ensureClaudeDir, fixWindowsMcpConfig, getAiOutputLanguageLabel, getExistingApiConfig, getExistingModelConfig, getInstallationStatus, getMcpConfigPath, getPlatform, importRecommendedEnv, importRecommendedPermissions, init, installClaudeCode, isClaudeCodeInstalled, isCodeToolType, isLocalClaudeCodeInstalled, manageApiKeyApproval, mergeAndCleanPermissions, mergeConfigs, mergeMcpServers, mergeSettingsFile, openSettingsJson, promptApiConfigurationAction, readMcpConfig, removeApiKeyFromRejected, removeLocalClaudeCode, resolveCodeToolType, setInstallMethod, setPrimaryApiKey, switchToOfficialLogin, updateCustomModel, updateDefaultModel, writeMcpConfig };
233
237
  export type { AiOutputLanguage, ApiConfig, ClaudeConfiguration, CodeToolType, InstallationStatus, McpServerConfig, McpService, SupportedLang };
package/dist/index.d.ts CHANGED
@@ -3,6 +3,11 @@ declare const SETTINGS_FILE: string;
3
3
  declare const CLAUDE_MD_FILE: string;
4
4
  declare const ClAUDE_CONFIG_FILE: string;
5
5
  declare const CLAUDE_VSC_CONFIG_FILE: string;
6
+ declare const CODEX_DIR: string;
7
+ declare const CODEX_CONFIG_FILE: string;
8
+ declare const CODEX_AUTH_FILE: string;
9
+ declare const CODEX_AGENTS_FILE: string;
10
+ declare const CODEX_PROMPTS_DIR: string;
6
11
  declare const ZCF_CONFIG_DIR: string;
7
12
  declare const ZCF_CONFIG_FILE: string;
8
13
  declare const LEGACY_ZCF_CONFIG_FILES: string[];
@@ -168,7 +173,6 @@ declare function applyAiLanguageDirective(aiOutputLang: AiOutputLanguage | strin
168
173
  * Switch to official login mode - remove all third-party API configurations
169
174
  * Removes: ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY from settings.json
170
175
  * Removes: primaryApiKey from ~/.claude/config.json
171
- * Removes: hasCompletedOnboarding from ~/.claude.json
172
176
  */
173
177
  declare function switchToOfficialLogin(): boolean;
174
178
  /**
@@ -229,5 +233,5 @@ declare function importRecommendedEnv(): Promise<void>;
229
233
  declare function importRecommendedPermissions(): Promise<void>;
230
234
  declare function openSettingsJson(): Promise<void>;
231
235
 
232
- export { AI_OUTPUT_LANGUAGES, API_DEFAULT_URL, API_ENV_KEY, CLAUDE_DIR, CLAUDE_MD_FILE, CLAUDE_VSC_CONFIG_FILE, CODE_TOOL_ALIASES, CODE_TOOL_BANNERS, CODE_TOOL_TYPES, ClAUDE_CONFIG_FILE, DEFAULT_CODE_TOOL_TYPE, LANG_LABELS, LEGACY_ZCF_CONFIG_FILES, SETTINGS_FILE, SUPPORTED_LANGS, ZCF_CONFIG_DIR, ZCF_CONFIG_FILE, addCompletedOnboarding, applyAiLanguageDirective, backupExistingConfig, backupMcpConfig, buildMcpServerConfig, cleanupPermissions, commandExists, configureApi, copyConfigFiles, ensureApiKeyApproved, ensureClaudeDir, fixWindowsMcpConfig, getAiOutputLanguageLabel, getExistingApiConfig, getExistingModelConfig, getInstallationStatus, getMcpConfigPath, getPlatform, importRecommendedEnv, importRecommendedPermissions, init, installClaudeCode, isClaudeCodeInstalled, isCodeToolType, isLocalClaudeCodeInstalled, manageApiKeyApproval, mergeAndCleanPermissions, mergeConfigs, mergeMcpServers, mergeSettingsFile, openSettingsJson, promptApiConfigurationAction, readMcpConfig, removeApiKeyFromRejected, removeLocalClaudeCode, resolveCodeToolType, setInstallMethod, setPrimaryApiKey, switchToOfficialLogin, updateCustomModel, updateDefaultModel, writeMcpConfig };
236
+ export { AI_OUTPUT_LANGUAGES, API_DEFAULT_URL, API_ENV_KEY, CLAUDE_DIR, CLAUDE_MD_FILE, CLAUDE_VSC_CONFIG_FILE, CODEX_AGENTS_FILE, CODEX_AUTH_FILE, CODEX_CONFIG_FILE, CODEX_DIR, CODEX_PROMPTS_DIR, CODE_TOOL_ALIASES, CODE_TOOL_BANNERS, CODE_TOOL_TYPES, ClAUDE_CONFIG_FILE, DEFAULT_CODE_TOOL_TYPE, LANG_LABELS, LEGACY_ZCF_CONFIG_FILES, SETTINGS_FILE, SUPPORTED_LANGS, ZCF_CONFIG_DIR, ZCF_CONFIG_FILE, addCompletedOnboarding, applyAiLanguageDirective, backupExistingConfig, backupMcpConfig, buildMcpServerConfig, cleanupPermissions, commandExists, configureApi, copyConfigFiles, ensureApiKeyApproved, ensureClaudeDir, fixWindowsMcpConfig, getAiOutputLanguageLabel, getExistingApiConfig, getExistingModelConfig, getInstallationStatus, getMcpConfigPath, getPlatform, importRecommendedEnv, importRecommendedPermissions, init, installClaudeCode, isClaudeCodeInstalled, isCodeToolType, isLocalClaudeCodeInstalled, manageApiKeyApproval, mergeAndCleanPermissions, mergeConfigs, mergeMcpServers, mergeSettingsFile, openSettingsJson, promptApiConfigurationAction, readMcpConfig, removeApiKeyFromRejected, removeLocalClaudeCode, resolveCodeToolType, setInstallMethod, setPrimaryApiKey, switchToOfficialLogin, updateCustomModel, updateDefaultModel, writeMcpConfig };
233
237
  export type { AiOutputLanguage, ApiConfig, ClaudeConfiguration, CodeToolType, InstallationStatus, McpServerConfig, McpService, SupportedLang };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { u as AI_OUTPUT_LANGUAGES, A as API_DEFAULT_URL, q as API_ENV_KEY, C as CLAUDE_DIR, e as CLAUDE_MD_FILE, h as CLAUDE_VSC_CONFIG_FILE, n as CODE_TOOL_ALIASES, l as CODE_TOOL_BANNERS, k as CODE_TOOL_TYPES, f as ClAUDE_CONFIG_FILE, D as DEFAULT_CODE_TOOL_TYPE, t as LANG_LABELS, L as LEGACY_ZCF_CONFIG_FILES, S as SETTINGS_FILE, s as SUPPORTED_LANGS, Z as ZCF_CONFIG_DIR, j as ZCF_CONFIG_FILE, G as addCompletedOnboarding, X as applyAiLanguageDirective, N as backupExistingConfig, z as backupMcpConfig, E as buildMcpServerConfig, c as cleanupPermissions, a as commandExists, P as configureApi, O as copyConfigFiles, H as ensureApiKeyApproved, M as ensureClaudeDir, F as fixWindowsMcpConfig, v as getAiOutputLanguageLabel, W as getExistingApiConfig, V as getExistingModelConfig, a2 as getInstallationStatus, w as getMcpConfigPath, g as getPlatform, b as importRecommendedEnv, d as importRecommendedPermissions, i as init, a0 as installClaudeCode, $ as isClaudeCodeInstalled, p as isCodeToolType, a1 as isLocalClaudeCodeInstalled, J as manageApiKeyApproval, m as mergeAndCleanPermissions, Q as mergeConfigs, B as mergeMcpServers, U as mergeSettingsFile, o as openSettingsJson, _ as promptApiConfigurationAction, x as readMcpConfig, I as removeApiKeyFromRejected, a3 as removeLocalClaudeCode, r as resolveCodeToolType, a4 as setInstallMethod, K as setPrimaryApiKey, Y as switchToOfficialLogin, R as updateCustomModel, T as updateDefaultModel, y as writeMcpConfig } from './chunks/simple-config.mjs';
1
+ export { z as AI_OUTPUT_LANGUAGES, A as API_DEFAULT_URL, v as API_ENV_KEY, C as CLAUDE_DIR, e as CLAUDE_MD_FILE, h as CLAUDE_VSC_CONFIG_FILE, n as CODEX_AGENTS_FILE, l as CODEX_AUTH_FILE, k as CODEX_CONFIG_FILE, j as CODEX_DIR, p as CODEX_PROMPTS_DIR, t as CODE_TOOL_ALIASES, s as CODE_TOOL_BANNERS, r as CODE_TOOL_TYPES, f as ClAUDE_CONFIG_FILE, D as DEFAULT_CODE_TOOL_TYPE, y as LANG_LABELS, L as LEGACY_ZCF_CONFIG_FILES, S as SETTINGS_FILE, x as SUPPORTED_LANGS, Z as ZCF_CONFIG_DIR, q as ZCF_CONFIG_FILE, M as addCompletedOnboarding, a1 as applyAiLanguageDirective, T as backupExistingConfig, H as backupMcpConfig, J as buildMcpServerConfig, c as cleanupPermissions, a as commandExists, V as configureApi, U as copyConfigFiles, N as ensureApiKeyApproved, R as ensureClaudeDir, K as fixWindowsMcpConfig, B as getAiOutputLanguageLabel, a0 as getExistingApiConfig, $ as getExistingModelConfig, a7 as getInstallationStatus, E as getMcpConfigPath, g as getPlatform, b as importRecommendedEnv, d as importRecommendedPermissions, i as init, a5 as installClaudeCode, a4 as isClaudeCodeInstalled, u as isCodeToolType, a6 as isLocalClaudeCodeInstalled, P as manageApiKeyApproval, m as mergeAndCleanPermissions, W as mergeConfigs, I as mergeMcpServers, _ as mergeSettingsFile, o as openSettingsJson, a3 as promptApiConfigurationAction, F as readMcpConfig, O as removeApiKeyFromRejected, a8 as removeLocalClaudeCode, w as resolveCodeToolType, a9 as setInstallMethod, Q as setPrimaryApiKey, a2 as switchToOfficialLogin, X as updateCustomModel, Y as updateDefaultModel, G as writeMcpConfig } from './chunks/simple-config.mjs';
2
2
  import 'node:fs';
3
3
  import 'node:process';
4
4
  import 'ansis';
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "zcf",
3
3
  "type": "module",
4
- "version": "3.3.0",
5
- "description": "Zero-Config Code Flow - One-click configuration tool for Claude Code",
4
+ "version": "3.3.2",
5
+ "description": "Zero-Config Code Flow - One-click configuration tool for Code Cli",
6
6
  "author": {
7
7
  "name": "Miao Da",
8
8
  "email": "ufo025174@gmail.com",
@@ -18,12 +18,15 @@
18
18
  "keywords": [
19
19
  "claude",
20
20
  "claude-code",
21
+ "codex",
21
22
  "config",
22
23
  "cli",
23
24
  "setup",
24
25
  "zero-config",
25
26
  "zcf",
26
27
  "anthropic",
28
+ "openai",
29
+ "ChatGPT",
27
30
  "ai",
28
31
  "automation",
29
32
  "mcp"
@@ -99,6 +102,9 @@
99
102
  "update:deps": "pnpx taze major -r -w",
100
103
  "release": "pnpm build && changeset publish",
101
104
  "commitlint": "commitlint",
102
- "commitlint:check": "commitlint --from HEAD~1 --to HEAD --verbose"
105
+ "commitlint:check": "commitlint --from HEAD~1 --to HEAD --verbose",
106
+ "docs:dev": "pnpm -F @zcf/docs dev",
107
+ "docs:build": "pnpm -F @zcf/docs build",
108
+ "docs:preview": "pnpm -F @zcf/docs preview"
103
109
  }
104
110
  }
@@ -1,5 +1,6 @@
1
1
  # Templates Module
2
2
 
3
+ **Last Updated**: Mon Oct 27 19:39:26 CST 2025
3
4
  [Root](../CLAUDE.md) > **templates**
4
5
 
5
6
  ## Module Responsibilities
@@ -1,5 +1,6 @@
1
1
  # Templates Module
2
2
 
3
+ **Last Updated**: Mon Oct 27 19:39:26 CST 2025
3
4
  [Root](../CLAUDE.md) > **templates**
4
5
 
5
6
  ## Module Responsibilities