ccman 3.3.15-beta.1 → 3.3.16

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 (2) hide show
  1. package/dist/index.js +147 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "../core/package.json"() {
16
16
  package_default = {
17
17
  name: "@ccman/core",
18
- version: "3.3.15-beta.1",
18
+ version: "3.3.16",
19
19
  type: "module",
20
20
  description: "Core business logic for ccman - Manage Codex, Claude Code, Gemini CLI, OpenCode, OpenClaw, and MCP configurations",
21
21
  main: "./dist/index.js",
@@ -260,6 +260,13 @@ function backupFile(filePath) {
260
260
  fs.chmodSync(backupPath, 384);
261
261
  return backupPath;
262
262
  }
263
+ function backupFileOrThrow(filePath, operation) {
264
+ try {
265
+ return backupFile(filePath);
266
+ } catch (error) {
267
+ throw new Error(`\u5907\u4EFD\u5931\u8D25\uFF0C\u5DF2\u4E2D\u6B62\u540E\u7EED\u5199\u5165\uFF08${operation}\uFF09: ${error.message}`);
268
+ }
269
+ }
263
270
  var init_file = __esm({
264
271
  "../core/dist/utils/file.js"() {
265
272
  "use strict";
@@ -306,12 +313,6 @@ function loadCodexTemplateConfig() {
306
313
  function writeCodexConfig(provider) {
307
314
  ensureDir(getCodexDir());
308
315
  const configPath = getCodexConfigPath();
309
- if (fileExists(configPath)) {
310
- try {
311
- backupFile(configPath);
312
- } catch {
313
- }
314
- }
315
316
  const templateConfig = loadCodexTemplateConfig();
316
317
  const nextConfig = { ...templateConfig };
317
318
  if (nextConfig.features && typeof nextConfig.features === "object" && !Array.isArray(nextConfig.features) && "web_search_request" in nextConfig.features) {
@@ -333,12 +334,6 @@ function writeCodexConfig(provider) {
333
334
  };
334
335
  fs2.writeFileSync(configPath, stringifyToml(nextConfig), { mode: 384 });
335
336
  const authPath = getCodexAuthPath();
336
- if (fileExists(authPath)) {
337
- try {
338
- backupFile(authPath);
339
- } catch {
340
- }
341
- }
342
337
  const auth = { OPENAI_API_KEY: provider.apiKey };
343
338
  writeJSON(authPath, auth);
344
339
  }
@@ -894,7 +889,9 @@ function saveEnvFile(envPath, env) {
894
889
  lines.push(`${key}=${String(env[key])}`);
895
890
  }
896
891
  const content = lines.join("\n") + (lines.length ? "\n" : "");
897
- fs5.writeFileSync(envPath, content, { mode: 384 });
892
+ const tempPath = `${envPath}.tmp`;
893
+ fs5.writeFileSync(tempPath, content, { mode: 384 });
894
+ fs5.renameSync(tempPath, envPath);
898
895
  }
899
896
  function writeGeminiConfig(provider) {
900
897
  const settingsPath = getGeminiSettingsPath();
@@ -2209,6 +2206,7 @@ function backupConfig(configPath, keepCount = 3) {
2209
2206
  const timestamp = Date.now();
2210
2207
  const backupPath = `${configPath}.backup.${timestamp}`;
2211
2208
  fs9.copyFileSync(configPath, backupPath);
2209
+ fs9.chmodSync(backupPath, 384);
2212
2210
  cleanupOldBackups(configPath, keepCount);
2213
2211
  return backupPath;
2214
2212
  }
@@ -2582,6 +2580,9 @@ function exportConfig(targetDir) {
2582
2580
  const src = path12.join(ccmanDir2, file);
2583
2581
  const dst = path12.join(targetDir, file);
2584
2582
  if (fileExists(src)) {
2583
+ if (fileExists(dst)) {
2584
+ backupFileOrThrow(dst, `export.${file}`);
2585
+ }
2585
2586
  fs11.copyFileSync(src, dst);
2586
2587
  exportedFiles.push(file);
2587
2588
  }
@@ -2658,8 +2659,13 @@ function getFileSize(filePath) {
2658
2659
  function backupFile2(filePath) {
2659
2660
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-").split(".")[0];
2660
2661
  const backupPath = `${filePath}.backup-${timestamp}`;
2661
- fs12.copyFileSync(filePath, backupPath);
2662
- return backupPath;
2662
+ try {
2663
+ fs12.copyFileSync(filePath, backupPath);
2664
+ fs12.chmodSync(backupPath, 384);
2665
+ return backupPath;
2666
+ } catch (error) {
2667
+ throw new Error(`\u5907\u4EFD\u5931\u8D25\uFF0C\u5DF2\u4E2D\u6B62\u540E\u7EED\u5199\u5165\uFF08claude-clean\uFF09: ${error.message}`);
2668
+ }
2663
2669
  }
2664
2670
  function saveJsonAtomic(filePath, data) {
2665
2671
  const tempPath = `${filePath}.tmp`;
@@ -3289,8 +3295,8 @@ function downloadCommand(program2) {
3289
3295
  console.log();
3290
3296
  if (backupPaths.length > 0) {
3291
3297
  console.log(chalk7.gray("\u672C\u5730\u5907\u4EFD:"));
3292
- backupPaths.forEach((path15) => {
3293
- console.log(chalk7.gray(` ${path15}`));
3298
+ backupPaths.forEach((path16) => {
3299
+ console.log(chalk7.gray(` ${path16}`));
3294
3300
  });
3295
3301
  console.log();
3296
3302
  }
@@ -3351,8 +3357,8 @@ function mergeCommand(program2) {
3351
3357
  console.log();
3352
3358
  if (result.backupPaths.length > 0) {
3353
3359
  console.log(chalk8.gray("\u5907\u4EFD:"));
3354
- result.backupPaths.forEach((path15) => {
3355
- console.log(chalk8.gray(` ${path15}`));
3360
+ result.backupPaths.forEach((path16) => {
3361
+ console.log(chalk8.gray(` ${path16}`));
3356
3362
  });
3357
3363
  console.log();
3358
3364
  }
@@ -7141,6 +7147,8 @@ function importCommand(program2) {
7141
7147
 
7142
7148
  // src/commands/gmn.ts
7143
7149
  init_dist2();
7150
+ import fs13 from "fs";
7151
+ import path15 from "path";
7144
7152
  import chalk54 from "chalk";
7145
7153
  import inquirer38 from "inquirer";
7146
7154
  var DEFAULT_PROVIDER_NAME2 = "gmn";
@@ -7283,6 +7291,72 @@ function findPreferredProvider(providers, targetName) {
7283
7291
  const lowerTarget = targetName.toLowerCase();
7284
7292
  return providers.find((p) => p.name.trim().toLowerCase() === lowerTarget);
7285
7293
  }
7294
+ function getPlatformTargetFiles(platform) {
7295
+ const ccmanDir2 = getCcmanDir();
7296
+ switch (platform) {
7297
+ case "codex":
7298
+ return [path15.join(ccmanDir2, "codex.json"), getCodexConfigPath(), getCodexAuthPath()];
7299
+ case "opencode":
7300
+ return [path15.join(ccmanDir2, "opencode.json"), getOpenCodeConfigPath()];
7301
+ case "openclaw":
7302
+ return [
7303
+ path15.join(ccmanDir2, "openclaw.json"),
7304
+ getOpenClawConfigPath(),
7305
+ getOpenClawModelsPath()
7306
+ ];
7307
+ }
7308
+ }
7309
+ function createPlatformBackupOrThrow(platform, backupRootDir) {
7310
+ const backupDir = path15.join(backupRootDir, platform);
7311
+ const entries = [];
7312
+ const targetFiles = getPlatformTargetFiles(platform);
7313
+ fs13.mkdirSync(backupDir, { recursive: true, mode: 448 });
7314
+ for (const [index, originalPath] of targetFiles.entries()) {
7315
+ const existed = fs13.existsSync(originalPath);
7316
+ if (!existed) {
7317
+ entries.push({ originalPath, backupPath: null, existed: false });
7318
+ continue;
7319
+ }
7320
+ const fileName = path15.basename(originalPath).replace(/[^\w.-]/g, "_");
7321
+ const backupPath = path15.join(backupDir, `${String(index).padStart(2, "0")}-${fileName}.bak`);
7322
+ try {
7323
+ fs13.copyFileSync(originalPath, backupPath);
7324
+ fs13.chmodSync(backupPath, 384);
7325
+ entries.push({ originalPath, backupPath, existed: true });
7326
+ } catch (error) {
7327
+ throw new Error(`\u5907\u4EFD\u5931\u8D25\uFF0C\u5DF2\u4E2D\u6B62\u540E\u7EED\u5199\u5165\uFF08${platform}\uFF09: ${error.message}`);
7328
+ }
7329
+ }
7330
+ const manifestPath = path15.join(backupDir, "manifest.json");
7331
+ const manifest = {
7332
+ platform,
7333
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
7334
+ entries
7335
+ };
7336
+ fs13.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), { mode: 384 });
7337
+ return { backupDir, entries };
7338
+ }
7339
+ function rollbackFromBackupOrThrow(result) {
7340
+ const errors = [];
7341
+ for (const entry of result.entries) {
7342
+ try {
7343
+ if (entry.existed) {
7344
+ if (!entry.backupPath || !fs13.existsSync(entry.backupPath)) {
7345
+ throw new Error(`\u5907\u4EFD\u6587\u4EF6\u7F3A\u5931: ${entry.backupPath || entry.originalPath}`);
7346
+ }
7347
+ fs13.mkdirSync(path15.dirname(entry.originalPath), { recursive: true });
7348
+ fs13.copyFileSync(entry.backupPath, entry.originalPath);
7349
+ } else if (fs13.existsSync(entry.originalPath)) {
7350
+ fs13.rmSync(entry.originalPath, { force: true });
7351
+ }
7352
+ } catch (error) {
7353
+ errors.push(`${entry.originalPath}: ${error.message}`);
7354
+ }
7355
+ }
7356
+ if (errors.length > 0) {
7357
+ throw new Error(`\u56DE\u6EDA\u5931\u8D25: ${errors.join("; ")}`);
7358
+ }
7359
+ }
7286
7360
  async function gmnCommand(apiKey, platformArg, providerNameArg) {
7287
7361
  printBanner();
7288
7362
  let platforms;
@@ -7328,6 +7402,14 @@ ${renderStep(3, TOTAL_STEPS, "\u5F00\u59CB\u5199\u5165\u914D\u7F6E")}`));
7328
7402
  }
7329
7403
  printWriteTargets(platforms);
7330
7404
  console.log();
7405
+ const backupRootDir = path15.join(
7406
+ getCcmanDir(),
7407
+ "backups",
7408
+ `gmn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
7409
+ );
7410
+ fs13.mkdirSync(backupRootDir, { recursive: true, mode: 448 });
7411
+ console.log(chalk54.gray(`\u5907\u4EFD\u6839\u76EE\u5F55: ${backupRootDir}`));
7412
+ console.log();
7331
7413
  const ALL_TOOLS = {
7332
7414
  codex: { name: "Codex", manager: createCodexManager() },
7333
7415
  opencode: { name: "OpenCode", manager: createOpenCodeManager() },
@@ -7337,22 +7419,66 @@ ${renderStep(3, TOTAL_STEPS, "\u5F00\u59CB\u5199\u5165\u914D\u7F6E")}`));
7337
7419
  platform,
7338
7420
  ...ALL_TOOLS[platform]
7339
7421
  }));
7422
+ const successBackups = [];
7340
7423
  let completed = 0;
7341
7424
  for (const { platform, name, manager } of tools) {
7425
+ let backupResult = null;
7342
7426
  try {
7343
7427
  console.log(chalk54.gray(`\u2192 \u914D\u7F6E ${name}...`));
7428
+ backupResult = createPlatformBackupOrThrow(platform, backupRootDir);
7429
+ const backupFiles = backupResult.entries.map((entry) => entry.backupPath).filter((p) => p !== null);
7430
+ if (backupFiles.length > 0) {
7431
+ console.log(chalk54.gray(` \u5DF2\u5907\u4EFD ${backupFiles.length} \u4E2A\u6587\u4EF6`));
7432
+ } else {
7433
+ console.log(chalk54.gray(" \u65E0\u5386\u53F2\u6587\u4EF6\u53EF\u5907\u4EFD"));
7434
+ }
7344
7435
  const baseUrl = platformBaseUrls[platform];
7345
7436
  const existing = findPreferredProvider(manager.list(), providerName);
7346
7437
  const provider = existing ? manager.edit(existing.id, { name: providerName, baseUrl, apiKey: resolvedApiKey }) : manager.add({ name: providerName, baseUrl, apiKey: resolvedApiKey });
7347
7438
  manager.switch(provider.id);
7348
7439
  completed += 1;
7349
7440
  console.log(chalk54.green(`\u2705 ${name}`));
7441
+ successBackups.push({
7442
+ name,
7443
+ backupDir: backupResult.backupDir,
7444
+ backupFiles
7445
+ });
7350
7446
  } catch (error) {
7351
- console.error(chalk54.red(`\u274C ${name}: ${error.message}`));
7447
+ const operationError = error;
7448
+ if (backupResult !== null) {
7449
+ try {
7450
+ rollbackFromBackupOrThrow(backupResult);
7451
+ console.error(chalk54.red(`\u274C ${name}: ${operationError.message}\uFF08\u5DF2\u56DE\u6EDA\u5386\u53F2\u6587\u4EF6\uFF09`));
7452
+ } catch (rollbackError) {
7453
+ console.error(
7454
+ chalk54.red(
7455
+ `\u274C ${name}: ${operationError.message}\uFF1B\u56DE\u6EDA\u4E5F\u5931\u8D25: ${rollbackError.message}`
7456
+ )
7457
+ );
7458
+ }
7459
+ } else {
7460
+ console.error(chalk54.red(`\u274C ${name}: ${operationError.message}`));
7461
+ }
7352
7462
  }
7353
7463
  }
7354
7464
  console.log(chalk54.green(`
7355
7465
  \u{1F389} GMN \u914D\u7F6E\u5B8C\u6210\uFF01(${completed}/${tools.length})`));
7466
+ console.log();
7467
+ console.log(chalk54.bold("\u5907\u4EFD\u4FE1\u606F:"));
7468
+ if (successBackups.length === 0) {
7469
+ console.log(chalk54.gray(" \u65E0\u6210\u529F\u914D\u7F6E\u9879\uFF0C\u672A\u751F\u6210\u53EF\u7528\u5907\u4EFD\u76EE\u5F55\u3002"));
7470
+ } else {
7471
+ for (const item of successBackups) {
7472
+ console.log(chalk54.gray(` ${item.name}: ${item.backupDir}`));
7473
+ if (item.backupFiles.length === 0) {
7474
+ console.log(chalk54.gray(" - \u65E0\u5386\u53F2\u6587\u4EF6\u53EF\u5907\u4EFD"));
7475
+ } else {
7476
+ for (const file of item.backupFiles) {
7477
+ console.log(chalk54.gray(` - ${file}`));
7478
+ }
7479
+ }
7480
+ }
7481
+ }
7356
7482
  console.log(chalk54.gray("\u63D0\u793A\uFF1A\u8BF7\u91CD\u542F\u5BF9\u5E94\u5DE5\u5177/\u63D2\u4EF6\u4EE5\u4F7F\u914D\u7F6E\u751F\u6548\u3002"));
7357
7483
  }
7358
7484
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccman",
3
- "version": "3.3.15-beta.1",
3
+ "version": "3.3.16",
4
4
  "type": "module",
5
5
  "description": "Manage Codex, Claude Code, Gemini CLI, OpenCode, OpenClaw, and MCP API service provider configurations",
6
6
  "main": "./dist/index.js",