ccjk 1.3.1

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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +455 -0
  3. package/README.ko.md +455 -0
  4. package/README.md +550 -0
  5. package/README.zh-CN.md +488 -0
  6. package/bin/ccjk.mjs +2 -0
  7. package/dist/chunks/api-providers.mjs +89 -0
  8. package/dist/chunks/claude-code-config-manager.mjs +733 -0
  9. package/dist/chunks/claude-code-incremental-manager.mjs +603 -0
  10. package/dist/chunks/codex-config-switch.mjs +427 -0
  11. package/dist/chunks/codex-provider-manager.mjs +232 -0
  12. package/dist/chunks/codex-uninstaller.mjs +404 -0
  13. package/dist/chunks/commands.mjs +120 -0
  14. package/dist/chunks/features.mjs +642 -0
  15. package/dist/chunks/simple-config.mjs +10445 -0
  16. package/dist/cli.d.mts +1 -0
  17. package/dist/cli.d.ts +1 -0
  18. package/dist/cli.mjs +5972 -0
  19. package/dist/i18n/locales/en/api.json +63 -0
  20. package/dist/i18n/locales/en/ccjk.json +276 -0
  21. package/dist/i18n/locales/en/ccr.json +65 -0
  22. package/dist/i18n/locales/en/cli.json +57 -0
  23. package/dist/i18n/locales/en/codex.json +124 -0
  24. package/dist/i18n/locales/en/cometix.json +29 -0
  25. package/dist/i18n/locales/en/common.json +20 -0
  26. package/dist/i18n/locales/en/configuration.json +77 -0
  27. package/dist/i18n/locales/en/errors.json +26 -0
  28. package/dist/i18n/locales/en/installation.json +80 -0
  29. package/dist/i18n/locales/en/interview.json +104 -0
  30. package/dist/i18n/locales/en/language.json +19 -0
  31. package/dist/i18n/locales/en/mcp.json +38 -0
  32. package/dist/i18n/locales/en/menu.json +51 -0
  33. package/dist/i18n/locales/en/multi-config.json +79 -0
  34. package/dist/i18n/locales/en/shencha.json +14 -0
  35. package/dist/i18n/locales/en/team.json +7 -0
  36. package/dist/i18n/locales/en/tools.json +42 -0
  37. package/dist/i18n/locales/en/uninstall.json +56 -0
  38. package/dist/i18n/locales/en/updater.json +25 -0
  39. package/dist/i18n/locales/en/workflow.json +25 -0
  40. package/dist/i18n/locales/zh-CN/api.json +63 -0
  41. package/dist/i18n/locales/zh-CN/ccjk.json +276 -0
  42. package/dist/i18n/locales/zh-CN/ccr.json +65 -0
  43. package/dist/i18n/locales/zh-CN/cli.json +57 -0
  44. package/dist/i18n/locales/zh-CN/codex.json +124 -0
  45. package/dist/i18n/locales/zh-CN/cometix.json +29 -0
  46. package/dist/i18n/locales/zh-CN/common.json +20 -0
  47. package/dist/i18n/locales/zh-CN/configuration.json +77 -0
  48. package/dist/i18n/locales/zh-CN/errors.json +26 -0
  49. package/dist/i18n/locales/zh-CN/installation.json +80 -0
  50. package/dist/i18n/locales/zh-CN/interview.json +104 -0
  51. package/dist/i18n/locales/zh-CN/language.json +19 -0
  52. package/dist/i18n/locales/zh-CN/mcp.json +38 -0
  53. package/dist/i18n/locales/zh-CN/menu.json +51 -0
  54. package/dist/i18n/locales/zh-CN/multi-config.json +79 -0
  55. package/dist/i18n/locales/zh-CN/shencha.json +14 -0
  56. package/dist/i18n/locales/zh-CN/team.json +7 -0
  57. package/dist/i18n/locales/zh-CN/tools.json +42 -0
  58. package/dist/i18n/locales/zh-CN/uninstall.json +56 -0
  59. package/dist/i18n/locales/zh-CN/updater.json +25 -0
  60. package/dist/i18n/locales/zh-CN/workflow.json +25 -0
  61. package/dist/index.d.mts +2644 -0
  62. package/dist/index.d.ts +2644 -0
  63. package/dist/index.mjs +1706 -0
  64. package/package.json +157 -0
  65. package/templates/CLAUDE.md +219 -0
  66. package/templates/claude-code/CLAUDE.md +250 -0
  67. package/templates/claude-code/common/settings.json +38 -0
  68. package/templates/claude-code/en/workflow/bmad/commands/bmad-init.md +165 -0
  69. package/templates/claude-code/en/workflow/common/agents/get-current-datetime.md +29 -0
  70. package/templates/claude-code/en/workflow/common/agents/init-architect.md +114 -0
  71. package/templates/claude-code/en/workflow/common/commands/init-project.md +53 -0
  72. package/templates/claude-code/en/workflow/plan/agents/planner.md +116 -0
  73. package/templates/claude-code/en/workflow/plan/agents/ui-ux-designer.md +91 -0
  74. package/templates/claude-code/en/workflow/plan/commands/feat.md +105 -0
  75. package/templates/claude-code/zh-CN/workflow/bmad/commands/bmad-init.md +172 -0
  76. package/templates/claude-code/zh-CN/workflow/common/agents/get-current-datetime.md +29 -0
  77. package/templates/claude-code/zh-CN/workflow/common/agents/init-architect.md +114 -0
  78. package/templates/claude-code/zh-CN/workflow/common/commands/init-project.md +53 -0
  79. package/templates/claude-code/zh-CN/workflow/plan/agents/planner.md +116 -0
  80. package/templates/claude-code/zh-CN/workflow/plan/agents/ui-ux-designer.md +91 -0
  81. package/templates/claude-code/zh-CN/workflow/plan/commands/feat.md +105 -0
  82. package/templates/codex/common/config.toml +0 -0
  83. package/templates/common/output-styles/en/casual-friendly.md +97 -0
  84. package/templates/common/output-styles/en/engineer-professional.md +88 -0
  85. package/templates/common/output-styles/en/expert-concise.md +93 -0
  86. package/templates/common/output-styles/en/laowang-engineer.md +127 -0
  87. package/templates/common/output-styles/en/nekomata-engineer.md +120 -0
  88. package/templates/common/output-styles/en/ojousama-engineer.md +121 -0
  89. package/templates/common/output-styles/en/teaching-mode.md +102 -0
  90. package/templates/common/output-styles/en/technical-precise.md +101 -0
  91. package/templates/common/output-styles/zh-CN/engineer-professional.md +89 -0
  92. package/templates/common/output-styles/zh-CN/laowang-engineer.md +127 -0
  93. package/templates/common/output-styles/zh-CN/nekomata-engineer.md +120 -0
  94. package/templates/common/output-styles/zh-CN/ojousama-engineer.md +121 -0
  95. package/templates/common/workflow/git/en/git-cleanBranches.md +102 -0
  96. package/templates/common/workflow/git/en/git-commit.md +205 -0
  97. package/templates/common/workflow/git/en/git-rollback.md +90 -0
  98. package/templates/common/workflow/git/en/git-worktree.md +276 -0
  99. package/templates/common/workflow/git/zh-CN/git-cleanBranches.md +102 -0
  100. package/templates/common/workflow/git/zh-CN/git-commit.md +205 -0
  101. package/templates/common/workflow/git/zh-CN/git-rollback.md +90 -0
  102. package/templates/common/workflow/git/zh-CN/git-worktree.md +276 -0
  103. package/templates/common/workflow/interview/en/interview.md +212 -0
  104. package/templates/common/workflow/interview/zh-CN/interview.md +212 -0
  105. package/templates/common/workflow/sixStep/en/workflow.md +251 -0
  106. package/templates/common/workflow/sixStep/zh-CN/workflow.md +215 -0
  107. package/templates/industry/devops/en/ci-cd-pipeline.md +410 -0
  108. package/templates/industry/web-dev/en/api-design.md +299 -0
  109. package/templates/industry/web-dev/en/react-nextjs-setup.md +236 -0
