zcf 3.2.2 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +131 -24
  2. package/dist/chunks/api-providers.mjs +76 -0
  3. package/dist/chunks/claude-code-config-manager.mjs +21 -7
  4. package/dist/chunks/claude-code-incremental-manager.mjs +59 -17
  5. package/dist/chunks/codex-config-switch.mjs +72 -13
  6. package/dist/chunks/codex-provider-manager.mjs +18 -8
  7. package/dist/chunks/codex-uninstaller.mjs +1 -1
  8. package/dist/chunks/commands.mjs +1 -1
  9. package/dist/chunks/features.mjs +637 -0
  10. package/dist/chunks/simple-config.mjs +192 -40
  11. package/dist/cli.mjs +28 -615
  12. package/dist/i18n/locales/en/api.json +6 -1
  13. package/dist/i18n/locales/en/common.json +0 -1
  14. package/dist/i18n/locales/en/errors.json +2 -1
  15. package/dist/i18n/locales/en/multi-config.json +2 -1
  16. package/dist/i18n/locales/zh-CN/api.json +6 -1
  17. package/dist/i18n/locales/zh-CN/common.json +0 -1
  18. package/dist/i18n/locales/zh-CN/errors.json +2 -1
  19. package/dist/i18n/locales/zh-CN/multi-config.json +2 -1
  20. package/dist/index.d.mts +8 -1
  21. package/dist/index.d.ts +8 -1
  22. package/dist/index.mjs +1 -1
  23. package/package.json +1 -1
  24. package/templates/CLAUDE.md +190 -0
  25. package/templates/claude-code/en/output-styles/engineer-professional.md +2 -1
  26. package/templates/claude-code/en/output-styles/laowang-engineer.md +1 -0
  27. package/templates/claude-code/en/output-styles/nekomata-engineer.md +1 -0
  28. package/templates/claude-code/en/output-styles/ojousama-engineer.md +1 -0
  29. package/templates/claude-code/zh-CN/output-styles/engineer-professional.md +2 -1
  30. package/templates/claude-code/zh-CN/output-styles/laowang-engineer.md +1 -0
  31. package/templates/claude-code/zh-CN/output-styles/nekomata-engineer.md +1 -0
  32. package/templates/claude-code/zh-CN/output-styles/ojousama-engineer.md +1 -0
  33. package/templates/codex/en/system-prompt/engineer-professional.md +2 -1
  34. package/templates/codex/en/system-prompt/laowang-engineer.md +1 -0
  35. package/templates/codex/en/system-prompt/nekomata-engineer.md +1 -0
  36. package/templates/codex/en/system-prompt/ojousama-engineer.md +1 -0
  37. package/templates/codex/zh-CN/system-prompt/engineer-professional.md +2 -1
  38. package/templates/codex/zh-CN/system-prompt/laowang-engineer.md +1 -0
  39. package/templates/codex/zh-CN/system-prompt/nekomata-engineer.md +1 -0
  40. package/templates/codex/zh-CN/system-prompt/ojousama-engineer.md +1 -0
@@ -1,6 +1,6 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
- import { a4 as ensureI18nInitialized, af as detectConfigManagementMode, a5 as i18n, a6 as addNumbersToChoices } from './simple-config.mjs';
3
+ import { a5 as ensureI18nInitialized, ag as detectConfigManagementMode, a6 as i18n, a7 as addNumbersToChoices } from './simple-config.mjs';
4
4
  import { deleteProviders, editExistingProvider, addProviderToExisting } from './codex-provider-manager.mjs';
5
5
  import 'node:fs';
6
6
  import 'node:process';
@@ -59,16 +59,41 @@ async function configureIncrementalManagement() {
59
59
  }
60
60
  }
