zcf 3.1.3 → 3.2.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 (37) hide show
  1. package/README.md +50 -21
  2. package/dist/chunks/claude-code-config-manager.mjs +705 -0
  3. package/dist/chunks/claude-code-incremental-manager.mjs +393 -0
  4. package/dist/chunks/codex-config-switch.mjs +2 -174
  5. package/dist/chunks/codex-provider-manager.mjs +193 -0
  6. package/dist/chunks/codex-uninstaller.mjs +1 -1
  7. package/dist/chunks/commands.mjs +117 -0
  8. package/dist/chunks/simple-config.mjs +578 -193
  9. package/dist/cli.mjs +284 -142
  10. package/dist/i18n/locales/en/api.json +1 -2
  11. package/dist/i18n/locales/en/cli.json +2 -0
  12. package/dist/i18n/locales/en/codex.json +0 -1
  13. package/dist/i18n/locales/en/common.json +2 -2
  14. package/dist/i18n/locales/en/errors.json +1 -0
  15. package/dist/i18n/locales/en/multi-config.json +61 -0
  16. package/dist/i18n/locales/zh-CN/api.json +1 -2
  17. package/dist/i18n/locales/zh-CN/cli.json +2 -0
  18. package/dist/i18n/locales/zh-CN/codex.json +0 -1
  19. package/dist/i18n/locales/zh-CN/common.json +2 -2
  20. package/dist/i18n/locales/zh-CN/errors.json +1 -0
  21. package/dist/i18n/locales/zh-CN/multi-config.json +61 -0
  22. package/dist/index.d.mts +6 -2
  23. package/dist/index.d.ts +6 -2
  24. package/dist/index.mjs +1 -1
  25. package/package.json +1 -1
  26. package/templates/claude-code/en/workflow/git/commands/git-commit.md +1 -0
  27. package/templates/claude-code/zh-CN/workflow/git/commands/git-commit.md +1 -0
  28. package/templates/codex/en/workflow/git/prompts/git-cleanBranches.md +102 -0
  29. package/templates/codex/en/workflow/git/prompts/git-commit.md +158 -0
  30. package/templates/codex/en/workflow/git/prompts/git-rollback.md +90 -0
  31. package/templates/codex/en/workflow/git/prompts/git-worktree.md +276 -0
  32. package/templates/codex/en/workflow/sixStep/prompts/workflow.md +140 -121
  33. package/templates/codex/zh-CN/workflow/git/prompts/git-cleanBranches.md +102 -0
  34. package/templates/codex/zh-CN/workflow/git/prompts/git-commit.md +158 -0
  35. package/templates/codex/zh-CN/workflow/git/prompts/git-rollback.md +90 -0
  36. package/templates/codex/zh-CN/workflow/git/prompts/git-worktree.md +276 -0
  37. package/templates/codex/zh-CN/workflow/sixStep/prompts/workflow.md +16 -33