@@ -0,0 +1,427 @@
1
+ import ansis from 'ansis';
2
+ import inquirer from 'inquirer';
3
+ import { co as ensureI18nInitialized, aZ as detectConfigManagementMode, cj as i18n, cz as addNumbersToChoices, ct as promptBoolean, cC as readJsonConfig, z as CODEX_AUTH_FILE } from './simple-config.mjs';
4
+ import { deleteProviders, addProviderToExisting, editExistingProvider } from './codex-provider-manager.mjs';
5
+ import 'node:fs';
6
+ import 'node:process';
7
+ import 'pathe';
8
+ import 'smol-toml';
9
+ import 'dayjs';
10
+ import 'node:child_process';
11
+ import 'node:os';
12
+ import 'node:util';
13
+ import 'node:url';
14
+ import 'inquirer-toggle';
15
+ import 'ora';
16
+ import 'tinyexec';
17
+ import 'semver';
18
+ import 'node:fs/promises';
19
+ import 'fs-extra';
20
+ import 'trash';
21
+ import 'i18next';
22
+ import 'i18next-fs-backend';
23
+
24
+ async function configureIncrementalManagement() {
25
+ ensureI18nInitialized();
26
+ const managementMode = detectConfigManagementMode();
27
+ if (managementMode.mode !== "management" || !managementMode.hasProviders) {
28
+ console.log(ansis.yellow(i18n.t("codex:noExistingProviders")));
29
+ return;
30
+ }
31
+ console.log(ansis.cyan(i18n.t("codex:incrementalManagementTitle")));
32
+ console.log(ansis.gray(i18n.t("codex:currentProviderCount", { count: managementMode.providerCount })));
33
+ if (managementMode.currentProvider) {
34
+ console.log(ansis.gray(i18n.t("codex:currentDefaultProvider", { provider: managementMode.currentProvider })));
35
+ }
36
+ const choices = [
37
+ { name: i18n.t("codex:addProvider"), value: "add" },
38
+ { name: i18n.t("codex:editProvider"), value: "edit" },
39
+ { name: i18n.t("codex:copyProvider"), value: "copy" },
40
+ { name: i18n.t("codex:deleteProvider"), value: "delete" },
41
+ { name: i18n.t("common:skip"), value: "skip" }
42
+ ];
43
+ const { action } = await inquirer.prompt([{
44
+ type: "list",
45
+ name: "action",
46
+ message: i18n.t("codex:selectAction"),
47
+ choices: addNumbersToChoices(choices)
48
+ }]);
49
+ if (!action || action === "skip") {
50
+ console.log(ansis.yellow(i18n.t("common:skip")));
51
+ return;
52
+ }
53
+ switch (action) {
54
+ case "add":
55
+ await handleAddProvider();
56
+ break;
57
+ case "edit":
58
+ await handleEditProvider(managementMode.providers);
59
+ break;
60
+ case "copy":
61
+ await handleCopyProvider(managementMode.providers);
62
+ break;
63
+ case "delete":
64
+ await handleDeleteProvider(managementMode.providers);
65
+ break;
66
+ }
67
+ }
68
+ async function handleAddProvider() {
69
+ const { getApiProviders } = await import('./api-providers.mjs');
70
+ const apiProviders = getApiProviders("codex");
71
+ const providerChoices = [
72
+ { name: i18n.t("api:customProvider"), value: "custom" },
73
+ ...apiProviders.map((p) => ({ name: p.name, value: p.id }))
74
+ ];
75
+ const { selectedProvider } = await inquirer.prompt([{
76
+ type: "list",
77
+ name: "selectedProvider",
78
+ message: i18n.t("api:selectApiProvider"),
79
+ choices: addNumbersToChoices(providerChoices)
80
+ }]);
81
+ let prefilledBaseUrl;
82
+ let prefilledWireApi;
83
+ let prefilledModel;
84
+ if (selectedProvider !== "custom") {
85
+ const provider2 = apiProviders.find((p) => p.id === selectedProvider);
86
+ if (provider2?.codex) {
87
+ prefilledBaseUrl = provider2.codex.baseUrl;
88
+ prefilledWireApi = provider2.codex.wireApi;
89
+ prefilledModel = provider2.codex.defaultModel;
90
+ console.log(ansis.gray(i18n.t("api:providerSelected", { name: provider2.name })));
91
+ }
92
+ }
93
+ const answers = await inquirer.prompt([
94
+ {
95
+ type: "input",
96
+ name: "providerName",
97
+ message: i18n.t("codex:providerNamePrompt"),
98
+ default: selectedProvider !== "custom" ? apiProviders.find((p) => p.id === selectedProvider)?.name : void 0,
99
+ validate: (input) => {
100
+ const trimmed = input.trim();
101
+ if (!trimmed)
102
+ return i18n.t("codex:providerNameRequired");
103
+ if (!/^[\w\-\s.]+$/.test(trimmed))
104
+ return i18n.t("codex:providerNameInvalid");
105
+ return true;
106
+ }
107
+ },
108
+ {
109
+ type: "input",
110
+ name: "baseUrl",
111
+ message: i18n.t("codex:providerBaseUrlPrompt"),
112
+ default: prefilledBaseUrl || "https://api.openai.com/v1",
113
+ when: () => selectedProvider === "custom",
114
+ validate: (input) => !!input.trim() || i18n.t("codex:providerBaseUrlRequired")
115
+ },
116
+ {
117
+ type: "list",
118
+ name: "wireApi",
119
+ message: i18n.t("codex:providerProtocolPrompt"),
120
+ choices: [
121
+ { name: i18n.t("codex:protocolResponses"), value: "responses" },
122
+ { name: i18n.t("codex:protocolChat"), value: "chat" }
123
+ ],
124
+ default: prefilledWireApi || "responses",
125
+ when: () => selectedProvider === "custom"
126
+ },
127
+ {
128
+ type: "input",
129
+ name: "apiKey",
130
+ message: selectedProvider !== "custom" ? i18n.t("api:enterProviderApiKey", { provider: apiProviders.find((p) => p.id === selectedProvider)?.name || selectedProvider }) : i18n.t("codex:providerApiKeyPrompt"),
131
+ validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
132
+ }
133
+ ]);
134
+ const providerId = answers.providerName.trim().toLowerCase().replace(/\s+/g, "-").replace(/\./g, "-").replace(/[^a-z0-9\-]/g, "");
135
+ const managementMode = detectConfigManagementMode();
136
+ const existingProvider = managementMode.providers?.find((p) => p.id === providerId);
137
+ if (existingProvider) {
138
+ const shouldOverwrite = await promptBoolean({
139
+ message: i18n.t("codex:providerDuplicatePrompt", {
140
+ name: existingProvider.name,
141
+ source: i18n.t("codex:existingConfig")
142
+ }),
143
+ defaultValue: false
144
+ });
145
+ if (!shouldOverwrite) {
146
+ console.log(ansis.yellow(i18n.t("codex:providerDuplicateSkipped")));
147
+ return;
148
+ }
149
+ }
150
+ const provider = {
151
+ id: providerId,
152
+ name: answers.providerName.trim(),
153
+ baseUrl: selectedProvider === "custom" ? answers.baseUrl.trim() : prefilledBaseUrl,
154
+ wireApi: selectedProvider === "custom" ? answers.wireApi : prefilledWireApi,
155
+ tempEnvKey: `${providerId.toUpperCase().replace(/-/g, "_")}_API_KEY`,
156
+ requiresOpenaiAuth: true,
157
+ model: prefilledModel || "gpt-5-codex"
158
+ // Use provider's default model or fallback
159
+ };
160
+ const result = await addProviderToExisting(provider, answers.apiKey.trim(), true);
161
+ if (result.success) {
162
+ console.log(ansis.green(i18n.t("codex:providerAdded", { name: result.addedProvider?.name })));
163
+ if (result.backupPath) {
164
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
165
+ }
166
+ const setAsDefault = await promptBoolean({
167
+ message: i18n.t("multi-config:setAsDefaultPrompt"),
168
+ defaultValue: true
169
+ });
170
+ if (setAsDefault) {
171
+ const { switchToProvider } = await import('./simple-config.mjs').then(function (n) { return n.da; });
172
+ const switched = await switchToProvider(provider.id);
173
+ if (switched) {
174
+ console.log(ansis.green(i18n.t("multi-config:profileSetAsDefault", { name: provider.name })));
175
+ }
176
+ }
177
+ } else {
178
+ console.log(ansis.red(i18n.t("codex:providerAddFailed", { error: result.error })));
179
+ }
180
+ }
181
+ async function handleEditProvider(providers) {
182
+ const choices = providers.map((provider2) => ({
183
+ name: `${provider2.name} (${provider2.baseUrl})`,
184
+ value: provider2.id
185
+ }));
186
+ const { selectedProviderId } = await inquirer.prompt([{
187
+ type: "list",
188
+ name: "selectedProviderId",
189
+ message: i18n.t("codex:selectProviderToEdit"),
190
+ choices: addNumbersToChoices(choices)
191
+ }]);
192
+ if (!selectedProviderId) {
193
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
194
+ return;
195
+ }
196
+ const provider = providers.find((p) => p.id === selectedProviderId);
197
+ if (!provider) {
198
+ console.log(ansis.red(i18n.t("codex:providerNotFound")));
199
+ return;
200
+ }
201
+ const existingAuth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
202
+ const existingApiKey = existingAuth[provider.tempEnvKey] || "";
203
+ const answers = await inquirer.prompt([
204
+ {
205
+ type: "input",
206
+ name: "providerName",
207
+ message: i18n.t("codex:providerNamePrompt"),
208
+ default: provider.name,
209
+ validate: (input) => {
210
+ const trimmed = input.trim();
211
+ if (!trimmed)
212
+ return i18n.t("codex:providerNameRequired");
213
+ if (!/^[\w\-\s]+$/.test(trimmed))
214
+ return i18n.t("codex:providerNameInvalid");
215
+ return true;
216
+ }
217
+ },
218
+ {
219
+ type: "input",
220
+ name: "baseUrl",
221
+ message: i18n.t("codex:providerBaseUrlPrompt"),
222
+ default: provider.baseUrl,
223
+ validate: (input) => !!input.trim() || i18n.t("codex:providerBaseUrlRequired")
224
+ },
225
+ {
226
+ type: "list",
227
+ name: "wireApi",
228
+ message: i18n.t("codex:providerProtocolPrompt"),
229
+ choices: [
230
+ { name: i18n.t("codex:protocolResponses"), value: "responses" },
231
+ { name: i18n.t("codex:protocolChat"), value: "chat" }
232
+ ],
233
+ default: provider.wireApi
234
+ },
235
+ {
236
+ type: "input",
237
+ name: "apiKey",
238
+ message: i18n.t("codex:providerApiKeyPrompt"),
239
+ default: existingApiKey,
240
+ // Show old API key from auth.json
241
+ validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
242
+ }
243
+ ]);
244
+ const { model } = await inquirer.prompt([
245
+ {
246
+ type: "input",
247
+ name: "model",
248
+ message: i18n.t("codex:providerModelPrompt"),
249
+ default: provider.model || "gpt-5-codex",
250
+ validate: (input) => !!input.trim() || i18n.t("codex:providerModelRequired")
251
+ }
252
+ ]);
253
+ const updates = {
254
+ name: answers.providerName.trim(),
255
+ baseUrl: answers.baseUrl.trim(),
256
+ wireApi: answers.wireApi,
257
+ apiKey: answers.apiKey.trim(),
258
+ model: model.trim()
259
+ };
260
+ const result = await editExistingProvider(selectedProviderId, updates);
261
+ if (result.success) {
262
+ console.log(ansis.green(i18n.t("codex:providerUpdated", { name: result.updatedProvider?.name })));
263
+ if (result.backupPath) {
264
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
265
+ }
266
+ } else {
267
+ console.log(ansis.red(i18n.t("codex:providerUpdateFailed", { error: result.error })));
268
+ }
269
+ }
270
+ async function handleCopyProvider(providers) {
271
+ const choices = providers.map((provider2) => ({
272
+ name: `${provider2.name} (${provider2.baseUrl})`,
273
+ value: provider2.id
274
+ }));
275
+ const { selectedProviderId } = await inquirer.prompt([{
276
+ type: "list",
277
+ name: "selectedProviderId",
278
+ message: i18n.t("codex:selectProviderToCopy"),
279
+ choices: addNumbersToChoices(choices)
280
+ }]);
281
+ if (!selectedProviderId) {
282
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
283
+ return;
284
+ }
285
+ const provider = providers.find((p) => p.id === selectedProviderId);
286
+ if (!provider) {
287
+ console.log(ansis.red(i18n.t("codex:providerNotFound")));
288
+ return;
289
+ }
290
+ console.log(ansis.cyan(`
291
+ ${i18n.t("codex:copyingProvider", { name: provider.name })}`));
292
+ const existingAuth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
293
+ const existingApiKey = existingAuth[provider.tempEnvKey] || "";
294
+ const copiedName = `${provider.name}-copy`;
295
+ const answers = await inquirer.prompt([
296
+ {
297
+ type: "input",
298
+ name: "providerName",
299
+ message: i18n.t("codex:providerNamePrompt"),
300
+ default: copiedName,
301
+ validate: (input) => {
302
+ const trimmed = input.trim();
303
+ if (!trimmed)
304
+ return i18n.t("codex:providerNameRequired");
305
+ if (!/^[\w\-\s.]+$/.test(trimmed))
306
+ return i18n.t("codex:providerNameInvalid");
307
+ return true;
308
+ }
309
+ },
310
+ {
311
+ type: "input",
312
+ name: "baseUrl",
313
+ message: i18n.t("codex:providerBaseUrlPrompt"),
314
+ default: provider.baseUrl,
315
+ validate: (input) => !!input.trim() || i18n.t("codex:providerBaseUrlRequired")
316
+ },
317
+ {
318
+ type: "list",
319
+ name: "wireApi",
320
+ message: i18n.t("codex:providerProtocolPrompt"),
321
+ choices: [
322
+ { name: i18n.t("codex:protocolResponses"), value: "responses" },
323
+ { name: i18n.t("codex:protocolChat"), value: "chat" }
324
+ ],
325
+ default: provider.wireApi
326
+ },
327
+ {
328
+ type: "input",
329
+ name: "apiKey",
330
+ message: i18n.t("codex:providerApiKeyPrompt"),
331
+ default: existingApiKey,
332
+ // Show old API key from auth.json
333
+ validate: (input) => !!input.trim() || i18n.t("codex:providerApiKeyRequired")
334
+ }
335
+ ]);
336
+ const { model } = await inquirer.prompt([
337
+ {
338
+ type: "input",
339
+ name: "model",
340
+ message: i18n.t("codex:providerModelPrompt"),
341
+ default: provider.model || "gpt-5-codex",
342
+ validate: (input) => !!input.trim() || i18n.t("codex:providerModelRequired")
343
+ }
344
+ ]);
345
+ const providerId = answers.providerName.trim().toLowerCase().replace(/\s+/g, "-").replace(/\./g, "-").replace(/[^a-z0-9\-]/g, "");
346
+ const copiedProvider = {
347
+ id: providerId,
348
+ name: answers.providerName.trim(),
349
+ baseUrl: answers.baseUrl.trim(),
350
+ wireApi: answers.wireApi,
351
+ tempEnvKey: `${providerId.toUpperCase().replace(/-/g, "_")}_API_KEY`,
352
+ requiresOpenaiAuth: provider.requiresOpenaiAuth ?? true,
353
+ model: model.trim()
354
+ };
355
+ const result = await addProviderToExisting(copiedProvider, answers.apiKey.trim(), false);
356
+ if (result.success) {
357
+ console.log(ansis.green(i18n.t("codex:providerCopied", { name: result.addedProvider?.name })));
358
+ if (result.backupPath) {
359
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
360
+ }
361
+ const setAsDefault = await promptBoolean({
362
+ message: i18n.t("multi-config:setAsDefaultPrompt"),
363
+ defaultValue: false
364
+ });
365
+ if (setAsDefault) {
366
+ const { switchToProvider } = await import('./simple-config.mjs').then(function (n) { return n.da; });
367
+ const switched = await switchToProvider(copiedProvider.id);
368
+ if (switched) {
369
+ console.log(ansis.green(i18n.t("multi-config:profileSetAsDefault", { name: copiedProvider.name })));
370
+ }
371
+ }
372
+ } else {
373
+ console.log(ansis.red(i18n.t("codex:providerCopyFailed", { error: result.error })));
374
+ }
375
+ }
376
+ async function handleDeleteProvider(providers) {
377
+ const choices = providers.map((provider) => ({
378
+ name: `${provider.name} (${provider.baseUrl})`,
379
+ value: provider.id
380
+ }));
381
+ const { selectedProviderIds } = await inquirer.prompt({
382
+ type: "checkbox",
383
+ name: "selectedProviderIds",
384
+ message: i18n.t("codex:selectProvidersToDelete"),
385
+ choices,
386
+ validate: (input) => {
387
+ const selected = input;
388
+ if (!selected || selected.length === 0) {
389
+ return i18n.t("codex:selectAtLeastOne");
390
+ }
391
+ if (selected.length === providers.length) {
392
+ return i18n.t("codex:cannotDeleteAll");
393
+ }
394
+ return true;
395
+ }
396
+ });
397
+ if (!selectedProviderIds || selectedProviderIds.length === 0) {
398
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
399
+ return;
400
+ }
401
+ const selectedNames = selectedProviderIds.map(
402
+ (id) => providers.find((p) => p.id === id)?.name || id
403
+ ).join(", ");
404
+ const confirmDelete = await promptBoolean({
405
+ message: i18n.t("codex:confirmDeleteProviders", { providers: selectedNames }),
406
+ defaultValue: false
407
+ });
408
+ if (!confirmDelete) {
409
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
410
+ return;
411
+ }
412
+ const result = await deleteProviders(selectedProviderIds);
413
+ if (result.success) {
414
+ console.log(ansis.green(i18n.t("codex:providersDeleted", { count: selectedProviderIds.length })));
415
+ if (result.newDefaultProvider) {
416
+ console.log(ansis.cyan(i18n.t("codex:newDefaultProvider", { provider: result.newDefaultProvider })));
417
+ }
418
+ if (result.backupPath) {
419
+ console.log(ansis.gray(i18n.t("common:backupCreated", { path: result.backupPath })));
420
+ }
421
+ } else {
422
+ console.log(ansis.red(i18n.t("codex:providersDeleteFailed", { error: result.error })));
423
+ }
424
+ }
425
+ const codexConfigSwitch = { configureIncrementalManagement };
426
+
427
+ export { configureIncrementalManagement, codexConfigSwitch as default };
@@ -0,0 +1,232 @@
1
+ import { co as ensureI18nInitialized, aM as readCodexConfig, cj as i18n, at as backupCodexComplete, aY as writeCodexConfig, aX as writeAuthFile } from './simple-config.mjs';
2
+ import 'node:fs';
3
+ import 'node:process';
4
+ import 'ansis';
5
+ import 'inquirer';
6
+ import 'pathe';
7
+ import 'smol-toml';
8
+ import 'dayjs';
9
+ import 'node:child_process';
10
+ import 'node:os';
11
+ import 'node:util';
12
+ import 'node:url';
13
+ import 'inquirer-toggle';
14
+ import 'ora';
15
+ import 'tinyexec';
16
+ import 'semver';
17
+ import 'node:fs/promises';
18
+ import 'fs-extra';
19
+ import 'trash';
20
+ import 'i18next';
21
+ import 'i18next-fs-backend';
22
+
23
+ async function addProviderToExisting(provider, apiKey, allowOverwrite = false) {
24
+ ensureI18nInitialized();
25
+ try {
26
+ const existingConfig = readCodexConfig();
27
+ const existingProviderIndex = existingConfig?.providers.findIndex((p) => p.id === provider.id) ?? -1;
28
+ if (existingProviderIndex !== -1 && !allowOverwrite) {
29
+ return {
30
+ success: false,
31
+ error: i18n.t("codex:providerManager.providerExists", { id: provider.id })
32
+ };
33
+ }
34
+ let updatedConfig;
35
+ if (!existingConfig) {
36
+ updatedConfig = {
37
+ model: provider.model || null,
38
+ modelProvider: provider.id,
39
+ providers: [provider],
40
+ mcpServices: [],
41
+ managed: true,
42
+ otherConfig: []
43
+ };
44
+ } else if (existingProviderIndex !== -1) {
45
+ const updatedProviders = [...existingConfig.providers];
46
+ updatedProviders[existingProviderIndex] = provider;
47
+ updatedConfig = {
48
+ ...existingConfig,
49
+ providers: updatedProviders,
50
+ modelProvider: existingConfig.modelProvider || provider.id
51
+ };
52
+ } else {
53
+ updatedConfig = {
54
+ ...existingConfig,
55
+ providers: [...existingConfig.providers, provider],
56
+ modelProvider: existingConfig.modelProvider || provider.id
57
+ };
58
+ }
59
+ let backupPath;
60
+ if (existingConfig) {
61
+ const backup = backupCodexComplete();
62
+ if (!backup) {
63
+ return {
64
+ success: false,
65
+ error: i18n.t("codex:providerManager.backupFailed")
66
+ };
67
+ }
68
+ backupPath = backup || void 0;
69
+ }
70
+ writeCodexConfig(updatedConfig);
71
+ const authEntries = {};
72
+ authEntries[provider.tempEnvKey] = apiKey;
73
+ writeAuthFile(authEntries);
74
+ return {
75
+ success: true,
76
+ backupPath,
77
+ addedProvider: provider
78
+ };
79
+ } catch (error) {
80
+ return {
81
+ success: false,
82
+ error: error instanceof Error ? error.message : i18n.t("codex:providerManager.unknownError")
83
+ };
84
+ }
85
+ }
86
+ async function editExistingProvider(providerId, updates) {
87
+ ensureI18nInitialized();
88
+ try {
89
+ const existingConfig = readCodexConfig();
90
+ if (!existingConfig) {
91
+ return {
92
+ success: false,
93
+ error: i18n.t("codex:providerManager.noConfig")
94
+ };
95
+ }
96
+ const providerIndex = existingConfig.providers.findIndex((p) => p.id === providerId);
97
+ if (providerIndex === -1) {
98
+ return {
99
+ success: false,
100
+ error: i18n.t("codex:providerManager.providerNotFound", { id: providerId })
101
+ };
102
+ }
103
+ const backupPath = backupCodexComplete();
104
+ if (!backupPath) {
105
+ return {
106
+ success: false,
107
+ error: i18n.t("codex:providerManager.backupFailed")
108
+ };
109
+ }
110
+ const updatedProvider = {
111
+ ...existingConfig.providers[providerIndex],
112
+ ...updates.name && { name: updates.name },
113
+ ...updates.baseUrl && { baseUrl: updates.baseUrl },
114
+ ...updates.wireApi && { wireApi: updates.wireApi },
115
+ ...updates.model && { model: updates.model }
116
+ };
117
+ const updatedProviders = [...existingConfig.providers];
118
+ updatedProviders[providerIndex] = updatedProvider;
119
+ const updatedConfig = {
120
+ ...existingConfig,
121
+ providers: updatedProviders
122
+ };
123
+ writeCodexConfig(updatedConfig);
124
+ if (updates.apiKey) {
125
+ const authEntries = {};
126
+ authEntries[updatedProvider.tempEnvKey] = updates.apiKey;
127
+ writeAuthFile(authEntries);
128
+ }
129
+ return {
130
+ success: true,
131
+ backupPath,
132
+ updatedProvider
133
+ };
134
+ } catch (error) {
135
+ return {
136
+ success: false,
137
+ error: error instanceof Error ? error.message : i18n.t("codex:providerManager.unknownError")
138
+ };
139
+ }
140
+ }
141
+ async function deleteProviders(providerIds) {
142
+ ensureI18nInitialized();
143
+ try {
144
+ const existingConfig = readCodexConfig();
145
+ if (!existingConfig) {
146
+ return {
147
+ success: false,
148
+ error: i18n.t("codex:providerManager.noConfig")
149
+ };
150
+ }
151
+ if (!providerIds || providerIds.length === 0) {
152
+ return {
153
+ success: false,
154
+ error: i18n.t("codex:providerManager.noProvidersSpecified")
155
+ };
156
+ }
157
+ const notFoundProviders = providerIds.filter(
158
+ (id) => !existingConfig.providers.some((p) => p.id === id)
159
+ );
160
+ if (notFoundProviders.length > 0) {
161
+ return {
162
+ success: false,
163
+ error: i18n.t("codex:providerManager.providersNotFound", {
164
+ providers: notFoundProviders.join(", ")
165
+ })
166
+ };
167
+ }
168
+ const remainingProviders = existingConfig.providers.filter(
169
+ (p) => !providerIds.includes(p.id)
170
+ );
171
+ if (remainingProviders.length === 0) {
172
+ return {
173
+ success: false,
174
+ error: i18n.t("codex:providerManager.cannotDeleteAll")
175
+ };
176
+ }
177
+ const backupPath = backupCodexComplete();
178
+ if (!backupPath) {
179
+ return {
180
+ success: false,
181
+ error: i18n.t("codex:providerManager.backupFailed")
182
+ };
183
+ }
184
+ let newDefaultProvider = existingConfig.modelProvider;
185
+ if (providerIds.includes(existingConfig.modelProvider || "")) {
186
+ newDefaultProvider = remainingProviders[0].id;
187
+ }
188
+ const updatedConfig = {
189
+ ...existingConfig,
190
+ modelProvider: newDefaultProvider,
191
+ providers: remainingProviders
192
+ };
193
+ writeCodexConfig(updatedConfig);
194
+ const result = {
195
+ success: true,
196
+ backupPath,
197
+ deletedProviders: providerIds,
198
+ remainingProviders
199
+ };
200
+ if (newDefaultProvider !== existingConfig.modelProvider) {
201
+ result.newDefaultProvider = newDefaultProvider || void 0;
202
+ }
203
+ return result;
204
+ } catch (error) {
205
+ return {
206
+ success: false,
207
+ error: error instanceof Error ? error.message : i18n.t("codex:providerManager.unknownError")
208
+ };
209
+ }
210
+ }
211
+ function validateProviderData(provider) {
212
+ ensureI18nInitialized();
213
+ const errors = [];
214
+ if (!provider.id || typeof provider.id !== "string" || provider.id.trim() === "") {
215
+ errors.push(i18n.t("codex:providerManager.providerIdRequired"));
216
+ }
217
+ if (!provider.name || typeof provider.name !== "string" || provider.name.trim() === "") {
218
+ errors.push(i18n.t("codex:providerManager.providerNameRequired"));
219
+ }
220
+ if (!provider.baseUrl || typeof provider.baseUrl !== "string" || provider.baseUrl.trim() === "") {
221
+ errors.push(i18n.t("codex:providerManager.baseUrlRequired"));
222
+ }
223
+ if (provider.wireApi && !["responses", "chat"].includes(provider.wireApi)) {
224
+ errors.push(i18n.t("codex:providerManager.wireApiInvalid"));
225
+ }
226
+ return {
227
+ valid: errors.length === 0,
228
+ errors
229
+ };
230
+ }
231
+
232
+ export { addProviderToExisting, deleteProviders, editExistingProvider, validateProviderData };