ccman 3.3.5 → 3.3.7

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.
package/README.md CHANGED
@@ -95,7 +95,7 @@ $ ccman cx list
95
95
  https://api.openai.com/v1
96
96
 
97
97
  ○ GMN
98
- https://gmn.chuangzuoli.cn/openai
98
+ https://gmn.chuangzuoli.com
99
99
  ```
100
100
 
101
101
  ```bash
@@ -231,29 +231,27 @@ ccman mcp remove # 删除 MCP 服务器
231
231
  | 预设名称 | Base URL |
232
232
  |---------|----------|
233
233
  | Anthropic Official | `https://api.anthropic.com` |
234
- | GMN | `https://gmn.chuangzuoli.cn/api` |
234
+ | GMN | `https://gmn.chuangzuoli.com/api` |
235
235
 
236
236
  ### Gemini CLI 预设(2 个)
237
237
 
238
238
  | 预设名称 | Base URL |
239
239
  |---------|----------|
240
240
  | Google Gemini (API Key) | 官方默认 |
241
- | GMN | `https://gmn.chuangzuoli.cn/gemini` |
241
+ | GMN | `https://gmn.chuangzuoli.com` |
242
242
 
243
- ### Codex 预设(3 个)
243
+ ### Codex 预设(2 个)
244
244
 
245
245
  | 预设名称 | Base URL |
246
246
  |---------|----------|
247
247
  | OpenAI Official | `https://api.openai.com/v1` |
248
- | GMN | `https://gmn.chuangzuoli.cn/openai` |
249
- | GMN (COM) | `https://gmn.chuangzuoli.com` |
248
+ | GMN | `https://gmn.chuangzuoli.com` |
250
249
 
251
- ### OpenCode 预设(2 个)
250
+ ### OpenCode 预设(1 个)
252
251
 
253
252
  | 预设名称 | Base URL |
254
253
  |---------|----------|
255
- | GMN | `https://gmn.chuangzuoli.cn/openai` |
256
- | GMN (COM) | `https://gmn.chuangzuoli.com` |
254
+ | GMN | `https://gmn.chuangzuoli.com` |
257
255
 
258
256
  ### MCP 预设(多个)
259
257
 
@@ -296,7 +294,7 @@ $ ccman cx current
296
294
 
297
295
  GMN
298
296
  ID: codex-1760178741529-abc123
299
- URL: https://gmn.chuangzuoli.cn/openai
297
+ URL: https://gmn.chuangzuoli.com
300
298
  最后使用: 2025/10/11 18:32:25