61
61
  async function handleAddProvider() {
62
+ const { getApiProviders } = await import('./api-providers.mjs');
63
+ const apiProviders = getApiProviders("codex");
64
+ const providerChoices = [
65
+ { name: i18n.t("api:customProvider"), value: "custom" },
66
+ ...apiProviders.map((p) => ({ name: p.name, value: p.id }))
67
+ ];
68
+ const { selectedProvider } = await inquirer.prompt([{
69
+ type: "list",
70
+ name: "selectedProvider",
71
+ message: i18n.t("api:selectApiProvider"),
72
+ choices: addNumbersToChoices(providerChoices)
73
+ }]);
74
+ let prefilledBaseUrl;
75
+ let prefilledWireApi;
76
+ let prefilledModel;
77
+ if (selectedProvider !== "custom") {
78
+ const provider2 = apiProviders.find((p) => p.id === selectedProvider);
79
+ if (provider2?.codex) {
80
+ prefilledBaseUrl = provider2.codex.baseUrl;
81
+ prefilledWireApi = provider2.codex.wireApi;
82
+ prefilledModel = provider2.codex.defaultModel;
83
+ console.log(ansis.gray(i18n.t("api:providerSelected", { name: provider2.name })));
84
+ }
85
+ }
62
86
  const answers = await inquirer.prompt([
63
87
  {
64
88
  type: "input",
65
89
  name: "providerName",
66
90
  message: i18n.t("codex:providerNamePrompt"),
91
+ default: selectedProvider !== "custom" ? apiProviders.find((p) => p.id === selectedProvider)?.name : void 0,
67
92
  validate: (input) => {
68
93
  const trimmed = input.trim();
69
94
  if (!trimmed)
70
95
  return i18n.t("codex:providerNameRequired");
71
- if (!/^[\w\-\s]+$/.test(trimmed))
96
+ if (!/^[\w\-\s.]+$/.test(trimmed))
72
97
  return i18n.t("codex:providerNameInvalid");
73
98
  return true;
74
99
  }
@@ -77,7 +102,8 @@ async function handleAddProvider() {
77
102
  type: "input",
78
103
  name: "baseUrl",
79
104
  message: i18n.t("codex:providerBaseUrlPrompt"),
80
- default: "https://api.openai.com/v1",
105
+ default: prefilledBaseUrl || "https://api.openai.com/v1",
106
+ when: () => selectedProvider === "custom",
81
107
  validate: (input) => !!input.trim() || i18n.t("codex:providerBaseUrlRequired")
82
108
  },
83
109
  {
@@ -88,30 +114,63 @@ async function handleAddProvider() {
88
114
  { name: i18n.t("codex:protocolResponses"), value: "responses" },
89
115
  { name: i18n.t("codex:protocolChat"), value: "chat" }
90
116
  ],
91
- default: "responses"
117
+ default: prefilledWireApi || "responses",
118
+ when: () => selectedProvider === "custom"
92
119
  },
93
120
  {
94
- type: "password",
121
+ type: "input",
95
122
  name: "apiKey",
96
- message: i18n.t("codex:providerApiKeyPrompt") + i18n.t("common:inputHidden"),
123
+ message: selectedProvider !== "custom" ? i18n.t("api:enterProviderApiKey", { provider: apiProviders.find((p) => p.id === selectedProvider)?.name || selectedProvider }) : i18n.t("codex:providerApiKeyPrompt"),
97
124
  validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
98
125
  }
99
126
  ]);
100
- const providerId = answers.providerName.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9\-]/g, "");
127
+ const providerId = answers.providerName.trim().toLowerCase().replace(/\s+/g, "-").replace(/\./g, "-").replace(/[^a-z0-9\-]/g, "");
128
+ const managementMode = detectConfigManagementMode();
129
+ const existingProvider = managementMode.providers?.find((p) => p.id === providerId);
130
+ if (existingProvider) {
131
+ const { shouldOverwrite } = await inquirer.prompt([{
132
+ type: "confirm",
133
+ name: "shouldOverwrite",
134
+ message: i18n.t("codex:providerDuplicatePrompt", {
135
+ name: existingProvider.name,
136
+ source: i18n.t("codex:existingConfig")
137
+ }),
138
+ default: false
139
+ }]);
140
+ if (!shouldOverwrite) {
141
+ console.log(ansis.yellow(i18n.t("codex:providerDuplicateSkipped")));
142
+ return;
143
+ }
144
+ }
101
145
  const provider = {
102
146
  id: providerId,
103
147
  name: answers.providerName.trim(),
104
- baseUrl: answers.baseUrl.trim(),
105
- wireApi: answers.wireApi,
148
+ baseUrl: selectedProvider === "custom" ? answers.baseUrl.trim() : prefilledBaseUrl,
149
+ wireApi: selectedProvider === "custom" ? answers.wireApi : prefilledWireApi,
106
150
  envKey: `${providerId.toUpperCase().replace(/-/g, "_")}_API_KEY`,
107
- requiresOpenaiAuth: true
151
+ requiresOpenaiAuth: true,
152
+ model: prefilledModel || "gpt-5-codex"
153
+ // Use provider's default model or fallback
108
154
  };
