ccjk 13.6.7 → 14.0.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 (38) hide show
  1. package/dist/chunks/api-cli.mjs +4 -2
  2. package/dist/chunks/api-config-selector.mjs +2 -4
  3. package/dist/chunks/auto-fix.mjs +3 -1
  4. package/dist/chunks/ccjk-all.mjs +5 -2
  5. package/dist/chunks/ccjk-mcp.mjs +5 -2
  6. package/dist/chunks/ccjk-setup.mjs +4 -1
  7. package/dist/chunks/ccr.mjs +3 -5
  8. package/dist/chunks/check-updates.mjs +0 -1
  9. package/dist/chunks/claude-code-incremental-manager.mjs +4 -6
  10. package/dist/chunks/codex-config-switch.mjs +0 -1
  11. package/dist/chunks/codex-provider-manager.mjs +0 -1
  12. package/dist/chunks/codex.mjs +2 -2
  13. package/dist/chunks/config-switch.mjs +2 -4
  14. package/dist/chunks/config.mjs +1104 -5
  15. package/dist/chunks/config2.mjs +6 -4
  16. package/dist/chunks/config3.mjs +4 -2
  17. package/dist/chunks/doctor.mjs +1 -1
  18. package/dist/chunks/evolution.mjs +47 -27
  19. package/dist/chunks/features.mjs +2 -3
  20. package/dist/chunks/index10.mjs +64 -10
  21. package/dist/chunks/init.mjs +6 -7
  22. package/dist/chunks/installer.mjs +2 -2
  23. package/dist/chunks/mcp-cli.mjs +18 -19
  24. package/dist/chunks/mcp.mjs +6 -7
  25. package/dist/chunks/package.mjs +1 -1
  26. package/dist/chunks/platform.mjs +1 -1
  27. package/dist/chunks/quick-setup.mjs +1 -2
  28. package/dist/chunks/slash-commands.mjs +1 -1
  29. package/dist/chunks/update.mjs +4 -5
  30. package/dist/i18n/locales/en/menu.json +7 -0
  31. package/dist/i18n/locales/zh-CN/menu.json +7 -0
  32. package/dist/index.mjs +3 -2
  33. package/dist/shared/{ccjk.DHaUdzX3.mjs → ccjk.B6VCKdyy.mjs} +2 -2
  34. package/dist/shared/{ccjk.B4aXNclK.mjs → ccjk.CVjfbEIj.mjs} +1 -1
  35. package/dist/shared/{ccjk.Dz0ssUQx.mjs → ccjk.Dh6Be-ef.mjs} +1 -1
  36. package/package.json +1 -1
  37. package/dist/chunks/claude-code-config-manager.mjs +0 -811
  38. package/dist/chunks/claude-config.mjs +0 -286