301
299
  ```
302
300
 
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.5",
18
+ version: "3.3.7",
19
19
  type: "module",
20
20
  description: "Core business logic for ccman - Manage Codex, Claude Code, Gemini CLI, and MCP configurations",
21
21
  main: "./dist/index.js",
@@ -229,6 +229,15 @@ function fileExists(filePath) {
229
229
  return false;
230
230
  }
231
231
  }
232
+ function backupFile(filePath) {
233
+ if (!fileExists(filePath)) {
234
+ throw new Error(`File not found: ${filePath}`);
235
+ }
236
+ const backupPath = `${filePath}.bak`;
237
+ fs.copyFileSync(filePath, backupPath);
238
+ fs.chmodSync(backupPath, 384);
239
+ return backupPath;
240
+ }
232
241
  var init_file = __esm({
233
242
  "../core/dist/utils/file.js"() {
234
243
  "use strict";
@@ -284,6 +293,12 @@ function resolveTemplatePath(relativePath) {
284
293
  }
285
294
  return null;
286
295
  }
296
+ function resolveCodexProviderKey(provider) {
297
+ const baseUrl = (provider.baseUrl || "").toLowerCase();
298
+ if (baseUrl.includes("gmn.chuangzuoli.com"))
299
+ return "gmn";
300
+ return provider.name;
301
+ }
287
302
  function loadCodexTemplateConfig() {
288
303
  try {
289
304
  const templatePath = resolveTemplatePath("codex/config.toml");
@@ -305,26 +320,45 @@ function writeCodexConfig(provider) {
305
320
  }
306
321
  const templateConfig = loadCodexTemplateConfig();
307
322
  const mergedConfig = deepMerge(templateConfig, userConfig);
308
- mergedConfig.model_provider = provider.name;
309
- mergedConfig.model = provider.model || mergedConfig.model || "gpt-5-codex";
323
+ if (mergedConfig.features && typeof mergedConfig.features === "object" && !Array.isArray(mergedConfig.features) && "web_search_request" in mergedConfig.features) {
324
+ delete mergedConfig.features.web_search_request;
325
+ }
326
+ if ("web_search_request" in mergedConfig) {
327
+ delete mergedConfig.web_search_request;
328
+ }
329
+ if (mergedConfig.features && typeof mergedConfig.features === "object" && !Array.isArray(mergedConfig.features)) {
330
+ for (const key of ["plan_tool", "view_image_tool", "rmcp_client", "streamable_shell"]) {
331
+ if (key in mergedConfig.features) {
332
+ delete mergedConfig.features[key];
333
+ }
334
+ }
335
+ if (Object.keys(mergedConfig.features).length === 0) {
336
+ delete mergedConfig.features;
337
+ }
338
+ }
339
+ const providerKey = resolveCodexProviderKey(provider);
340
+ mergedConfig.model_provider = providerKey;
341
+ mergedConfig.model = provider.model || mergedConfig.model || "gpt-5.2-codex";
310
342
  mergedConfig.model_providers = mergedConfig.model_providers || {};
311
- mergedConfig.model_providers[provider.name] = {
312
- name: provider.name,
343
+ if (providerKey !== provider.name) {
344
+ delete mergedConfig.model_providers[provider.name];
345
+ }
346
+ mergedConfig.model_providers[providerKey] = {
347
+ name: providerKey,
313
348
  base_url: provider.baseUrl,
314
349
  wire_api: "responses",
315
350
  requires_openai_auth: true
316
351
  };
317
352
  fs2.writeFileSync(configPath, stringifyToml(mergedConfig), { mode: 384 });
318
353
  const authPath = getCodexAuthPath();
319
- let auth;
320
354
  if (fileExists(authPath)) {
321
- const content = fs2.readFileSync(authPath, "utf-8");
322
- auth = JSON.parse(content);
323
- } else {
324
- auth = { OPENAI_API_KEY: "" };
355
+ try {
356
+ backupFile(authPath);
357
+ } catch {
358
+ }
325
359
  }
326
- auth.OPENAI_API_KEY = provider.apiKey;
327
- fs2.writeFileSync(authPath, JSON.stringify(auth, null, 2), { mode: 384 });
360
+ const auth = { OPENAI_API_KEY: provider.apiKey };
361
+ writeJSON(authPath, auth);
328
362
  }
329
363
  var __filename, __dirname, CODEX_DEFAULT_CONFIG;
330
364
  var init_codex = __esm({
@@ -336,49 +370,12 @@ var init_codex = __esm({
336
370
  __filename = fileURLToPath(import.meta.url);
337
371
  __dirname = path3.dirname(__filename);
338
372
  CODEX_DEFAULT_CONFIG = {
339
- model: "gpt-5.1-code-max",
373
+ model: "gpt-5.2-codex",
340
374
  model_reasoning_effort: "high",
375
+ model_verbosity: "high",
376
+ network_access: "enabled",
341
377
  disable_response_storage: true,
342
- sandbox_mode: "danger-full-access",
343
- windows_wsl_setup_acknowledged: true,
344
- approval_policy: "never",
345
- profile: "auto-max",
346
- file_opener: "vscode",
347
- history: {
348
- persistence: "save-all"
349
- },
350
- tui: {
351
- notifications: true
352
- },
353
- shell_environment_policy: {
354
- inherit: "all",
355
- ignore_default_excludes: false
356
- },
357
- features: {
358
- plan_tool: true,
359
- apply_patch_freeform: true,
360
- view_image_tool: true,
361
- web_search_request: true,
362
- unified_exec: false,
363
- streamable_shell: false,
364
- rmcp_client: true
365
- },
366
- sandbox_workspace_write: {
367
- network_access: true
368
- },
369
- profiles: {
370
- "auto-max": {
371
- approval_policy: "never",
372
- sandbox_mode: "workspace-write"
373
- },
374
- review: {
375
- approval_policy: "on-request",
376
- sandbox_mode: "workspace-write"
377
- }
378
- },
379
- notice: {
380
- hide_gpt5_1_migration_prompt: true
381
- }
378
+ windows_wsl_setup_acknowledged: true
382
379
  };
383
380
  }
384
381
  });
@@ -629,11 +626,6 @@ var init_codex2 = __esm({
629
626
  },
630
627
  {
631
628
  name: "GMN",
632
- baseUrl: "https://gmn.chuangzuoli.cn/openai",
633
- description: "GMN \u670D\u52A1 (OpenAI/Codex \u517C\u5BB9)"
634
- },
635
- {
636
- name: "GMN (COM)",
637
629
  baseUrl: "https://gmn.chuangzuoli.com",
638
630
  description: "GMN \u670D\u52A1 (OpenAI/Codex \u517C\u5BB9)"
639
631
  }
@@ -654,7 +646,7 @@ var init_claude2 = __esm({
654
646
  },
655
647
  {
656
648
  name: "GMN",
657
- baseUrl: "https://gmn.chuangzuoli.cn/api",
649
+ baseUrl: "https://gmn.chuangzuoli.com/api",
658
650
  description: "GMN \u670D\u52A1 (Claude \u517C\u5BB9)"
659
651
  }
660
652
  ];
@@ -744,7 +736,7 @@ var init_gemini = __esm({
744
736
  },
745
737
  {
746
738
  name: "GMN",
747
- baseUrl: "https://gmn.chuangzuoli.cn/gemini",
739
+ baseUrl: "https://gmn.chuangzuoli.com",
748
740
  description: "GMN \u670D\u52A1 (Gemini \u517C\u5BB9)"
749
741
  }
750
742
  ];
@@ -759,12 +751,7 @@ var init_opencode = __esm({
759
751
  OPENCODE_PRESETS = [
760
752
  {
761
753
  name: "GMN",
762
- baseUrl: "https://gmn.chuangzuoli.cn/openai",
763
- description: "GMN \u670D\u52A1 (OpenCode \u517C\u5BB9)"
764
- },
765
- {
766
- name: "GMN (COM)",
767
- baseUrl: "https://gmn.chuangzuoli.com/v1",
754
+ baseUrl: "https://gmn.chuangzuoli.com",
768
755
  description: "GMN \u670D\u52A1 (OpenCode \u517C\u5BB9)"
769
756
  }
770
757
  ];
@@ -2219,7 +2206,7 @@ function getFileSize(filePath) {
2219
2206
  return 0;
2220
2207
  }
2221
2208
  }
2222
- function backupFile(filePath) {
2209
+ function backupFile2(filePath) {
2223
2210
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-").split(".")[0];
2224
2211
  const backupPath = `${filePath}.backup-${timestamp}`;
2225
2212
  fs11.copyFileSync(filePath, backupPath);
@@ -2286,7 +2273,7 @@ function cleanClaudeJson(options = {}) {
2286
2273
  if (!fs11.existsSync(filePath)) {
2287
2274
  throw new Error(`${filePath} \u6587\u4EF6\u4E0D\u5B58\u5728`);
2288
2275
  }
2289
- const backupPath = backupFile(filePath);
2276
+ const backupPath = backupFile2(filePath);
2290
2277
  const sizeBefore = getFileSize(filePath);
2291
2278
  const content = fs11.readFileSync(filePath, "utf-8");
2292
2279
  const config = JSON.parse(content);
@@ -6229,14 +6216,11 @@ var PROVIDER_NAME = "GMN";
6229
6216
  var VALID_PLATFORMS = ["claude", "codex", "gemini", "opencode"];
6230
6217
  var DEFAULT_PLATFORMS = ["codex", "opencode"];
6231
6218
  var GMN_BASE_URLS = {
6232
- claude: "https://gmn.chuangzuoli.cn/api",
6233
- gemini: "https://gmn.chuangzuoli.cn/gemini"
6234
- };
6235
- var GMN_OPENAI_BASE_URLS = {
6236
- cn: "https://gmn.chuangzuoli.cn/openai",
6237
- com: "https://gmn.chuangzuoli.com"
6219
+ claude: "https://gmn.chuangzuoli.com/api",
6220
+ gemini: "https://gmn.chuangzuoli.com"
6238
6221
  };
6239
- var TOTAL_STEPS = 4;
6222
+ var GMN_OPENAI_BASE_URL = "https://gmn.chuangzuoli.com";
6223
+ var TOTAL_STEPS = 3;
6240
6224
  function renderStep(current, total, title) {
6241
6225
  const barLength = total;
6242
6226
  const filledLength = Math.min(current, total);
@@ -6258,7 +6242,7 @@ function printBanner() {
6258
6242
  ].join("\n")
6259
6243
  )
6260
6244
  );
6261
- console.log(chalk47.gray("\u81EA\u52A8\u5199\u5165\u9009\u4E2D\u5DE5\u5177\u914D\u7F6E\uFF0C\u652F\u6301\u591A\u9009\u4E0E\u7AEF\u70B9\u9009\u62E9\u3002\n"));
6245
+ console.log(chalk47.gray("\u81EA\u52A8\u5199\u5165\u9009\u4E2D\u5DE5\u5177\u914D\u7F6E\uFF0C\u652F\u6301\u591A\u9009\u3002\n"));
6262
6246
  }
6263
6247
  function printKeyNotice() {
6264
6248
  console.log(
@@ -6356,33 +6340,7 @@ async function resolvePlatforms(platformArg) {
6356
6340
  }
6357
6341
  return promptPlatforms();
6358
6342
  }
6359
- async function resolveOpenAIDomain(domainArg, platforms) {
6360
- const needsOpenAI = platforms.includes("codex") || platforms.includes("opencode");
6361
- if (!needsOpenAI) {
6362
- return "cn";
6363
- }
6364
- if (domainArg && domainArg.trim().length > 0) {
6365
- const normalized = domainArg.trim().toLowerCase();
6366
- if (normalized === "cn" || normalized === "com") {
6367
- return normalized;
6368
- }
6369
- throw new Error(`\u65E0\u6548\u7684 domain: ${domainArg} (\u53EF\u9009: cn, com)`);
6370
- }
6371
- const answers = await inquirer33.prompt([
6372
- {
6373
- type: "list",
6374
- name: "domain",
6375
- message: "\u9009\u62E9 Codex/OpenCode \u7684 OpenAI Base URL\uFF08\u53EA\u5F71\u54CD\u8FD9\u4E24\u4E2A\u5DE5\u5177\uFF09:",
6376
- choices: [
6377
- { name: `CN\uFF08\u56FD\u5185\uFF09 ${GMN_OPENAI_BASE_URLS.cn}`, value: "cn" },
6378
- { name: `COM\uFF08\u56FD\u9645\uFF09 ${GMN_OPENAI_BASE_URLS.com}`, value: "com" }
6379
- ],
6380
- default: "cn"
6381
- }
6382
- ]);
6383
- return answers.domain;
6384
- }
6385
- async function gmnCommand(apiKey, platformArg, domainArg) {
6343
+ async function gmnCommand(apiKey, platformArg) {
6386
6344
  printBanner();
6387
6345
  let platforms;
6388
6346
  try {
@@ -6395,26 +6353,9 @@ ${renderStep(1, TOTAL_STEPS, "\u9009\u62E9\u8981\u914D\u7F6E\u7684\u5DE5\u5177")
6395
6353
  }
6396
6354
  console.log(chalk47.gray(`\u5DF2\u9009\u62E9: ${platforms.join(", ")}`));
6397
6355
  printKeyNotice();
6398
- let openaiDomain;
6399
- try {
6400
- if (platforms.includes("codex") || platforms.includes("opencode")) {
6401
- console.log(
6402
- chalk47.cyan(`
6403
- ${renderStep(2, TOTAL_STEPS, "\u9009\u62E9 OpenAI \u7AEF\u70B9 (\u4EC5 Codex/OpenCode)")}`)
6404
- );
6405
- } else {
6406
- console.log(chalk47.cyan(`
6407
- ${renderStep(2, TOTAL_STEPS, "\u9009\u62E9 OpenAI \u7AEF\u70B9 (\u5DF2\u8DF3\u8FC7)")}`));
6408
- console.log(chalk47.gray("\u672A\u9009\u62E9 Codex/OpenCode\uFF0C\u5C06\u8DF3\u8FC7\u6B64\u6B65\u9AA4\u3002"));
6409
- }
6410
- openaiDomain = await resolveOpenAIDomain(domainArg, platforms);
6411
- } catch (error) {
6412
- console.error(chalk47.red(`\u274C ${error.message}`));
6413
- process.exit(1);
6414
- }
6415
6356
  let resolvedApiKey = apiKey?.trim();
6416
6357
  console.log(chalk47.cyan(`