109
- const result = await addProviderToExisting(provider, answers.apiKey.trim());
155
+ const result = await addProviderToExisting(provider, answers.apiKey.trim(), true);
110
156
  if (result.success) {
111
157
  console.log(ansis.green(i18n.t("codex:providerAdded", { name: result.addedProvider?.name })));
112
158
  if (result.backupPath) {
113
159
  console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
114
160
  }
161
+ const { setAsDefault } = await inquirer.prompt([{
162
+ type: "confirm",
163
+ name: "setAsDefault",
164
+ message: i18n.t("multi-config:setAsDefaultPrompt"),
165
+ default: true
166
+ }]);
167
+ if (setAsDefault) {
168
+ const { switchToProvider } = await import('./simple-config.mjs').then(function (n) { return n.b6; });
169
+ const switched = await switchToProvider(provider.id);
170
+ if (switched) {
171
+ console.log(ansis.green(i18n.t("multi-config:profileSetAsDefault", { name: provider.name })));
172
+ }
173
+ }
115
174
  } else {
116
175
  console.log(ansis.red(i18n.t("codex:providerAddFailed", { error: result.error })));
117
176
  }
@@ -169,9 +228,9 @@ async function handleEditProvider(providers) {
169
228
  default: provider.wireApi
170
229
  },
171
230
  {
172
- type: "password",
231
+ type: "input",
173
232
  name: "apiKey",
174
- message: i18n.t("codex:providerApiKeyPrompt") + i18n.t("common:inputHidden"),
233
+ message: i18n.t("codex:providerApiKeyPrompt"),
175
234
  validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
176
235
  }
177
236
  ]);
@@ -1,4 +1,4 @@
1
- import { ag as readCodexConfig, ah as backupCodexComplete, ai as writeCodexConfig, aj as writeAuthFile } from './simple-config.mjs';
1
+ import { ah as readCodexConfig, ai as backupCodexComplete, aj as writeCodexConfig, ak as writeAuthFile } from './simple-config.mjs';
2
2
  import 'node:fs';
3
3
  import 'node:process';
4
4
  import 'ansis';
@@ -26,7 +26,7 @@ const ERROR_MESSAGES = {
26
26
  PROVIDERS_NOT_FOUND: (providers) => `Some providers not found: ${providers.join(", ")}`,
27
27
  CANNOT_DELETE_ALL: "Cannot delete all providers. At least one provider must remain."
28
28
  };
29
- async function addProviderToExisting(provider, apiKey) {
29
+ async function addProviderToExisting(provider, apiKey, allowOverwrite = false) {
30
30
  try {
31
31
  const existingConfig = readCodexConfig();
32
32
  if (!existingConfig) {
@@ -35,8 +35,8 @@ async function addProviderToExisting(provider, apiKey) {
35
35
  error: ERROR_MESSAGES.NO_CONFIG
36
36
  };
37
37
  }
38
- const existingProvider = existingConfig.providers.find((p) => p.id === provider.id);
39
- if (existingProvider) {
38
+ const existingProviderIndex = existingConfig.providers.findIndex((p) => p.id === provider.id);
39
+ if (existingProviderIndex !== -1 && !allowOverwrite) {
40
40
  return {
41
41
  success: false,
42
42
  error: ERROR_MESSAGES.PROVIDER_EXISTS(provider.id)
@@ -49,10 +49,20 @@ async function addProviderToExisting(provider, apiKey) {
49
49
  error: ERROR_MESSAGES.BACKUP_FAILED
50
50
  };
51
51
  }
52
- const updatedConfig = {
53
- ...existingConfig,
54
- providers: [...existingConfig.providers, provider]
55
- };
52
+ let updatedConfig;
53
+ if (existingProviderIndex !== -1) {
54
+ const updatedProviders = [...existingConfig.providers];
55
+ updatedProviders[existingProviderIndex] = provider;
56
+ updatedConfig = {
57
+ ...existingConfig,
58
+ providers: updatedProviders
59
+ };
60
+ } else {
61
+ updatedConfig = {
62
+ ...existingConfig,
63
+ providers: [...existingConfig.providers, provider]
64
+ };
65
+ }
56
66
  writeCodexConfig(updatedConfig);
57
67
  const authEntries = {};
58
68
  authEntries[provider.envKey] = apiKey;
@@ -2,7 +2,7 @@ import { homedir } from 'node:os';
2
2
  import { pathExists } from 'fs-extra';
3
3
  import { join } from 'pathe';
4
4
  import { exec } from 'tinyexec';
5
- import { a5 as i18n } from './simple-config.mjs';
5
+ import { a6 as i18n } from './simple-config.mjs';
6
6
  import { m as moveToTrash } from '../shared/zcf.DGjQxTq_.mjs';
7
7
  import 'node:fs';
8
8
  import 'node:process';
@@ -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 { a4 as ensureI18nInitialized, a5 as i18n } from './simple-config.mjs';
4
+ import { a5 as ensureI18nInitialized, a6 as i18n } from './simple-config.mjs';
5
5
  import 'node:fs';
6
6
  import 'node:process';
7
7
  import 'inquirer';