@@ -0,0 +1,393 @@
1
+ import ansis from 'ansis';
2
+ import inquirer from 'inquirer';
3
+ import { a2 as ensureI18nInitialized, a3 as i18n, a4 as addNumbersToChoices, a5 as validateApiKey } from './simple-config.mjs';
4
+ import { ClaudeCodeConfigManager } from './claude-code-config-manager.mjs';
5
+ import 'node:fs';
6
+ import 'node:process';
7
+ import 'node:child_process';
8
+ import 'node:os';
9
+ import 'node:util';
10
+ import 'dayjs';
11
+ import 'pathe';
12
+ import 'node:url';
13
+ import 'ora';
14
+ import 'semver';
15
+ import 'smol-toml';
16
+ import 'tinyexec';
17
+ import 'node:fs/promises';
18
+ import 'i18next';
19
+ import 'i18next-fs-backend';
20
+
21
+ function getAuthTypeLabel(authType) {
22
+ ensureI18nInitialized();
23
+ switch (authType) {
24
+ case "api_key":
25
+ return i18n.t("multi-config:authType.api_key");
26
+ case "auth_token":
27
+ return i18n.t("multi-config:authType.auth_token");
28
+ case "ccr_proxy":
29
+ return i18n.t("multi-config:authType.ccr_proxy");
30
+ default:
31
+ return authType;
32
+ }
33
+ }
34
+ async function configureIncrementalManagement() {
35
+ ensureI18nInitialized();
36
+ const config = ClaudeCodeConfigManager.readConfig();
37
+ if (!config || !config.profiles || Object.keys(config.profiles).length === 0) {
38
+ await handleAddProfile();
39
+ return;
40
+ }
41
+ const profiles = Object.values(config.profiles);
42
+ const currentProfile = config.currentProfileId ? config.profiles[config.currentProfileId] : null;
43
+ console.log(ansis.cyan(i18n.t("multi-config:incrementalManagementTitle")));
44
+ console.log(ansis.gray(i18n.t("multi-config:currentProfileCount", { count: profiles.length })));
45
+ if (currentProfile) {
46
+ console.log(ansis.gray(i18n.t("multi-config:currentDefaultProfile", { profile: currentProfile.name })));
47
+ }
48
+ const choices = [
49
+ { name: i18n.t("multi-config:addProfile"), value: "add" },
50
+ { name: i18n.t("multi-config:editProfile"), value: "edit" },
51
+ { name: i18n.t("multi-config:deleteProfile"), value: "delete" },
52
+ { name: i18n.t("common:skip"), value: "skip" }
53
+ ];
54
+ const { action } = await inquirer.prompt([{
55
+ type: "list",
56
+ name: "action",
57
+ message: i18n.t("multi-config:selectAction"),
58
+ choices: addNumbersToChoices(choices)
59
+ }]);
60
+ if (!action || action === "skip") {
61
+ console.log(ansis.yellow(i18n.t("common:skip")));
62
+ return;
63
+ }
64
+ switch (action) {
65
+ case "add":
66
+ await handleAddProfile();
67
+ break;
68
+ case "edit":
69
+ await handleEditProfile(profiles);
70
+ break;
71
+ case "delete":
72
+ await handleDeleteProfile(profiles);
73
+ break;
74
+ }
75
+ }
76
+ async function promptContinueAdding() {
77
+ const { continueAdding } = await inquirer.prompt([{
78
+ type: "confirm",
79
+ name: "continueAdding",
80
+ message: i18n.t("multi-config:addAnotherProfilePrompt"),
81
+ default: false
82
+ }]);
83
+ return continueAdding;
84
+ }
85
+ async function handleAddProfile() {
86
+ console.log(ansis.cyan(`
87
+ ${i18n.t("multi-config:addingNewProfile")}`));
88
+ const answers = await inquirer.prompt([
89
+ {
90
+ type: "input",
91
+ name: "profileName",
92
+ message: i18n.t("multi-config:profileNamePrompt"),
93
+ validate: (input) => {
94
+ const trimmed = input.trim();
95
+ if (!trimmed) {
96
+ return i18n.t("multi-config:profileNameRequired");
97
+ }
98
+ if (!/^[\w\-\s\u4E00-\u9FA5]+$/.test(trimmed)) {
99
+ return i18n.t("multi-config:profileNameInvalid");
100
+ }
101
+ return true;
102
+ }
103
+ },
104
+ {
105
+ type: "list",
106
+ name: "authType",
107
+ message: i18n.t("multi-config:authTypePrompt"),
108
+ choices: [
109
+ { name: i18n.t("multi-config:authType.api_key"), value: "api_key" },
110
+ { name: i18n.t("multi-config:authType.auth_token"), value: "auth_token" }
111
+ ],
112
+ default: "api_key"
113
+ },
114
+ {
115
+ type: "input",
116
+ name: "baseUrl",
117
+ message: i18n.t("multi-config:baseUrlPrompt"),
118
+ default: "https://api.anthropic.com",
119
+ when: (answers2) => answers2.authType !== "ccr_proxy",
120
+ validate: (input) => {
121
+ const trimmed = input.trim();
122
+ if (!trimmed) {
123
+ return i18n.t("multi-config:baseUrlRequired");
124
+ }
125
+ try {
126
+ new URL(trimmed);
127
+ return true;
128
+ } catch {
129
+ return i18n.t("multi-config:baseUrlInvalid");
130
+ }
131
+ }
132
+ },
133
+ {
134
+ type: "password",
135
+ name: "apiKey",
136
+ message: i18n.t("multi-config:apiKeyPrompt") + i18n.t("common:inputHidden"),
137
+ when: (answers2) => answers2.authType !== "ccr_proxy",
138
+ validate: (input) => {
139
+ const trimmed = input.trim();
140
+ if (!trimmed) {
141
+ return i18n.t("multi-config:apiKeyRequired");
142
+ }
143
+ const validation = validateApiKey(trimmed);
144
+ if (!validation.isValid) {
145
+ return validation.error || "Invalid API key format";
146
+ }
147
+ return true;
148
+ }
149
+ },
150
+ {
151
+ type: "confirm",
152
+ name: "setAsDefault",
153
+ message: i18n.t("multi-config:setAsDefaultPrompt"),
154
+ default: true
155
+ }
156
+ ]);
157
+ const profileName = answers.profileName.trim();
158
+ const profileId = ClaudeCodeConfigManager.generateProfileId(profileName);
159
+ const profile = {
160
+ id: profileId,
161
+ name: profileName,
162
+ authType: answers.authType
163
+ };
164
+ if (answers.authType !== "ccr_proxy") {
165
+ profile.apiKey = answers.apiKey.trim();
166
+ profile.baseUrl = answers.baseUrl.trim();
167
+ }
168
+ const existingProfile = ClaudeCodeConfigManager.getProfileByName(profile.name);
169
+ if (existingProfile) {
170
+ const { overwrite } = await inquirer.prompt([{
171
+ type: "confirm",
172
+ name: "overwrite",
173
+ message: i18n.t("multi-config:profileDuplicatePrompt", {
174
+ name: profile.name,
175
+ source: i18n.t("multi-config:existingConfig")
176
+ }),
177
+ default: false
178
+ }]);
179
+ if (!overwrite) {
180
+ console.log(ansis.yellow(i18n.t("multi-config:profileDuplicateSkipped", { name: profile.name })));
181
+ const shouldContinue2 = await promptContinueAdding();
182
+ if (shouldContinue2) {
183
+ await handleAddProfile();
184
+ }
185
+ return;
186
+ }
187
+ const updateResult = await ClaudeCodeConfigManager.updateProfile(existingProfile.id, {
188
+ name: profile.name,
189
+ authType: profile.authType,
190
+ apiKey: profile.apiKey,
191
+ baseUrl: profile.baseUrl
192
+ });
193
+ if (updateResult.success) {
194
+ console.log(ansis.green(i18n.t("multi-config:profileUpdated", { name: profile.name })));
195
+ if (updateResult.backupPath) {
196
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: updateResult.backupPath })));
197
+ }
198
+ if (answers.setAsDefault) {
199
+ const switchResult = await ClaudeCodeConfigManager.switchProfile(existingProfile.id);
200
+ if (switchResult.success) {
201
+ console.log(ansis.green(i18n.t("multi-config:profileSetAsDefault", { name: profile.name })));
202
+ await ClaudeCodeConfigManager.applyProfileSettings({ ...profile, id: existingProfile.id });
203
+ }
204
+ }
205
+ } else {
206
+ console.log(ansis.red(i18n.t("multi-config:profileUpdateFailed", { error: updateResult.error || "" })));
207
+ }
208
+ } else {
209
+ const result = await ClaudeCodeConfigManager.addProfile(profile);
210
+ if (result.success) {
211
+ const runtimeProfile = result.addedProfile || { ...profile, id: profileId };
212
+ console.log(ansis.green(i18n.t("multi-config:profileAdded", { name: runtimeProfile.name })));
213
+ if (result.backupPath) {
214
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
215
+ }
216
+ if (answers.setAsDefault) {
217
+ const switchResult = await ClaudeCodeConfigManager.switchProfile(runtimeProfile.id);
218
+ if (switchResult.success) {
219
+ console.log(ansis.green(i18n.t("multi-config:profileSetAsDefault", { name: runtimeProfile.name })));
220
+ await ClaudeCodeConfigManager.applyProfileSettings(runtimeProfile);
221
+ }
222
+ }
223
+ } else {
224
+ console.log(ansis.red(i18n.t("multi-config:profileAddFailed", { error: result.error })));
225
+ }
226
+ }
227
+ const shouldContinue = await promptContinueAdding();
228
+ if (shouldContinue) {
229
+ await handleAddProfile();
230
+ }
231
+ }
232
+ async function handleEditProfile(profiles) {
233
+ const choices = profiles.map((profile) => ({
234
+ name: `${profile.name} (${getAuthTypeLabel(profile.authType)})`,
235
+ value: profile.id
236
+ }));
237
+ const { selectedProfileId } = await inquirer.prompt([{
238
+ type: "list",
239
+ name: "selectedProfileId",
240
+ message: i18n.t("multi-config:selectProfileToEdit"),
241
+ choices: addNumbersToChoices(choices)
242
+ }]);
243
+ if (!selectedProfileId) {
244
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
245
+ return;
246
+ }
247
+ const selectedProfile = profiles.find((p) => p.id === selectedProfileId);
248
+ if (!selectedProfile) {
249
+ console.log(ansis.red(i18n.t("multi-config:profileNotFound")));
250
+ return;
251
+ }
252
+ console.log(ansis.cyan(`
253
+ ${i18n.t("multi-config:editingProfile", { name: selectedProfile.name })}`));
254
+ const answers = await inquirer.prompt([
255
+ {
256
+ type: "input",
257
+ name: "profileName",
258
+ message: i18n.t("multi-config:profileNamePrompt"),
259
+ default: selectedProfile.name,
260
+ validate: (input) => {
261
+ const trimmed = input.trim();
262
+ if (!trimmed) {
263
+ return i18n.t("multi-config:profileNameRequired");
264
+ }
265
+ if (!/^[\w\-\s\u4E00-\u9FA5]+$/.test(trimmed)) {
266
+ return i18n.t("multi-config:profileNameInvalid");
267
+ }
268
+ return true;
269
+ }
270
+ },
271
+ {
272
+ type: "input",
273
+ name: "baseUrl",
274
+ message: i18n.t("multi-config:baseUrlPrompt"),
275
+ default: selectedProfile.baseUrl || "https://api.anthropic.com",
276
+ when: () => selectedProfile.authType !== "ccr_proxy",
277
+ validate: (input) => {
278
+ const trimmed = input.trim();
279
+ if (!trimmed) {
280
+ return i18n.t("multi-config:baseUrlRequired");
281
+ }
282
+ try {
283
+ new URL(trimmed);
284
+ return true;
285
+ } catch {
286
+ return i18n.t("multi-config:baseUrlInvalid");
287
+ }
288
+ }
289
+ },
290
+ {
291
+ type: "password",
292
+ name: "apiKey",
293
+ message: i18n.t("multi-config:apiKeyPrompt") + i18n.t("common:inputHidden"),
294
+ default: selectedProfile.apiKey,
295
+ when: () => selectedProfile.authType !== "ccr_proxy",
296
+ validate: (input) => {
297
+ const trimmed = input.trim();
298
+ if (!trimmed) {
299
+ return i18n.t("multi-config:apiKeyRequired");
300
+ }
301
+ const validation = validateApiKey(trimmed);
302
+ if (!validation.isValid) {
303
+ return validation.error || "Invalid API key format";
304
+ }
305
+ return true;
306
+ }
307
+ }
308
+ ]);
309
+ const updateData = {
310
+ name: answers.profileName.trim()
311
+ };
312
+ if (selectedProfile.authType !== "ccr_proxy") {
313
+ updateData.apiKey = answers.apiKey.trim();
314
+ updateData.baseUrl = answers.baseUrl.trim();
315
+ }
316
+ const result = await ClaudeCodeConfigManager.updateProfile(selectedProfile.id, updateData);
317
+ if (result.success) {
318
+ console.log(ansis.green(i18n.t("multi-config:profileUpdated", { name: updateData.name })));
319
+ if (result.backupPath) {
320
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
321
+ }
322
+ const currentConfig = ClaudeCodeConfigManager.readConfig();
323
+ if (currentConfig?.currentProfileId === selectedProfile.id) {
324
+ const updatedProfile = ClaudeCodeConfigManager.getProfileById(selectedProfile.id);
325
+ if (updatedProfile) {
326
+ await ClaudeCodeConfigManager.applyProfileSettings(updatedProfile);
327
+ console.log(ansis.green(i18n.t("multi-config:settingsApplied")));
328
+ }
329
+ }
330
+ } else {
331
+ console.log(ansis.red(i18n.t("multi-config:profileUpdateFailed", { error: result.error })));
332
+ }
333
+ }
334
+ async function handleDeleteProfile(profiles) {
335
+ if (profiles.length <= 1) {
336
+ console.log(ansis.yellow(i18n.t("multi-config:cannotDeleteLast")));
337
+ return;
338
+ }
339
+ const choices = profiles.map((profile) => ({
340
+ name: `${profile.name} (${getAuthTypeLabel(profile.authType)})`,
341
+ value: profile.id
342
+ }));
343
+ const { selectedProfileIds } = await inquirer.prompt({
344
+ type: "checkbox",
345
+ name: "selectedProfileIds",
346
+ message: i18n.t("multi-config:selectProfilesToDelete"),
347
+ choices: addNumbersToChoices(choices),
348
+ validate: (input) => {
349
+ if (input.length === 0) {
350
+ return i18n.t("multi-config:selectAtLeastOne");
351
+ }
352
+ if (input.length >= profiles.length) {
353
+ return i18n.t("multi-config:cannotDeleteAll");
354
+ }
355
+ return true;
356
+ }
357
+ });
358
+ if (!selectedProfileIds || selectedProfileIds.length === 0) {
359
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
360
+ return;
361
+ }
362
+ const selectedNames = selectedProfileIds.map(
363
+ (id) => profiles.find((p) => p.id === id)?.name || id
364
+ );
365
+ const { confirmed } = await inquirer.prompt([{
366
+ type: "confirm",
367
+ name: "confirmed",
368
+ message: i18n.t("multi-config:confirmDeleteProfiles", { providers: selectedNames.join(", ") }),
369
+ default: false
370
+ }]);
371
+ if (!confirmed) {
372
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
373
+ return;
374
+ }
375
+ const result = await ClaudeCodeConfigManager.deleteProfiles(selectedProfileIds);
376
+ if (result.success) {
377
+ console.log(ansis.green(i18n.t("multi-config:profilesDeleted", { count: selectedProfileIds.length })));
378
+ if (result.backupPath) {
379
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
380
+ }
381
+ if (result.newCurrentProfileId) {
382
+ const newProfile = ClaudeCodeConfigManager.getProfileById(result.newCurrentProfileId);
383
+ if (newProfile) {
384
+ console.log(ansis.cyan(i18n.t("multi-config:newDefaultProfile", { profile: newProfile.name })));
385
+ await ClaudeCodeConfigManager.applyProfileSettings(newProfile);
386
+ }
387
+ }
388
+ } else {
389
+ console.log(ansis.red(i18n.t("multi-config:profilesDeleteFailed", { error: result.error })));
390
+ }
391
+ }
392
+
393
+ export { configureIncrementalManagement };
@@ -1,6 +1,7 @@
1
1
  import ansis from 'ansis';