6417
- ${renderStep(3, TOTAL_STEPS, "\u8F93\u5165 API Key")}`));
6358
+ ${renderStep(2, TOTAL_STEPS, "\u8F93\u5165 API Key")}`));
6418
6359
  if (!resolvedApiKey) {
6419
6360
  resolvedApiKey = await promptApiKey();
6420
6361
  } else {
@@ -6424,7 +6365,7 @@ ${renderStep(3, TOTAL_STEPS, "\u8F93\u5165 API Key")}`));
6424
6365
  console.error(chalk47.red("\u274C \u9519\u8BEF: API Key \u4E0D\u80FD\u4E3A\u7A7A"));
6425
6366
  process.exit(1);
6426
6367
  }
6427
- const openaiBaseUrl = GMN_OPENAI_BASE_URLS[openaiDomain];
6368
+ const openaiBaseUrl = GMN_OPENAI_BASE_URL;
6428
6369
  const platformBaseUrls = {
6429
6370
  claude: GMN_BASE_URLS.claude,
6430
6371
  codex: openaiBaseUrl,
@@ -6432,10 +6373,10 @@ ${renderStep(3, TOTAL_STEPS, "\u8F93\u5165 API Key")}`));
6432
6373
  opencode: openaiBaseUrl
6433
6374
  };