@@ -1,811 +0,0 @@
1
- import { d as dayjs } from '../shared/ccjk.RyizuzOI.mjs';
2
- import { ZCF_CONFIG_FILE, ZCF_CONFIG_DIR, SETTINGS_FILE } from './constants.mjs';
3
- import { readDefaultTomlConfig, createDefaultTomlConfig, writeTomlConfig } from './ccjk-config.mjs';
4
- import { o as overwriteModelSettings } from './config.mjs';
5
- import { ensureDir, exists, copyFile } from './fs-operations.mjs';
6
- import { readJsonConfig } from './json-config.mjs';
7
- import { j as join } from '../shared/ccjk.bQ7Dh1g4.mjs';
8
- import '../shared/ccjk.BAGoDD49.mjs';
9
- import 'node:os';
10
- import './index2.mjs';
11
- import 'node:fs';
12
- import 'node:process';
13
- import 'node:url';
14
- import '../shared/ccjk.BBtCGd_g.mjs';
15
- import './index3.mjs';
16
- import 'node:crypto';
17
- import 'node:fs/promises';
18
- import './index5.mjs';
19
- import './index6.mjs';
20
- import 'node:readline';
21
- import 'stream';
22
- import 'node:tty';
23
- import 'node:async_hooks';
24
- import '../shared/ccjk.Cjgrln_h.mjs';
25
- import 'node:util';
26
- import 'tty';
27
- import 'fs';
28
- import 'child_process';
29
- import 'node:path';
30
- import 'buffer';
31
- import 'string_decoder';
32
- import './claude-config.mjs';
33
- import './platform.mjs';
34
- import './main.mjs';
35
- import 'module';
36
- import 'node:child_process';
37
- import 'node:stream';
38
- import '../shared/ccjk.DScm_NnL.mjs';
39
-
40
- class ClaudeCodeConfigManager {
41
- static CONFIG_FILE = ZCF_CONFIG_FILE;
42
- static LEGACY_CONFIG_FILE = join(ZCF_CONFIG_DIR, "claude-code-configs.json");
43
- /**
44
- * Ensure configuration directory exists
45
- */
46
- static ensureConfigDir() {
47
- ensureDir(ZCF_CONFIG_DIR);
48
- }
49
- /**
50
- * Read TOML configuration
51
- */
52
- static readTomlConfig() {
53
- return readDefaultTomlConfig();
54
- }
55
- /**
56
- * Load TOML configuration, falling back to default when missing
57
- */
58
- static loadTomlConfig() {
59
- const existingConfig = this.readTomlConfig();
60
- if (existingConfig) {
61
- return existingConfig;
62
- }
63
- return createDefaultTomlConfig();
64
- }
65
- /**
66
- * Migrate legacy JSON-based configuration into TOML storage
67
- */
68
- static migrateFromLegacyConfig() {
69
- if (!exists(this.LEGACY_CONFIG_FILE)) {
70
- return null;
71
- }
72
- try {
73
- const legacyConfig = readJsonConfig(this.LEGACY_CONFIG_FILE);
74
- if (!legacyConfig) {
75
- return null;
76
- }
77
- const normalizedProfiles = {};
78
- const existingKeys = /* @__PURE__ */ new Set();
79
- let migratedCurrentKey = "";
80
- Object.entries(legacyConfig.profiles || {}).forEach(([legacyKey, profile]) => {
81
- const sourceProfile = profile;
82
- const name = sourceProfile.name?.trim() || legacyKey;
83
- const baseKey = this.generateProfileId(name);
84
- let uniqueKey = baseKey || legacyKey;
85
- let suffix = 2;
86
- while (existingKeys.has(uniqueKey)) {
87
- uniqueKey = `${baseKey || legacyKey}-${suffix++}`;
88
- }
89
- existingKeys.add(uniqueKey);
90
- const sanitizedProfile = this.sanitizeProfile({
91
- ...sourceProfile,
92
- name
93
- });
94
- normalizedProfiles[uniqueKey] = {
95
- ...sanitizedProfile,
96
- id: uniqueKey
97
- };
98
- if (legacyConfig.currentProfileId === legacyKey || legacyConfig.currentProfileId === sourceProfile.id) {
99
- migratedCurrentKey = uniqueKey;
100
- }
101
- });
102
- if (!migratedCurrentKey && legacyConfig.currentProfileId) {
103
- const fallbackKey = this.generateProfileId(legacyConfig.currentProfileId);
104
- if (existingKeys.has(fallbackKey)) {
105
- migratedCurrentKey = fallbackKey;
106
- }
107
- }
108
- if (!migratedCurrentKey && existingKeys.size > 0) {
109
- migratedCurrentKey = Array.from(existingKeys)[0];
110
- }
111
- const migratedConfig = {
112
- currentProfileId: migratedCurrentKey,
113
- profiles: normalizedProfiles
114
- };
115
- this.writeConfig(migratedConfig);
116
- return migratedConfig;
117
- } catch (error) {
118
- console.error("Failed to migrate legacy Claude Code config:", error);
119
- return null;
120
- }
121
- }
122
- /**
123
- * Read configuration
124
- */
125
- static readConfig() {
126
- try {
127
- const tomlConfig = readDefaultTomlConfig();
128
- if (!tomlConfig || !tomlConfig.claudeCode) {
129
- return this.migrateFromLegacyConfig();
130
- }
131
- const { claudeCode } = tomlConfig;
132
- const rawProfiles = claudeCode.profiles || {};
133
- const sanitizedProfiles = Object.fromEntries(
134
- Object.entries(rawProfiles).map(([key, profile]) => {
135
- const storedProfile = this.sanitizeProfile({
136
- ...profile,
137
- name: profile.name || key
138
- });
139
- return [key, { ...storedProfile, id: key }];
140
- })
141
- );
142
- const configData = {
143
- currentProfileId: claudeCode.currentProfile || "",
144
- profiles: sanitizedProfiles
145
- };
146
- if (Object.keys(configData.profiles).length === 0) {
147
- const migrated = this.migrateFromLegacyConfig();
148
- if (migrated) {
149
- return migrated;
150
- }
151
- }
152
- return configData;
153
- } catch (error) {
154
- console.error("Failed to read Claude Code config:", error);
155
- return null;
156
- }
157
- }
158
- /**
159
- * Write configuration
160
- */
161
- static writeConfig(config) {
162
- try {
163
- this.ensureConfigDir();
164
- const keyMap = /* @__PURE__ */ new Map();
165
- const sanitizedProfiles = Object.fromEntries(
166
- Object.entries(config.profiles).map(([key, profile]) => {
167
- const normalizedName = profile.name?.trim() || key;
168
- const profileKey = this.generateProfileId(normalizedName);
169
- keyMap.set(key, profileKey);
170
- const sanitizedProfile = this.sanitizeProfile({
171
- ...profile,
172
- name: normalizedName
173
- });
174
- return [profileKey, sanitizedProfile];
175
- })
176
- );
177
- const tomlConfig = this.loadTomlConfig();
178
- const nextTomlConfig = {
179
- ...tomlConfig,
180
- claudeCode: {
181
- ...tomlConfig.claudeCode,
182
- currentProfile: keyMap.get(config.currentProfileId) || config.currentProfileId,
183
- profiles: sanitizedProfiles
184
- }
185
- };
186
- writeTomlConfig(this.CONFIG_FILE, nextTomlConfig);
187
- } catch (error) {
188
- console.error("Failed to write Claude Code config:", error);
189
- throw new Error(`Failed to write config: ${error instanceof Error ? error.message : String(error)}`);
190
- }
191
- }
192
- /**
193
- * Create empty configuration
194
- */
195
- static createEmptyConfig() {
196
- return {
197
- currentProfileId: "",
198
- profiles: {}
199
- };
200
- }
201
- static settingsMatchProfile(settings, profile) {
202
- const env = settings?.env || {};
203
- if (!profile) {
204
- return !settings?.model && !env.ANTHROPIC_MODEL && !env.ANTHROPIC_DEFAULT_HAIKU_MODEL && !env.ANTHROPIC_DEFAULT_SONNET_MODEL && !env.ANTHROPIC_DEFAULT_OPUS_MODEL;
205
- }
206
- const expectedPrimary = profile.primaryModel?.trim();
207
- const expectedHaiku = profile.defaultHaikuModel?.trim();
208
- const expectedSonnet = profile.defaultSonnetModel?.trim();
209
- const expectedOpus = profile.defaultOpusModel?.trim();
210
- const hasExplicitModelConfig = Boolean(expectedPrimary || expectedHaiku || expectedSonnet || expectedOpus);
211
- if (!hasExplicitModelConfig) {
212
- return !settings?.model && (env.ANTHROPIC_MODEL === "" || env.ANTHROPIC_MODEL === void 0) && env.ANTHROPIC_DEFAULT_HAIKU_MODEL === void 0 && env.ANTHROPIC_DEFAULT_SONNET_MODEL === void 0 && env.ANTHROPIC_DEFAULT_OPUS_MODEL === void 0;
213
- }
214
- const hasAdaptiveRouting = Boolean(expectedHaiku || expectedSonnet || expectedOpus);
215
- if (hasAdaptiveRouting) {
216
- return !settings?.model && env.ANTHROPIC_MODEL === void 0 && env.ANTHROPIC_DEFAULT_HAIKU_MODEL === expectedHaiku && env.ANTHROPIC_SMALL_FAST_MODEL === expectedHaiku && env.ANTHROPIC_DEFAULT_SONNET_MODEL === expectedSonnet && env.ANTHROPIC_DEFAULT_OPUS_MODEL === expectedOpus;
217
- }
218
- return settings?.model === expectedPrimary && env.ANTHROPIC_MODEL === void 0 && env.ANTHROPIC_DEFAULT_HAIKU_MODEL === expectedHaiku && env.ANTHROPIC_SMALL_FAST_MODEL === expectedHaiku && env.ANTHROPIC_DEFAULT_SONNET_MODEL === expectedSonnet && env.ANTHROPIC_DEFAULT_OPUS_MODEL === expectedOpus;
219
- }
220
- static async syncCurrentProfileToSettings() {
221
- const currentProfile = this.getCurrentProfile();
222
- await this.applyProfileSettings(currentProfile);
223
- }
224
- /**
225
- * Apply profile settings to Claude Code runtime
226
- */
227
- static async applyProfileSettings(profile) {
228
- const { ensureI18nInitialized, i18n } = await import('./index2.mjs');
229
- ensureI18nInitialized();
230
- try {
231
- if (!profile) {
232
- const { switchToOfficialLogin } = await import('./config.mjs').then(function (n) { return n.j; });
233
- switchToOfficialLogin();
234
- return;
235
- }
236
- const { readJsonConfig: readJsonConfig2, writeJsonConfig } = await import('./json-config.mjs');
237
- const settings = readJsonConfig2(SETTINGS_FILE) || {};
238
- if (!settings.env)
239
- settings.env = {};
240
- let shouldRestartCcr = false;
241
- if (profile.authType === "api_key") {
242
- settings.env.ANTHROPIC_API_KEY = profile.apiKey;
243
- delete settings.env.ANTHROPIC_AUTH_TOKEN;
244
- } else if (profile.authType === "auth_token") {
245
- settings.env.ANTHROPIC_AUTH_TOKEN = profile.apiKey;
246
- delete settings.env.ANTHROPIC_API_KEY;
247
- } else if (profile.authType === "ccr_proxy") {
248
- const { readCcrConfig } = await import('./config2.mjs');
249
- const ccrConfig = readCcrConfig();
250
- if (!ccrConfig) {
251
- throw new Error(i18n.t("ccr:ccrNotConfigured") || "CCR proxy configuration not found");
252
- }
253
- const host = ccrConfig.HOST || "127.0.0.1";
254
- const port = ccrConfig.PORT || 3456;
255
- const apiKey = ccrConfig.APIKEY || "sk-ccjk-x-ccr";
256
- settings.env.ANTHROPIC_BASE_URL = `http://${host}:${port}`;
257
- settings.env.ANTHROPIC_API_KEY = apiKey;
258
- delete settings.env.ANTHROPIC_AUTH_TOKEN;
259
- shouldRestartCcr = true;
260
- }
261
- if (profile.authType !== "ccr_proxy") {
262
- if (profile.baseUrl)
263
- settings.env.ANTHROPIC_BASE_URL = profile.baseUrl;
264
- else
265
- delete settings.env.ANTHROPIC_BASE_URL;
266
- }
267
- const hasModelConfig = Boolean(
268
- profile.primaryModel || profile.defaultHaikuModel || profile.defaultSonnetModel || profile.defaultOpusModel
269
- );
270
- const modelMode = hasModelConfig ? "override" : "reset";
271
- overwriteModelSettings(settings, {
272
- primaryModel: profile.primaryModel,
273
- haikuModel: profile.defaultHaikuModel,
274
- sonnetModel: profile.defaultSonnetModel,
275
- opusModel: profile.defaultOpusModel
276
- }, modelMode);
277
- writeJsonConfig(SETTINGS_FILE, settings);
278
- const { setPrimaryApiKey, addCompletedOnboarding } = await import('./claude-config.mjs').then(function (n) { return n.l; });
279
- setPrimaryApiKey();
280
- addCompletedOnboarding();
281
- let verifiedSettings = readJsonConfig2(SETTINGS_FILE) || {};
282
- if (!this.settingsMatchProfile(verifiedSettings, profile)) {
283
- const repairedSettings = readJsonConfig2(SETTINGS_FILE) || {};
284
- repairedSettings.env = repairedSettings.env || {};
285
- if (profile?.authType === "api_key") {
286
- repairedSettings.env.ANTHROPIC_API_KEY = profile.apiKey;
287
- delete repairedSettings.env.ANTHROPIC_AUTH_TOKEN;
288
- } else if (profile?.authType === "auth_token") {
289
- repairedSettings.env.ANTHROPIC_AUTH_TOKEN = profile.apiKey;
290
- delete repairedSettings.env.ANTHROPIC_API_KEY;
291
- }
292
- if (profile?.authType !== "ccr_proxy") {
293
- if (profile?.baseUrl)
294
- repairedSettings.env.ANTHROPIC_BASE_URL = profile.baseUrl;
295
- else
296
- delete repairedSettings.env.ANTHROPIC_BASE_URL;
297
- }
298
- overwriteModelSettings(repairedSettings, {
299
- primaryModel: profile?.primaryModel,
300
- haikuModel: profile?.defaultHaikuModel,
301
- sonnetModel: profile?.defaultSonnetModel,
302
- opusModel: profile?.defaultOpusModel
303
- }, profile ? modelMode : "reset");
304
- writeJsonConfig(SETTINGS_FILE, repairedSettings);
305
- verifiedSettings = readJsonConfig2(SETTINGS_FILE) || {};
306
- }
307
- if (!this.settingsMatchProfile(verifiedSettings, profile)) {
308
- throw new Error("settings.json verification failed after applying current profile");
309
- }
310
- if (shouldRestartCcr) {
311
- const { runCcrRestart } = await import('./commands.mjs');
312
- await runCcrRestart();
313
- }
314
- } catch (error) {
315
- const reason = error instanceof Error ? error.message : String(error);
316
- throw new Error(`${i18n.t("multi-config:failedToApplySettings")}: ${reason}`);
317
- }
318
- }
319
- static async applyCurrentProfile() {
320
- await this.syncCurrentProfileToSettings();
321
- }
322
- /**
323
- * Remove unsupported fields from profile payload
324
- */
325
- static sanitizeProfile(profile) {
326
- const sanitized = {
327
- name: profile.name,
328
- authType: profile.authType
329
- };
330
- if (profile.provider)
331
- sanitized.provider = profile.provider;
332
- if (profile.apiKey)
333
- sanitized.apiKey = profile.apiKey;
334
- if (profile.baseUrl)
335
- sanitized.baseUrl = profile.baseUrl;
336
- if (profile.primaryModel)
337
- sanitized.primaryModel = profile.primaryModel;
338
- if (profile.defaultHaikuModel)
339
- sanitized.defaultHaikuModel = profile.defaultHaikuModel;
340
- if (profile.defaultSonnetModel)
341
- sanitized.defaultSonnetModel = profile.defaultSonnetModel;
342
- if (profile.defaultOpusModel)
343
- sanitized.defaultOpusModel = profile.defaultOpusModel;
344
- return sanitized;
345
- }
346
- /**
347
- * Backup configuration
348
- */
349
- static backupConfig() {
350
- try {
351
- if (!exists(this.CONFIG_FILE)) {
352
- return null;
353
- }
354
- const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
355
- const backupPath = join(ZCF_CONFIG_DIR, `config.backup.${timestamp}.toml`);
356
- copyFile(this.CONFIG_FILE, backupPath);
357
- return backupPath;
358
- } catch (error) {
359
- console.error("Failed to backup Claude Code config:", error);
360
- return null;
361
- }
362
- }
363
- /**
364
- * Add configuration
365
- */
366
- static async addProfile(profile) {
367
- try {
368
- const validationErrors = this.validateProfile(profile);
369
- if (validationErrors.length > 0) {
370
- return {
371
- success: false,
372
- error: `Validation failed: ${validationErrors.join(", ")}`
373
- };
374
- }
375
- const backupPath = this.backupConfig();
376
- let config = this.readConfig();
377
- if (!config) {
378
- config = this.createEmptyConfig();
379
- }
380
- if (profile.id && config.profiles[profile.id]) {
381
- return {
382
- success: false,
383
- error: `Profile with ID "${profile.id}" already exists`,
384
- backupPath: backupPath || void 0
385
- };
386
- }
387
- const normalizedName = profile.name.trim();
388
- const profileKey = this.generateProfileId(normalizedName);
389
- const existingNames = Object.values(config.profiles).map((p) => p.name || "");
390
- if (config.profiles[profileKey] || existingNames.some((name) => name.toLowerCase() === normalizedName.toLowerCase())) {
391
- return {
392
- success: false,
393
- error: `Profile with name "${profile.name}" already exists`,
394
- backupPath: backupPath || void 0
395
- };
396
- }
397
- const sanitizedProfile = this.sanitizeProfile({
398
- ...profile,
399
- name: normalizedName
400
- });
401
- const runtimeProfile = {
402
- ...sanitizedProfile,
403
- id: profileKey
404
- };
405
- config.profiles[profileKey] = runtimeProfile;
406
- if (!config.currentProfileId) {
407
- config.currentProfileId = profileKey;
408
- }
409
- this.writeConfig(config);
410
- if (config.currentProfileId === profileKey) {
411
- await this.syncCurrentProfileToSettings();
412
- }
413
- return {
414
- success: true,
415
- backupPath: backupPath || void 0,
416
- addedProfile: runtimeProfile
417
- };
418
- } catch (error) {
419
- return {
420
- success: false,
421
- error: error instanceof Error ? error.message : String(error)
422
- };
423
- }
424
- }
425
- /**
426
- * Update configuration
427
- */
428
- static async updateProfile(id, data) {
429
- try {
430
- const validationErrors = this.validateProfile(data, true);
431
- if (validationErrors.length > 0) {
432
- return {
433
- success: false,
434
- error: `Validation failed: ${validationErrors.join(", ")}`
435
- };
436
- }
437
- const backupPath = this.backupConfig();
438
- const config = this.readConfig();
439
- if (!config || !config.profiles[id]) {
440
- return {
441
- success: false,
442
- error: `Profile with ID "${id}" not found`,
443
- backupPath: backupPath || void 0
444
- };
445
- }
446
- const existingProfile = config.profiles[id];
447
- const nextName = data.name !== void 0 ? data.name.trim() : existingProfile.name;
448
- const nextKey = this.generateProfileId(nextName);
449
- const nameChanged = nextKey !== id;
450
- if (nameChanged) {
451
- const duplicateName = Object.entries(config.profiles).some(([key, profile]) => key !== id && (profile.name || "").toLowerCase() === nextName.toLowerCase());
452
- if (duplicateName || config.profiles[nextKey]) {
453
- return {
454
- success: false,
455
- error: `Profile with name "${data.name}" already exists`,
456
- backupPath: backupPath || void 0
457
- };
458
- }
459
- }
460
- const mergedProfile = this.sanitizeProfile({
461
- ...existingProfile,
462
- ...data,
463
- name: nextName
464
- });
465
- if (nameChanged) {
466
- delete config.profiles[id];
467
- config.profiles[nextKey] = {
468
- ...mergedProfile,
469
- id: nextKey
470
- };
471
- if (config.currentProfileId === id) {
472
- config.currentProfileId = nextKey;
473
- }
474
- } else {
475
- config.profiles[id] = {
476
- ...mergedProfile,
477
- id
478
- };
479
- }
480
- this.writeConfig(config);
481
- if (config.currentProfileId === (nameChanged ? nextKey : id)) {
482
- await this.syncCurrentProfileToSettings();
483
- }
484
- return {
485
- success: true,
486
- backupPath: backupPath || void 0,
487
- updatedProfile: {
488
- ...mergedProfile,
489
- id: nameChanged ? nextKey : id
490
- }
491
- };
492
- } catch (error) {
493
- return {
494
- success: false,
495
- error: error instanceof Error ? error.message : String(error)
496
- };
497
- }
498
- }
499
- /**
500
- * Delete configuration
501
- */
502
- static async deleteProfile(id) {
503
- try {
504
- const backupPath = this.backupConfig();
505
- const config = this.readConfig();
506
- if (!config || !config.profiles[id]) {
507
- return {
508
- success: false,
509
- error: `Profile with ID "${id}" not found`,
510
- backupPath: backupPath || void 0
511
- };
512
- }
513
- const profileCount = Object.keys(config.profiles).length;
514
- if (profileCount === 1) {
515
- return {
516
- success: false,
517
- error: "Cannot delete the last profile. At least one profile must remain.",
518
- backupPath: backupPath || void 0
519
- };
520
- }
521
- delete config.profiles[id];
522
- if (config.currentProfileId === id) {
523
- const remainingIds = Object.keys(config.profiles);
524
- config.currentProfileId = remainingIds[0];
525
- }
526
- this.writeConfig(config);
527
- if (config.currentProfileId) {
528
- await this.syncCurrentProfileToSettings();
529
- }
530
- return {
531
- success: true,
532
- backupPath: backupPath || void 0,
533
- remainingProfiles: Object.entries(config.profiles).map(([key, profile]) => ({
534
- ...profile,
535
- id: key
536
- }))
537
- };
538
- } catch (error) {
539
- return {
540
- success: false,
541
- error: error instanceof Error ? error.message : String(error)
542
- };
543
- }
544
- }
545
- /**
546
- * Delete multiple configurations
547
- */
548
- static async deleteProfiles(ids) {
549
- try {
550
- const backupPath = this.backupConfig();
551
- const config = this.readConfig();
552
- if (!config) {
553
- return {
554
- success: false,
555
- error: "No configuration found",
556
- backupPath: backupPath || void 0
557
- };
558
- }
559
- const missingIds = ids.filter((id) => !config.profiles[id]);
560
- if (missingIds.length > 0) {
561
- return {
562
- success: false,
563
- error: `Profiles not found: ${missingIds.join(", ")}`,
564
- backupPath: backupPath || void 0
565
- };
566
- }
567
- const remainingCount = Object.keys(config.profiles).length - ids.length;
568
- if (remainingCount === 0) {
569
- return {
570
- success: false,
571
- error: "Cannot delete all profiles. At least one profile must remain.",
572
- backupPath: backupPath || void 0
573
- };
574
- }
575
- let newCurrentProfileId;
576
- ids.forEach((id) => {
577
- delete config.profiles[id];
578
- });
579
- if (ids.includes(config.currentProfileId)) {
580
- const remainingIds = Object.keys(config.profiles);
581
- config.currentProfileId = remainingIds[0];
582
- newCurrentProfileId = config.currentProfileId;
583
- }
584
- this.writeConfig(config);
585
- if (config.currentProfileId) {
586
- await this.syncCurrentProfileToSettings();
587
- }
588
- return {
589
- success: true,
590
- backupPath: backupPath || void 0,
591
- newCurrentProfileId,
592
- deletedProfiles: ids,
593
- remainingProfiles: Object.entries(config.profiles).map(([key, profile]) => ({
594
- ...profile,
595
- id: key
596
- }))
597
- };
598
- } catch (error) {
599
- return {
600
- success: false,
601
- error: error instanceof Error ? error.message : String(error)
602
- };
603
- }
604
- }
605
- /**
606
- * Generate profile ID from name
607
- */
608
- static generateProfileId(name) {
609
- return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "profile";
610
- }
611
- /**
612
- * Switch configuration
613
- */
614
- static async switchProfile(id) {
615
- try {
616
- const config = this.readConfig();
617
- if (!config || !config.profiles[id]) {
618
- return {
619
- success: false,
620
- error: "Profile not found"
621
- };
622
- }
623
- if (config.currentProfileId === id) {
624
- return { success: true };
625
- }
626
- config.currentProfileId = id;
627
- this.writeConfig(config);
628
- await this.syncCurrentProfileToSettings();
629
- return { success: true };
630
- } catch (error) {
631
- return {
632
- success: false,
633
- error: error instanceof Error ? error.message : String(error)
634
- };
635
- }
636
- }
637
- /**
638
- * List all configurations
639
- */
640
- static listProfiles() {
641
- const config = this.readConfig();
642
- if (!config) {
643
- return [];
644
- }
645
- return Object.values(config.profiles);
646
- }
647
- /**
648
- * Get current configuration
649
- */
650
- static getCurrentProfile() {
651
- const config = this.readConfig();
652
- if (!config || !config.currentProfileId) {
653
- return null;
654
- }
655
- return config.profiles[config.currentProfileId] || null;
656
- }
657
- /**
658
- * Get configuration by ID
659
- */
660
- static getProfileById(id) {
661
- const config = this.readConfig();
662
- if (!config) {
663
- return null;
664
- }
665
- return config.profiles[id] || null;
666
- }
667
- /**
668
- * Get configuration by name
669
- */
670
- static getProfileByName(name) {
671
- const config = this.readConfig();
672
- if (!config) {
673
- return null;
674
- }
675
- return Object.values(config.profiles).find((p) => p.name === name) || null;
676
- }
677
- /**
678
- * Sync CCR configuration
679
- */
680
- static async syncCcrProfile() {
681
- try {
682
- const { readCcrConfig } = await import('./config2.mjs');
683
- const ccrConfig = readCcrConfig();
684
- if (!ccrConfig) {
685
- await this.ensureCcrProfileExists(ccrConfig);
686
- return;
687
- }
688
- await this.ensureCcrProfileExists(ccrConfig);
689
- } catch (error) {
690
- console.error("Failed to sync CCR profile:", error);
691
- }
692
- }
693
- /**
694
- * 确保CCR配置文件存在
695
- */
696
- static async ensureCcrProfileExists(ccrConfig) {
697
- const config = this.readConfig() || this.createEmptyConfig();
698
- const ccrProfileId = "ccr-proxy";
699
- const existingCcrProfile = config.profiles[ccrProfileId];
700
- if (!ccrConfig) {
701
- if (existingCcrProfile) {
702
- delete config.profiles[ccrProfileId];
703
- if (config.currentProfileId === ccrProfileId) {
704
- const remainingIds = Object.keys(config.profiles);
705
- config.currentProfileId = remainingIds[0] || "";
706
- }
707
- this.writeConfig(config);
708
- }
709
- return;
710
- }
711
- const host = ccrConfig.HOST || "127.0.0.1";
712
- const port = ccrConfig.PORT || 3456;
713
- const apiKey = ccrConfig.APIKEY || "sk-ccjk-x-ccr";
714
- const baseUrl = `http://${host}:${port}`;
715
- const ccrProfile = {
716
- name: "CCR Proxy",
717
- authType: "ccr_proxy",
718
- baseUrl,
719
- apiKey
720
- };
721
- config.profiles[ccrProfileId] = {
722
- ...ccrProfile,
723
- id: ccrProfileId
724
- };
725
- if (!config.currentProfileId) {
726
- config.currentProfileId = ccrProfileId;
727
- }
728
- this.writeConfig(config);
729
- }
730
- /**
731
- * Switch to official login
732
- */
733
- static async switchToOfficial() {
734
- try {
735
- const config = this.readConfig();
736
- if (!config) {
737
- return { success: true };
738
- }
739
- config.currentProfileId = "";
740
- this.writeConfig(config);
741
- await this.applyProfileSettings(null);
742
- return { success: true };
743
- } catch (error) {
744
- return {
745
- success: false,
746
- error: error instanceof Error ? error.message : String(error)
747
- };
748
- }
749
- }
750
- /**
751
- * Switch to CCR proxy
752
- */
753
- static async switchToCcr() {
754
- try {
755
- await this.syncCcrProfile();
756
- const config = this.readConfig();
757
- if (!config || !config.profiles["ccr-proxy"]) {
758
- return {
759
- success: false,
760
- error: "CCR proxy configuration not found. Please configure CCR first."
761
- };
762
- }
763
- return await this.switchProfile("ccr-proxy");
764
- } catch (error) {
765
- return {
766
- success: false,
767
- error: error instanceof Error ? error.message : String(error)
768
- };
769
- }
770
- }
771
- /**
772
- * Validate configuration
773
- */
774
- static validateProfile(profile, isUpdate = false) {
775
- const errors = [];
776
- if (!isUpdate && (!profile.name || typeof profile.name !== "string" || profile.name.trim() === "")) {
777
- errors.push("Profile name is required");
778
- }
779
- if (profile.name && typeof profile.name !== "string") {
780
- errors.push("Profile name must be a string");
781
- }
782
- if (profile.authType && !["api_key", "auth_token", "ccr_proxy"].includes(profile.authType)) {
783
- errors.push("Invalid auth type. Must be one of: api_key, auth_token, ccr_proxy");
784
- }
785
- if (profile.authType === "api_key" || profile.authType === "auth_token") {
786
- if (!profile.apiKey || typeof profile.apiKey !== "string" || profile.apiKey.trim() === "") {
787
- errors.push("API key is required for api_key and auth_token types");
788
- }
789
- }
790
- if (profile.baseUrl) {
791
- try {
792
- new URL(profile.baseUrl);
793
- } catch {
794
- errors.push("Invalid base URL format");
795
- }
796
- }
797
- return errors;
798
- }
799
- /**
800
- * 检查是否为最后一个配置
801
- */
802
- static isLastProfile(id) {
803
- const config = this.readConfig();
804
- if (!config || !config.profiles[id]) {
805
- return false;
806
- }
807
- return Object.keys(config.profiles).length === 1;
808
- }
809
- }
810
-
811
- export { ClaudeCodeConfigManager };