2
2
  import inquirer from 'inquirer';
3
- import { a1 as readCodexConfig, a2 as backupCodexComplete, a3 as writeCodexConfig, a4 as writeAuthFile, a5 as ensureI18nInitialized, a6 as detectConfigManagementMode, a0 as i18n, a7 as addNumbersToChoices } from './simple-config.mjs';
3
+ import { a2 as ensureI18nInitialized, ad as detectConfigManagementMode, a3 as i18n, a4 as addNumbersToChoices } from './simple-config.mjs';
4
+ import { deleteProviders, editExistingProvider, addProviderToExisting } from './codex-provider-manager.mjs';
4
5
  import 'node:fs';
5
6
  import 'node:process';
6
7
  import 'node:child_process';
@@ -17,179 +18,6 @@ import 'node:fs/promises';
17
18
  import 'i18next';
18
19
  import 'i18next-fs-backend';
19
20
 
20
- const ERROR_MESSAGES = {
21
- NO_CONFIG: "No existing configuration found",
22
- BACKUP_FAILED: "Failed to create backup",
23
- PROVIDER_EXISTS: (id) => `Provider with ID "${id}" already exists`,
24
- PROVIDER_NOT_FOUND: (id) => `Provider with ID "${id}" not found`,
25
- NO_PROVIDERS_SPECIFIED: "No providers specified for deletion",
26
- PROVIDERS_NOT_FOUND: (providers) => `Some providers not found: ${providers.join(", ")}`,
27
- CANNOT_DELETE_ALL: "Cannot delete all providers. At least one provider must remain."
28
- };
29
- async function addProviderToExisting(provider, apiKey) {
30
- try {
31
- const existingConfig = readCodexConfig();
32
- if (!existingConfig) {
33
- return {
34
- success: false,
35
- error: ERROR_MESSAGES.NO_CONFIG
36
- };
37
- }
38
- const existingProvider = existingConfig.providers.find((p) => p.id === provider.id);
39
- if (existingProvider) {
40
- return {
41
- success: false,
42
- error: ERROR_MESSAGES.PROVIDER_EXISTS(provider.id)
43
- };
44
- }
45
- const backupPath = backupCodexComplete();
46
- if (!backupPath) {
47
- return {
48
- success: false,
49
- error: ERROR_MESSAGES.BACKUP_FAILED
50
- };
51
- }
52
- const updatedConfig = {
53
- ...existingConfig,
54
- providers: [...existingConfig.providers, provider]
55
- };
56
- writeCodexConfig(updatedConfig);
57
- const authEntries = {};
58
- authEntries[provider.envKey] = apiKey;
59
- writeAuthFile(authEntries);
60
- return {
61
- success: true,
62
- backupPath,
63
- addedProvider: provider
64
- };
65
- } catch (error) {
66
- return {
67
- success: false,
68
- error: error instanceof Error ? error.message : "Unknown error"
69
- };
70
- }
71
- }
72
- async function editExistingProvider(providerId, updates) {
73
- try {
74
- const existingConfig = readCodexConfig();
75
- if (!existingConfig) {
76
- return {
77
- success: false,
78
- error: ERROR_MESSAGES.NO_CONFIG
79
- };
80
- }
81
- const providerIndex = existingConfig.providers.findIndex((p) => p.id === providerId);
82
- if (providerIndex === -1) {
83
- return {
84
- success: false,
85
- error: ERROR_MESSAGES.PROVIDER_NOT_FOUND(providerId)
86
- };
87
- }
88
- const backupPath = backupCodexComplete();
89
- if (!backupPath) {
90
- return {
91
- success: false,
92
- error: ERROR_MESSAGES.BACKUP_FAILED
93
- };
94
- }
95
- const updatedProvider = {
96
- ...existingConfig.providers[providerIndex],
97
- ...updates.name && { name: updates.name },
98
- ...updates.baseUrl && { baseUrl: updates.baseUrl },
99
- ...updates.wireApi && { wireApi: updates.wireApi }
100
- };
101
- const updatedProviders = [...existingConfig.providers];
102
- updatedProviders[providerIndex] = updatedProvider;
103
- const updatedConfig = {
104
- ...existingConfig,
105
- providers: updatedProviders
106
- };
107
- writeCodexConfig(updatedConfig);
108
- if (updates.apiKey) {
109
- const authEntries = {};
110
- authEntries[updatedProvider.envKey] = updates.apiKey;
111
- writeAuthFile(authEntries);
112
- }
113
- return {
114
- success: true,
115
- backupPath,
116
- updatedProvider
117
- };
118
- } catch (error) {
119
- return {
120
- success: false,
121
- error: error instanceof Error ? error.message : "Unknown error"
122
- };
123
- }
124
- }
125
- async function deleteProviders(providerIds) {
126
- try {
127
- const existingConfig = readCodexConfig();
128
- if (!existingConfig) {
129
- return {
130
- success: false,
131
- error: ERROR_MESSAGES.NO_CONFIG
132
- };
133
- }
134
- if (!providerIds || providerIds.length === 0) {
135
- return {
136
- success: false,
137
- error: ERROR_MESSAGES.NO_PROVIDERS_SPECIFIED
138
- };
139
- }
140
- const notFoundProviders = providerIds.filter(
141
- (id) => !existingConfig.providers.some((p) => p.id === id)
142
- );
143
- if (notFoundProviders.length > 0) {
144
- return {
145
- success: false,
146
- error: ERROR_MESSAGES.PROVIDERS_NOT_FOUND(notFoundProviders)
147
- };
148
- }
149
- const remainingProviders = existingConfig.providers.filter(
150
- (p) => !providerIds.includes(p.id)
151
- );
152
- if (remainingProviders.length === 0) {
153
- return {
154
- success: false,
155
- error: ERROR_MESSAGES.CANNOT_DELETE_ALL
156
- };
157
- }
158
- const backupPath = backupCodexComplete();
159
- if (!backupPath) {
160
- return {
161
- success: false,
162
- error: ERROR_MESSAGES.BACKUP_FAILED
163
- };
164
- }
165
- let newDefaultProvider = existingConfig.modelProvider;
166
- if (providerIds.includes(existingConfig.modelProvider || "")) {
167
- newDefaultProvider = remainingProviders[0].id;
168
- }
169
- const updatedConfig = {
170
- ...existingConfig,
171
- modelProvider: newDefaultProvider,
172
- providers: remainingProviders
173
- };
174
- writeCodexConfig(updatedConfig);
175
- const result = {
176
- success: true,
177
- backupPath,
178
- deletedProviders: providerIds,
179
- remainingProviders
180
- };
181
- if (newDefaultProvider !== existingConfig.modelProvider) {
182
- result.newDefaultProvider = newDefaultProvider || void 0;
183
- }
184
- return result;
185
- } catch (error) {
186
- return {
187
- success: false,
188
- error: error instanceof Error ? error.message : "Unknown error"
189
- };
190
- }
191
- }
192
-
193
21
  async function configureIncrementalManagement() {
194
22
  ensureI18nInitialized();
195
23
  const managementMode = detectConfigManagementMode();