6434
6375
  console.log(chalk47.cyan(`
6435
- ${renderStep(4, TOTAL_STEPS, "\u5F00\u59CB\u5199\u5165\u914D\u7F6E")}`));
6376
+ ${renderStep(3, TOTAL_STEPS, "\u5F00\u59CB\u5199\u5165\u914D\u7F6E")}`));
6436
6377
  console.log(chalk47.gray(`\u5DF2\u9009\u62E9\u5E73\u53F0: ${platforms.join(", ")}`));
6437
6378
  if (platforms.includes("codex") || platforms.includes("opencode")) {
6438
- console.log(chalk47.gray(`OpenAI \u7AEF\u70B9: ${openaiBaseUrl}`));
6379
+ console.log(chalk47.gray(`OpenAI Base URL: ${openaiBaseUrl}`));
6439
6380
  }
6440
6381
  printWriteTargets(platforms);
6441
6382
  console.log();
@@ -6542,8 +6483,8 @@ sync.action(async () => {
6542
6483
  });
6543
6484
  exportCommand(program);
6544
6485
  importCommand(program);
6545
- program.command("gmn [apiKey]").description("\u914D\u7F6E GMN \u5230\u6240\u6709\u5DE5\u5177").option("-p, --platform <platforms>", "\u6307\u5B9A\u5E73\u53F0 (claude,codex,gemini,opencode,all)").option("-d, --domain <domain>", "\u9009\u62E9 OpenAI \u7AEF\u70B9 (cn|com)").action(async (apiKey, options) => {
6546
- await gmnCommand(apiKey, options.platform, options.domain);
6486
+ program.command("gmn [apiKey]").description("\u914D\u7F6E GMN \u5230\u6240\u6709\u5DE5\u5177").option("-p, --platform <platforms>", "\u6307\u5B9A\u5E73\u53F0 (claude,codex,gemini,opencode,all)").action(async (apiKey, options) => {
6487
+ await gmnCommand(apiKey, options.platform);
6547
6488
  });
6548
6489
  (async () => {
6549
6490
  if (!process.argv.slice(2).length) {
@@ -1,109 +1,13 @@
1
1
  ########################################
2
- # 基础设置:通用 Codex 默认配置
2
+ # Codex 最小模板(ccman 默认)
3
+ #
4
+ # - model_provider 与 [model_providers.*] 由 ccman 根据当前服务商自动写入
5
+ # - 配置越少越稳定;需要扩展再手动加
3
6
  ########################################
4
7
 
5
- model = "gpt-5.1-code-max"
6
-
7
- # model_provider 与 model_providers 由 ccman 根据当前服务商自动写入
8
- # 如需手动指定可自行在此添加:
9
- # model_provider = "YourProviderName"
10
-
11
- # 理力度设置
8
+ model = "gpt-5.2-codex"
12
9
  model_reasoning_effort = "high"
13
-
14
- # 存储策略
10
+ model_verbosity = "high"
11
+ network_access = "enabled"
15
12
  disable_response_storage = true
16
-
17
- # 沙箱模式
18
- sandbox_mode = "danger-full-access" # 完全禁用沙箱
19
- # sandbox_mode = "workspace-write"
20
13
  windows_wsl_setup_acknowledged = true
21
-
22
- # 命令审批策略(只影响本地行为,不会影响上游服务商)
23
- # - "never":尽量自动执行命令(自动模式)
24
- approval_policy = "never"
25
-
26
- # 默认使用的 profile(下面定义,只改行为,不改 model)
27
- profile = "auto-max"
28
-
29
- # 打开文件用哪个编辑器
30
- file_opener = "vscode"
31
-
32
-
33
- ########################################
34
- # 历史记录 & 终端 UI(纯本地)
35
- ########################################
36
-
37
- [history]
38
- persistence = "save-all"
39
-
40
- [tui]
41
- notifications = true
42
-
43
-
44
- ########################################
45
- # Shell 环境(纯本地)
46
- ########################################
47
-
48
- [shell_environment_policy]
49
- inherit = "all"
50
- ignore_default_excludes = false
51
- # 如有需要可以再加 exclude / include_only / set
52
-
53
-
54
- ########################################
55
- # workspace-write 沙箱设置(纯本地)
56
- ########################################
57
-
58
- [sandbox_workspace_write]
59
- network_access = true
60
- # 可按需再加 writable_roots / exclude_tmpdir_env_var / exclude_slash_tmp
61
-
62
-
63
- ########################################
64
- # Features(完全沿用你原来的 + 本地能力)
65
- ########################################
66
-
67
- [features]
68
- plan_tool = true
69
- apply_patch_freeform = true
70
- view_image_tool = true
71
- web_search_request = true
72
- unified_exec = false
73
- streamable_shell = false
74
- rmcp_client = true
75
- # 如以后确认其他服务完全兼容,可以考虑再打开 ghost_commit 等
76
-
77
-
78
- ########################################
79
- # Profiles:只改“行为”,不改模型/提供方
80
- ########################################
81
-
82
- [profiles.auto-max]
83
- # 使用顶层的 model / model_provider(即 gpt-5.1-codex + OpenAI/GMN)
84
- # 这里只覆盖“本地行为”,例如审批和沙箱
85
- approval_policy = "never"
86
- sandbox_mode = "workspace-write"
87
-
88
- [profiles.review]
89
- # 审核模式:命令前多问一句(适合公司仓库)
90
- approval_policy = "on-request"
91
- sandbox_mode = "workspace-write"
92
-
93
-
94
- ########################################
95
- # 其它提示 / 杂项
96
- ########################################
97
-
98
- [notice]
99
- hide_gpt5_1_migration_prompt = true
100
-
101
- ########################################
102
- # 模型提供方示例(仅注释示例,不会生效)
103
- ########################################
104
-
105
- # [model_providers.gmn]
106
- # name = "GMN"
107
- # base_url = "https://gmn.chuangzuoli.cn/openai"
108
- # wire_api = "responses"
109
- # requires_openai_auth = true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccman",
3
- "version": "3.3.5",
3
+ "version": "3.3.7",
4
4
  "type": "module",
5
5
  "description": "Manage Codex, Claude Code, Gemini CLI, OpenCode, and MCP API service provider configurations",
6
6
  "main": "./dist/index.js",