ccem 2.0.0-beta.3 → 2.0.0-beta.6

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 +439 -186
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11,27 +11,109 @@ import * as fs8 from "fs";
11
11
  import * as path6 from "path";
12
12
  import { fileURLToPath as fileURLToPath2 } from "url";
13
13
 
14
- // ../../packages/core/dist/chunk-YO7HO5AS.js
14
+ // ../../packages/core/dist/chunk-6W4EMMVY.js
15
+ var TIER_MODEL_ALIASES = /* @__PURE__ */ new Set(["opus", "sonnet", "haiku"]);
16
+ function normalizeEnvConfig(envConfig, defaultRuntimeModel = "opus") {
17
+ const hasTierDefaults = Boolean(envConfig.ANTHROPIC_DEFAULT_OPUS_MODEL) || Boolean(envConfig.ANTHROPIC_DEFAULT_SONNET_MODEL) || Boolean(envConfig.ANTHROPIC_DEFAULT_HAIKU_MODEL);
18
+ const defaultOpusModel = envConfig.ANTHROPIC_DEFAULT_OPUS_MODEL ?? (hasTierDefaults ? void 0 : envConfig.ANTHROPIC_MODEL);
19
+ const defaultSonnetModel = envConfig.ANTHROPIC_DEFAULT_SONNET_MODEL ?? defaultOpusModel ?? (hasTierDefaults ? void 0 : envConfig.ANTHROPIC_MODEL);
20
+ const defaultHaikuModel = envConfig.ANTHROPIC_DEFAULT_HAIKU_MODEL ?? envConfig.ANTHROPIC_SMALL_FAST_MODEL;
21
+ return {
22
+ ...envConfig.ANTHROPIC_BASE_URL && {
23
+ ANTHROPIC_BASE_URL: envConfig.ANTHROPIC_BASE_URL
24
+ },
25
+ ...(envConfig.ANTHROPIC_AUTH_TOKEN ?? envConfig.ANTHROPIC_API_KEY) && {
26
+ ANTHROPIC_AUTH_TOKEN: envConfig.ANTHROPIC_AUTH_TOKEN ?? envConfig.ANTHROPIC_API_KEY
27
+ },
28
+ ...defaultOpusModel && {
29
+ ANTHROPIC_DEFAULT_OPUS_MODEL: defaultOpusModel
30
+ },
31
+ ...defaultSonnetModel && {
32
+ ANTHROPIC_DEFAULT_SONNET_MODEL: defaultSonnetModel
33
+ },
34
+ ...defaultHaikuModel && {
35
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: defaultHaikuModel
36
+ },
37
+ ANTHROPIC_MODEL: hasTierDefaults ? envConfig.ANTHROPIC_MODEL ?? defaultRuntimeModel : defaultRuntimeModel,
38
+ ...envConfig.CLAUDE_CODE_SUBAGENT_MODEL && {
39
+ CLAUDE_CODE_SUBAGENT_MODEL: envConfig.CLAUDE_CODE_SUBAGENT_MODEL
40
+ }
41
+ };
42
+ }
43
+ function shouldRecoverTierModel(model) {
44
+ return !model || TIER_MODEL_ALIASES.has(model);
45
+ }
46
+ function recoverEnvConfigFromLegacy(currentEnvConfig, legacyEnvConfig) {
47
+ const current = normalizeEnvConfig(currentEnvConfig);
48
+ const legacy = normalizeEnvConfig(legacyEnvConfig);
49
+ return {
50
+ ...current,
51
+ ...!current.ANTHROPIC_AUTH_TOKEN && legacy.ANTHROPIC_AUTH_TOKEN && {
52
+ ANTHROPIC_AUTH_TOKEN: legacy.ANTHROPIC_AUTH_TOKEN
53
+ },
54
+ ...shouldRecoverTierModel(current.ANTHROPIC_DEFAULT_OPUS_MODEL) && legacy.ANTHROPIC_DEFAULT_OPUS_MODEL && {
55
+ ANTHROPIC_DEFAULT_OPUS_MODEL: legacy.ANTHROPIC_DEFAULT_OPUS_MODEL
56
+ },
57
+ ...shouldRecoverTierModel(current.ANTHROPIC_DEFAULT_SONNET_MODEL) && legacy.ANTHROPIC_DEFAULT_SONNET_MODEL && {
58
+ ANTHROPIC_DEFAULT_SONNET_MODEL: legacy.ANTHROPIC_DEFAULT_SONNET_MODEL
59
+ },
60
+ ...shouldRecoverTierModel(current.ANTHROPIC_DEFAULT_HAIKU_MODEL) && legacy.ANTHROPIC_DEFAULT_HAIKU_MODEL && {
61
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: legacy.ANTHROPIC_DEFAULT_HAIKU_MODEL
62
+ },
63
+ ...!current.CLAUDE_CODE_SUBAGENT_MODEL && legacy.CLAUDE_CODE_SUBAGENT_MODEL && {
64
+ CLAUDE_CODE_SUBAGENT_MODEL: legacy.CLAUDE_CODE_SUBAGENT_MODEL
65
+ }
66
+ };
67
+ }
15
68
  var ENV_PRESETS = {
16
69
  "GLM": {
17
70
  ANTHROPIC_BASE_URL: "https://open.bigmodel.cn/api/anthropic",
18
- ANTHROPIC_MODEL: "glm-4.6",
19
- ANTHROPIC_SMALL_FAST_MODEL: "glm-4.5-air"
71
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "glm-5",
72
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "glm-5",
73
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "glm-4.5-air",
74
+ ANTHROPIC_MODEL: "opus"
20
75
  },
21
76
  "KIMI": {
22
77
  ANTHROPIC_BASE_URL: "https://api.moonshot.cn/anthropic",
23
- ANTHROPIC_MODEL: "kimi-k2-thinking-turbo",
24
- ANTHROPIC_SMALL_FAST_MODEL: "kimi-k2-turbo-preview"
78
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "kimi-k2-thinking-turbo",
79
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "kimi-k2-thinking-turbo",
80
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "kimi-k2-turbo-preview",
81
+ ANTHROPIC_MODEL: "opus"
25
82
  },
26
83
  "MiniMax": {
27
84
  ANTHROPIC_BASE_URL: "https://api.minimaxi.com/anthropic",
28
- ANTHROPIC_MODEL: "MiniMax-M2",
29
- ANTHROPIC_SMALL_FAST_MODEL: "MiniMax-M2"
85
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "MiniMax-M2.5",
86
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "MiniMax-M2.5",
87
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "MiniMax-M2.5-highspeed",
88
+ ANTHROPIC_MODEL: "opus"
30
89
  },
31
90
  "DeepSeek": {
32
91
  ANTHROPIC_BASE_URL: "https://api.deepseek.com/anthropic",
33
- ANTHROPIC_MODEL: "deepseek-chat",
34
- ANTHROPIC_SMALL_FAST_MODEL: "deepseek-chat"
92
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "deepseek-chat",
93
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "deepseek-chat",
94
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "deepseek-chat",
95
+ ANTHROPIC_MODEL: "opus"
96
+ },
97
+ "Bailian": {
98
+ ANTHROPIC_BASE_URL: "https://dashscope.aliyuncs.com/api/v2/apps/claude-code-proxy",
99
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "qwen3-coder-plus",
100
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "qwen3-coder-plus",
101
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "qwen3-coder-flash",
102
+ ANTHROPIC_MODEL: "opus"
103
+ },
104
+ "BailianCodePlan": {
105
+ ANTHROPIC_BASE_URL: "https://coding.dashscope.aliyuncs.com/api/v2/apps/claude-code-proxy",
106
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "qwen3-coder-plus",
107
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "qwen3-coder-plus",
108
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "qwen3-coder-plus",
109
+ ANTHROPIC_MODEL: "opus"
110
+ },
111
+ "OpenRouter": {
112
+ ANTHROPIC_BASE_URL: "https://openrouter.ai/api/v1",
113
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "anthropic/claude-opus-4-1",
114
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "anthropic/claude-opus-4-1",
115
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "anthropic/claude-3.5-haiku",
116
+ ANTHROPIC_MODEL: "opus"
35
117
  }
36
118
  };
37
119
  var PERMISSION_PRESETS = {
@@ -814,9 +896,10 @@ var renderLogoWithEnvPanel = (envName, env, defaultMode) => {
814
896
  const titleShort = theme.primary("CCEM");
815
897
  const envLabel = theme.muted("Env: ") + theme.primary(envName);
816
898
  const baseUrl = env.ANTHROPIC_BASE_URL || "-";
817
- const model = env.ANTHROPIC_MODEL || "-";
818
- const fastModel = env.ANTHROPIC_SMALL_FAST_MODEL || "-";
819
- const apiKey = env.ANTHROPIC_API_KEY ? env.ANTHROPIC_API_KEY.slice(0, 2) + "\u2022\u2022\u2022\u2022" + env.ANTHROPIC_API_KEY.slice(-4) : "-";
899
+ const runtimeModel = env.ANTHROPIC_MODEL || "-";
900
+ const opusModel = env.ANTHROPIC_DEFAULT_OPUS_MODEL || "-";
901
+ const haikuModel = env.ANTHROPIC_DEFAULT_HAIKU_MODEL || "-";
902
+ const authToken = env.ANTHROPIC_AUTH_TOKEN ? env.ANTHROPIC_AUTH_TOKEN.slice(0, 2) + "\u2022\u2022\u2022\u2022" + env.ANTHROPIC_AUTH_TOKEN.slice(-4) : "-";
820
903
  const truncate = (s, max) => s.length > max ? s.slice(0, max - 3) + "..." : s;
821
904
  const maskUrl = (url, max) => {
822
905
  if (url.length <= max) return url;
@@ -838,15 +921,15 @@ var renderLogoWithEnvPanel = (envName, env, defaultMode) => {
838
921
  if (isNarrow) {
839
922
  envLines = [
840
923
  envLabel,
841
- theme.muted("Model:".padEnd(labelWidth)) + theme.dim(truncate(model, 25)),
842
- theme.muted("Key:".padEnd(labelWidth)) + theme.dim(apiKey)
924
+ theme.muted("Opus:".padEnd(labelWidth)) + theme.dim(truncate(opusModel, 25)),
925
+ theme.muted("Token:".padEnd(labelWidth)) + theme.dim(authToken)
843
926
  ];
844
927
  } else {
845
928
  envLines = [
846
929
  envLabel + (defaultMode && PERMISSION_PRESETS[defaultMode] ? " " + theme.accent(`[${PERMISSION_PRESETS[defaultMode].name}]`) : ""),
847
930
  theme.muted("URL:".padEnd(labelWidth)) + theme.dim(maskUrl(baseUrl, 40)),
848
- theme.muted("Model:".padEnd(labelWidth)) + theme.dim(truncate(model, 15)) + " " + theme.muted("Fast:".padEnd(labelWidth)) + theme.dim(truncate(fastModel, 15)),
849
- theme.muted("Key:".padEnd(labelWidth)) + theme.dim(apiKey)
931
+ theme.muted("Run:".padEnd(labelWidth)) + theme.dim(truncate(runtimeModel, 12)) + " " + theme.muted("Opus:".padEnd(labelWidth)) + theme.dim(truncate(opusModel, 15)),
932
+ theme.muted("Haiku:".padEnd(labelWidth)) + theme.dim(truncate(haikuModel, 15)) + " " + theme.muted("Token:".padEnd(labelWidth)) + theme.dim(authToken)
850
933
  ];
851
934
  }
852
935
  const lines = [];
@@ -1321,12 +1404,26 @@ import { spawn } from "child_process";
1321
1404
  import * as fs4 from "fs";
1322
1405
  import * as path4 from "path";
1323
1406
  import chalk2 from "chalk";
1407
+ var MANAGED_CLAUDE_ENV_KEYS = [
1408
+ "ANTHROPIC_BASE_URL",
1409
+ "ANTHROPIC_AUTH_TOKEN",
1410
+ "ANTHROPIC_DEFAULT_OPUS_MODEL",
1411
+ "ANTHROPIC_DEFAULT_SONNET_MODEL",
1412
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL",
1413
+ "ANTHROPIC_MODEL",
1414
+ "CLAUDE_CODE_SUBAGENT_MODEL",
1415
+ "ANTHROPIC_API_KEY",
1416
+ "ANTHROPIC_SMALL_FAST_MODEL"
1417
+ ];
1324
1418
  function buildEnvVars(envConfig) {
1325
1419
  const vars = {};
1326
1420
  if (envConfig.ANTHROPIC_BASE_URL) vars.ANTHROPIC_BASE_URL = envConfig.ANTHROPIC_BASE_URL;
1327
- if (envConfig.ANTHROPIC_API_KEY) vars.ANTHROPIC_API_KEY = decrypt(envConfig.ANTHROPIC_API_KEY);
1421
+ if (envConfig.ANTHROPIC_AUTH_TOKEN) vars.ANTHROPIC_AUTH_TOKEN = decrypt(envConfig.ANTHROPIC_AUTH_TOKEN);
1422
+ if (envConfig.ANTHROPIC_DEFAULT_OPUS_MODEL) vars.ANTHROPIC_DEFAULT_OPUS_MODEL = envConfig.ANTHROPIC_DEFAULT_OPUS_MODEL;
1423
+ if (envConfig.ANTHROPIC_DEFAULT_SONNET_MODEL) vars.ANTHROPIC_DEFAULT_SONNET_MODEL = envConfig.ANTHROPIC_DEFAULT_SONNET_MODEL;
1424
+ if (envConfig.ANTHROPIC_DEFAULT_HAIKU_MODEL) vars.ANTHROPIC_DEFAULT_HAIKU_MODEL = envConfig.ANTHROPIC_DEFAULT_HAIKU_MODEL;
1328
1425
  if (envConfig.ANTHROPIC_MODEL) vars.ANTHROPIC_MODEL = envConfig.ANTHROPIC_MODEL;
1329
- if (envConfig.ANTHROPIC_SMALL_FAST_MODEL) vars.ANTHROPIC_SMALL_FAST_MODEL = envConfig.ANTHROPIC_SMALL_FAST_MODEL;
1426
+ if (envConfig.CLAUDE_CODE_SUBAGENT_MODEL) vars.CLAUDE_CODE_SUBAGENT_MODEL = envConfig.CLAUDE_CODE_SUBAGENT_MODEL;
1330
1427
  return vars;
1331
1428
  }
1332
1429
  function buildPermArgs(modeName) {
@@ -1353,6 +1450,9 @@ function ensureSessionsDir() {
1353
1450
  async function launchClaude(options) {
1354
1451
  const { envConfig, permMode, workingDir, sessionId, resumeSessionId, silent } = options;
1355
1452
  const env = { ...process.env };
1453
+ for (const key of MANAGED_CLAUDE_ENV_KEYS) {
1454
+ delete env[key];
1455
+ }
1356
1456
  if (envConfig) {
1357
1457
  Object.assign(env, buildEnvVars(envConfig));
1358
1458
  }
@@ -2228,9 +2328,10 @@ var loadFromRemote = async (url, secret) => {
2228
2328
  for (const [name, envConfig] of Object.entries(decrypted.environments)) {
2229
2329
  const uniqueName = getUniqueName(name, existingNames);
2230
2330
  const renamed = uniqueName !== name;
2231
- const configToSave = { ...envConfig };
2232
- if (configToSave.ANTHROPIC_API_KEY) {
2233
- configToSave.ANTHROPIC_API_KEY = encrypt(configToSave.ANTHROPIC_API_KEY);
2331
+ const normalizedConfig = normalizeEnvConfig(envConfig);
2332
+ const configToSave = { ...normalizedConfig };
2333
+ if (configToSave.ANTHROPIC_AUTH_TOKEN) {
2334
+ configToSave.ANTHROPIC_AUTH_TOKEN = encrypt(configToSave.ANTHROPIC_AUTH_TOKEN);
2234
2335
  }
2235
2336
  registries[uniqueName] = configToSave;
2236
2337
  existingNames.add(uniqueName);
@@ -2402,6 +2503,47 @@ var __dirname2 = path6.dirname(__filename2);
2402
2503
  var pkgPath = path6.resolve(__dirname2, "..", "package.json");
2403
2504
  var pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
2404
2505
  var program = new Command();
2506
+ var DEFAULT_OFFICIAL_ENV = {
2507
+ ANTHROPIC_BASE_URL: "https://api.anthropic.com",
2508
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "claude-opus-4-1-20250805",
2509
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "claude-opus-4-1-20250805",
2510
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "claude-3-5-haiku-20241022",
2511
+ ANTHROPIC_MODEL: "opus"
2512
+ };
2513
+ var MANAGED_CLAUDE_ENV_KEYS2 = [
2514
+ "ANTHROPIC_BASE_URL",
2515
+ "ANTHROPIC_AUTH_TOKEN",
2516
+ "ANTHROPIC_DEFAULT_OPUS_MODEL",
2517
+ "ANTHROPIC_DEFAULT_SONNET_MODEL",
2518
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL",
2519
+ "ANTHROPIC_MODEL",
2520
+ "CLAUDE_CODE_SUBAGENT_MODEL",
2521
+ "ANTHROPIC_API_KEY",
2522
+ "ANTHROPIC_SMALL_FAST_MODEL"
2523
+ ];
2524
+ var shellQuote = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
2525
+ var clearManagedClaudeEnv = (env) => {
2526
+ for (const key of MANAGED_CLAUDE_ENV_KEYS2) {
2527
+ delete env[key];
2528
+ }
2529
+ };
2530
+ var buildResolvedEnvVars = (env) => {
2531
+ const resolved = {};
2532
+ if (env.ANTHROPIC_BASE_URL) resolved.ANTHROPIC_BASE_URL = env.ANTHROPIC_BASE_URL;
2533
+ if (env.ANTHROPIC_AUTH_TOKEN) resolved.ANTHROPIC_AUTH_TOKEN = decrypt(env.ANTHROPIC_AUTH_TOKEN);
2534
+ if (env.ANTHROPIC_DEFAULT_OPUS_MODEL) resolved.ANTHROPIC_DEFAULT_OPUS_MODEL = env.ANTHROPIC_DEFAULT_OPUS_MODEL;
2535
+ if (env.ANTHROPIC_DEFAULT_SONNET_MODEL) resolved.ANTHROPIC_DEFAULT_SONNET_MODEL = env.ANTHROPIC_DEFAULT_SONNET_MODEL;
2536
+ if (env.ANTHROPIC_DEFAULT_HAIKU_MODEL) resolved.ANTHROPIC_DEFAULT_HAIKU_MODEL = env.ANTHROPIC_DEFAULT_HAIKU_MODEL;
2537
+ if (env.ANTHROPIC_MODEL) resolved.ANTHROPIC_MODEL = env.ANTHROPIC_MODEL;
2538
+ if (env.CLAUDE_CODE_SUBAGENT_MODEL) resolved.CLAUDE_CODE_SUBAGENT_MODEL = env.CLAUDE_CODE_SUBAGENT_MODEL;
2539
+ return resolved;
2540
+ };
2541
+ var buildShellEnvCommands = (env) => {
2542
+ const resolved = buildResolvedEnvVars(env);
2543
+ return MANAGED_CLAUDE_ENV_KEYS2.map(
2544
+ (key) => resolved[key] ? `export ${key}=${shellQuote(resolved[key])}` : `unset ${key}`
2545
+ );
2546
+ };
2405
2547
  ensureCcemDir();
2406
2548
  var config2 = new Conf2({
2407
2549
  projectName: "claude-code-env-manager",
@@ -2409,16 +2551,129 @@ var config2 = new Conf2({
2409
2551
  // 使用新路径
2410
2552
  defaults: {
2411
2553
  registries: {
2412
- "official": {
2413
- ANTHROPIC_BASE_URL: "https://api.anthropic.com",
2414
- ANTHROPIC_MODEL: "claude-sonnet-4-5-20250929",
2415
- ANTHROPIC_SMALL_FAST_MODEL: "claude-haiku-4-5-20251001"
2416
- }
2554
+ official: DEFAULT_OFFICIAL_ENV
2417
2555
  },
2418
2556
  current: "official",
2419
2557
  defaultMode: null
2420
2558
  }
2421
2559
  });
2560
+ var recoverRegistriesFromLegacy = (registries) => {
2561
+ const currentAuthCount = Object.values(registries).filter(
2562
+ (env) => Boolean(env.ANTHROPIC_AUTH_TOKEN)
2563
+ ).length;
2564
+ if (currentAuthCount > 0) {
2565
+ return registries;
2566
+ }
2567
+ const legacyConfigPath = getLegacyConfigPath();
2568
+ if (!fs8.existsSync(legacyConfigPath)) {
2569
+ return registries;
2570
+ }
2571
+ try {
2572
+ const legacyRaw = JSON.parse(fs8.readFileSync(legacyConfigPath, "utf-8"));
2573
+ const legacyRegistries = legacyRaw.registries ?? {};
2574
+ let changed = false;
2575
+ const recovered = { ...registries };
2576
+ for (const [name, envConfig] of Object.entries(registries)) {
2577
+ const legacyEnvConfig = legacyRegistries[name];
2578
+ if (!legacyEnvConfig) {
2579
+ continue;
2580
+ }
2581
+ const recoveredEnv = recoverEnvConfigFromLegacy(envConfig, legacyEnvConfig);
2582
+ if (JSON.stringify(recoveredEnv) !== JSON.stringify(envConfig)) {
2583
+ recovered[name] = recoveredEnv;
2584
+ changed = true;
2585
+ }
2586
+ }
2587
+ return changed ? recovered : registries;
2588
+ } catch {
2589
+ return registries;
2590
+ }
2591
+ };
2592
+ var getRegistries = () => {
2593
+ const rawRegistries = config2.get("registries") ?? {};
2594
+ const normalizedEntries = Object.entries(rawRegistries).map(([name, envConfig]) => [
2595
+ name,
2596
+ normalizeEnvConfig(envConfig ?? {})
2597
+ ]);
2598
+ const normalizedRegistries = Object.fromEntries(normalizedEntries);
2599
+ const repairedRegistries = recoverRegistriesFromLegacy(normalizedRegistries);
2600
+ if (!repairedRegistries.official) {
2601
+ repairedRegistries.official = { ...DEFAULT_OFFICIAL_ENV };
2602
+ }
2603
+ const changed = Object.keys(rawRegistries).length !== Object.keys(repairedRegistries).length || JSON.stringify(rawRegistries) !== JSON.stringify(repairedRegistries);
2604
+ if (changed) {
2605
+ config2.set("registries", repairedRegistries);
2606
+ }
2607
+ return repairedRegistries;
2608
+ };
2609
+ var setRegistries = (registries) => {
2610
+ config2.set("registries", registries);
2611
+ };
2612
+ var getDecryptedAuthToken = (envConfig) => {
2613
+ return envConfig.ANTHROPIC_AUTH_TOKEN ? decrypt(envConfig.ANTHROPIC_AUTH_TOKEN) : void 0;
2614
+ };
2615
+ var applyPromptAnswers = (current, answers, keepCurrentSecret) => {
2616
+ const next = {
2617
+ ...current,
2618
+ ANTHROPIC_BASE_URL: answers.ANTHROPIC_BASE_URL?.trim() || current.ANTHROPIC_BASE_URL,
2619
+ ANTHROPIC_DEFAULT_OPUS_MODEL: answers.ANTHROPIC_DEFAULT_OPUS_MODEL?.trim() || current.ANTHROPIC_DEFAULT_OPUS_MODEL,
2620
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: answers.ANTHROPIC_DEFAULT_HAIKU_MODEL?.trim() || current.ANTHROPIC_DEFAULT_HAIKU_MODEL,
2621
+ ANTHROPIC_DEFAULT_SONNET_MODEL: answers.ANTHROPIC_DEFAULT_SONNET_MODEL?.trim() || answers.ANTHROPIC_DEFAULT_OPUS_MODEL?.trim() || current.ANTHROPIC_DEFAULT_SONNET_MODEL || current.ANTHROPIC_DEFAULT_OPUS_MODEL,
2622
+ ANTHROPIC_MODEL: answers.ANTHROPIC_MODEL?.trim() || current.ANTHROPIC_MODEL || "opus",
2623
+ CLAUDE_CODE_SUBAGENT_MODEL: answers.CLAUDE_CODE_SUBAGENT_MODEL?.trim() || current.CLAUDE_CODE_SUBAGENT_MODEL
2624
+ };
2625
+ if (!keepCurrentSecret) {
2626
+ next.ANTHROPIC_AUTH_TOKEN = answers.ANTHROPIC_AUTH_TOKEN ? encrypt(answers.ANTHROPIC_AUTH_TOKEN) : void 0;
2627
+ } else if (answers.ANTHROPIC_AUTH_TOKEN) {
2628
+ next.ANTHROPIC_AUTH_TOKEN = encrypt(answers.ANTHROPIC_AUTH_TOKEN);
2629
+ }
2630
+ return normalizeEnvConfig(next);
2631
+ };
2632
+ var promptForEnvironmentConfig = async (current = {}, keepCurrentSecret = false) => {
2633
+ return inquirer.prompt([
2634
+ {
2635
+ type: "input",
2636
+ name: "ANTHROPIC_BASE_URL",
2637
+ message: "ANTHROPIC_BASE_URL:",
2638
+ default: current.ANTHROPIC_BASE_URL || DEFAULT_OFFICIAL_ENV.ANTHROPIC_BASE_URL
2639
+ },
2640
+ {
2641
+ type: "password",
2642
+ name: "ANTHROPIC_AUTH_TOKEN",
2643
+ message: keepCurrentSecret ? "ANTHROPIC_AUTH_TOKEN (leave empty to keep current):" : "ANTHROPIC_AUTH_TOKEN:"
2644
+ },
2645
+ {
2646
+ type: "input",
2647
+ name: "ANTHROPIC_DEFAULT_OPUS_MODEL",
2648
+ message: "ANTHROPIC_DEFAULT_OPUS_MODEL:",
2649
+ default: current.ANTHROPIC_DEFAULT_OPUS_MODEL || DEFAULT_OFFICIAL_ENV.ANTHROPIC_DEFAULT_OPUS_MODEL
2650
+ },
2651
+ {
2652
+ type: "input",
2653
+ name: "ANTHROPIC_DEFAULT_HAIKU_MODEL",
2654
+ message: "ANTHROPIC_DEFAULT_HAIKU_MODEL:",
2655
+ default: current.ANTHROPIC_DEFAULT_HAIKU_MODEL || DEFAULT_OFFICIAL_ENV.ANTHROPIC_DEFAULT_HAIKU_MODEL
2656
+ },
2657
+ {
2658
+ type: "input",
2659
+ name: "ANTHROPIC_DEFAULT_SONNET_MODEL",
2660
+ message: "ANTHROPIC_DEFAULT_SONNET_MODEL (blank = same as opus):",
2661
+ default: current.ANTHROPIC_DEFAULT_SONNET_MODEL || current.ANTHROPIC_DEFAULT_OPUS_MODEL || ""
2662
+ },
2663
+ {
2664
+ type: "input",
2665
+ name: "ANTHROPIC_MODEL",
2666
+ message: "ANTHROPIC_MODEL (e.g. opus, opusplan, sonnet):",
2667
+ default: current.ANTHROPIC_MODEL || "opus"
2668
+ },
2669
+ {
2670
+ type: "input",
2671
+ name: "CLAUDE_CODE_SUBAGENT_MODEL",
2672
+ message: "CLAUDE_CODE_SUBAGENT_MODEL (optional):",
2673
+ default: current.CLAUDE_CODE_SUBAGENT_MODEL || ""
2674
+ }
2675
+ ]);
2676
+ };
2422
2677
  var PERMISSION_MODES = ["yolo", "dev", "readonly", "safe", "ci", "audit"];
2423
2678
  var usageStats = null;
2424
2679
  var usageLoading = true;
@@ -2457,7 +2712,7 @@ program.name("ccem").description("Claude Code Environment Manager - \u7BA1\u7406
2457
2712
  PERMISSION_MODES.forEach((mode) => {
2458
2713
  const preset = PERMISSION_PRESETS[mode];
2459
2714
  program.command(mode).description(`\u4E34\u65F6\u5E94\u7528 ${preset.name}\uFF0C\u9000\u51FA\u540E\u8FD8\u539F`).action(async () => {
2460
- const registries = config2.get("registries");
2715
+ const registries = getRegistries();
2461
2716
  const current = config2.get("current");
2462
2717
  const envConfig = registries[current];
2463
2718
  await runWithTempPermissions(mode, envConfig);
@@ -2466,15 +2721,18 @@ PERMISSION_MODES.forEach((mode) => {
2466
2721
  var showCurrentEnv = (usageStats2, usageLoading2) => {
2467
2722
  if (!process.stdout.isTTY) return;
2468
2723
  const current = config2.get("current");
2469
- const registries = config2.get("registries");
2724
+ const registries = getRegistries();
2470
2725
  const env = registries[current];
2471
2726
  const defaultMode = config2.get("defaultMode");
2472
2727
  if (!env) return;
2473
2728
  console.log(renderLogoWithEnvPanel(current, {
2474
2729
  ANTHROPIC_BASE_URL: env.ANTHROPIC_BASE_URL,
2475
- ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY ? decrypt(env.ANTHROPIC_API_KEY) : void 0,
2730
+ ANTHROPIC_AUTH_TOKEN: getDecryptedAuthToken(env),
2731
+ ANTHROPIC_DEFAULT_OPUS_MODEL: env.ANTHROPIC_DEFAULT_OPUS_MODEL,
2732
+ ANTHROPIC_DEFAULT_SONNET_MODEL: env.ANTHROPIC_DEFAULT_SONNET_MODEL,
2733
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: env.ANTHROPIC_DEFAULT_HAIKU_MODEL,
2476
2734
  ANTHROPIC_MODEL: env.ANTHROPIC_MODEL,
2477
- ANTHROPIC_SMALL_FAST_MODEL: env.ANTHROPIC_SMALL_FAST_MODEL
2735
+ CLAUDE_CODE_SUBAGENT_MODEL: env.CLAUDE_CODE_SUBAGENT_MODEL
2478
2736
  }, defaultMode));
2479
2737
  console.log("");
2480
2738
  console.log(renderUsageLine(usageStats2, usageLoading2));
@@ -2482,7 +2740,7 @@ var showCurrentEnv = (usageStats2, usageLoading2) => {
2482
2740
  console.log("");
2483
2741
  };
2484
2742
  var switchEnvironment = async (name) => {
2485
- const registries = config2.get("registries");
2743
+ const registries = getRegistries();
2486
2744
  if (!registries[name]) {
2487
2745
  console.error(chalk7.red(`Environment '${name}' not found.`));
2488
2746
  return;
@@ -2495,11 +2753,7 @@ var switchEnvironment = async (name) => {
2495
2753
  }
2496
2754
  showCurrentEnv(null, false);
2497
2755
  const env = registries[name];
2498
- const exportCmds = [];
2499
- if (env.ANTHROPIC_BASE_URL) exportCmds.push(`export ANTHROPIC_BASE_URL="${env.ANTHROPIC_BASE_URL}"`);
2500
- if (env.ANTHROPIC_API_KEY) exportCmds.push(`export ANTHROPIC_API_KEY="${decrypt(env.ANTHROPIC_API_KEY)}"`);
2501
- if (env.ANTHROPIC_MODEL) exportCmds.push(`export ANTHROPIC_MODEL="${env.ANTHROPIC_MODEL}"`);
2502
- if (env.ANTHROPIC_SMALL_FAST_MODEL) exportCmds.push(`export ANTHROPIC_SMALL_FAST_MODEL="${env.ANTHROPIC_SMALL_FAST_MODEL}"`);
2756
+ const exportCmds = buildShellEnvCommands(env);
2503
2757
  if (process.stdout.isTTY) {
2504
2758
  console.log(chalk7.yellow("\nTo apply to current shell immediately, run:"));
2505
2759
  console.log(chalk7.cyan("eval $(ccem env)"));
@@ -2509,11 +2763,92 @@ var switchEnvironment = async (name) => {
2509
2763
  exportCmds.forEach((cmd) => console.log(cmd));
2510
2764
  }
2511
2765
  };
2766
+ var getSessionsFilePath = () => path6.join(getCcemConfigDir(), "sessions.json");
2767
+ var getRuntimeStateFilePath = () => path6.join(getCcemConfigDir(), "runtime-state.json");
2768
+ var parseJsonFile = (filePath) => {
2769
+ if (!fs8.existsSync(filePath)) {
2770
+ return null;
2771
+ }
2772
+ try {
2773
+ return JSON.parse(fs8.readFileSync(filePath, "utf-8"));
2774
+ } catch {
2775
+ return null;
2776
+ }
2777
+ };
2778
+ var readInteractiveAttachSessions = () => {
2779
+ const sessionsById = /* @__PURE__ */ new Map();
2780
+ const runtimeState = parseJsonFile(getRuntimeStateFilePath());
2781
+ const persistedSessions = parseJsonFile(getSessionsFilePath()) ?? [];
2782
+ for (const entry of runtimeState?.sessions ?? []) {
2783
+ if (entry.runtime_kind && entry.runtime_kind !== "interactive") {
2784
+ continue;
2785
+ }
2786
+ const fallback = persistedSessions.find((session) => session.id === entry.runtime_id);
2787
+ const tmuxTarget = entry.tmux_session && entry.tmux_window ? `${entry.tmux_session}:${entry.tmux_window}` : fallback?.window_id ?? null;
2788
+ if (!tmuxTarget) {
2789
+ continue;
2790
+ }
2791
+ sessionsById.set(entry.runtime_id, {
2792
+ id: entry.runtime_id,
2793
+ projectDir: entry.project_dir,
2794
+ envName: entry.env_name,
2795
+ permMode: entry.perm_mode,
2796
+ status: fallback?.status ?? "running",
2797
+ tmuxTarget,
2798
+ sortTime: entry.saved_at
2799
+ });
2800
+ }
2801
+ for (const session of persistedSessions) {
2802
+ if (session.status !== "running" || session.terminal_type !== "embedded" || !session.window_id) {
2803
+ continue;
2804
+ }
2805
+ if (sessionsById.has(session.id)) {
2806
+ continue;
2807
+ }
2808
+ sessionsById.set(session.id, {
2809
+ id: session.id,
2810
+ projectDir: session.working_dir,
2811
+ envName: session.env_name,
2812
+ permMode: session.perm_mode,
2813
+ status: session.status,
2814
+ tmuxTarget: session.window_id,
2815
+ sortTime: session.start_time
2816
+ });
2817
+ }
2818
+ return [...sessionsById.values()].sort(
2819
+ (left, right) => right.sortTime.localeCompare(left.sortTime)
2820
+ );
2821
+ };
2822
+ var findAttachSession = (id) => {
2823
+ const sessions = readInteractiveAttachSessions();
2824
+ if (!id) {
2825
+ return sessions[0];
2826
+ }
2827
+ const exact = sessions.find((session) => session.id === id);
2828
+ if (exact) {
2829
+ return exact;
2830
+ }
2831
+ return sessions.find((session) => session.id.startsWith(id));
2832
+ };
2833
+ var attachTmuxTarget = (target) => {
2834
+ const args = process.env.TMUX ? ["switch-client", "-t", target] : ["attach-session", "-t", target];
2835
+ return new Promise((resolve2, reject) => {
2836
+ const child = spawn3("tmux", args, { stdio: "inherit" });
2837
+ child.on("error", reject);
2838
+ child.on("exit", (code) => {
2839
+ if (code === 0 || code === null) {
2840
+ resolve2();
2841
+ } else {
2842
+ reject(new Error(`tmux exited with code ${code}`));
2843
+ }
2844
+ });
2845
+ });
2846
+ };
2512
2847
  program.command("ls").description("List all configured environments").action(() => {
2513
- const registries = config2.get("registries");
2848
+ const registries = getRegistries();
2514
2849
  const current = config2.get("current");
2515
2850
  const table = new Table3({
2516
- head: ["Name", "Base URL", "Model"],
2851
+ head: ["Name", "Base URL", "Opus"],
2517
2852
  style: { head: ["cyan"] }
2518
2853
  });
2519
2854
  Object.keys(registries).forEach((name) => {
@@ -2522,7 +2857,7 @@ program.command("ls").description("List all configured environments").action(()
2522
2857
  table.push([
2523
2858
  prefix + name,
2524
2859
  reg.ANTHROPIC_BASE_URL || "-",
2525
- reg.ANTHROPIC_MODEL || "-"
2860
+ reg.ANTHROPIC_DEFAULT_OPUS_MODEL || "-"
2526
2861
  ]);
2527
2862
  });
2528
2863
  console.log(table.toString());
@@ -2530,8 +2865,42 @@ program.command("ls").description("List all configured environments").action(()
2530
2865
  program.command("use <name>").description("Switch to a specific environment").action(async (name) => {
2531
2866
  await switchEnvironment(name);
2532
2867
  });
2868
+ program.command("sessions").description("List tmux-backed interactive sessions").action(() => {
2869
+ const sessions = readInteractiveAttachSessions();
2870
+ if (sessions.length === 0) {
2871
+ console.log(chalk7.yellow("No tmux-backed interactive sessions found."));
2872
+ return;
2873
+ }
2874
+ const table = new Table3({
2875
+ head: ["ID", "Project", "Env", "Status", "Tmux"],
2876
+ style: { head: ["cyan"] }
2877
+ });
2878
+ sessions.forEach((session) => {
2879
+ table.push([
2880
+ session.id,
2881
+ session.projectDir,
2882
+ session.envName,
2883
+ session.status,
2884
+ session.tmuxTarget
2885
+ ]);
2886
+ });
2887
+ console.log(table.toString());
2888
+ });
2889
+ program.command("attach [id]").description("Attach to a tmux-backed interactive session").action(async (id) => {
2890
+ const session = findAttachSession(id);
2891
+ if (!session) {
2892
+ console.error(chalk7.red(id ? `Interactive session '${id}' not found.` : "No interactive session available to attach."));
2893
+ process.exit(1);
2894
+ }
2895
+ try {
2896
+ await attachTmuxTarget(session.tmuxTarget);
2897
+ } catch (error) {
2898
+ console.error(chalk7.red(`Failed to attach ${session.tmuxTarget}: ${String(error)}`));
2899
+ process.exit(1);
2900
+ }
2901
+ });
2533
2902
  program.command("add <name>").description("Add a new environment configuration").action(async (name) => {
2534
- const registries = config2.get("registries");
2903
+ const registries = getRegistries();
2535
2904
  if (registries[name]) {
2536
2905
  console.log(chalk7.red(`Environment '${name}' already exists.`));
2537
2906
  return;
@@ -2556,40 +2925,13 @@ program.command("add <name>").description("Add a new environment configuration")
2556
2925
  ]);
2557
2926
  presetConfig = ENV_PRESETS[presetName];
2558
2927
  }
2559
- const answers = await inquirer.prompt([
2560
- {
2561
- type: "input",
2562
- name: "ANTHROPIC_BASE_URL",
2563
- message: "Enter ANTHROPIC_BASE_URL:",
2564
- default: presetConfig.ANTHROPIC_BASE_URL || "https://api.anthropic.com"
2565
- },
2566
- {
2567
- type: "password",
2568
- name: "ANTHROPIC_API_KEY",
2569
- message: "Enter ANTHROPIC_API_KEY:"
2570
- },
2571
- {
2572
- type: "input",
2573
- name: "ANTHROPIC_MODEL",
2574
- message: "Enter ANTHROPIC_MODEL:",
2575
- default: presetConfig.ANTHROPIC_MODEL || "claude-sonnet-4-5-20250929"
2576
- },
2577
- {
2578
- type: "input",
2579
- name: "ANTHROPIC_SMALL_FAST_MODEL",
2580
- message: "Enter ANTHROPIC_SMALL_FAST_MODEL:",
2581
- default: presetConfig.ANTHROPIC_SMALL_FAST_MODEL || "claude-haiku-4-5-20251001"
2582
- }
2583
- ]);
2584
- if (answers.ANTHROPIC_API_KEY) {
2585
- answers.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
2586
- }
2587
- registries[name] = answers;
2588
- config2.set("registries", registries);
2928
+ const answers = await promptForEnvironmentConfig(presetConfig);
2929
+ registries[name] = applyPromptAnswers(normalizeEnvConfig(presetConfig), answers, false);
2930
+ setRegistries(registries);
2589
2931
  console.log(chalk7.green(`Environment '${name}' added successfully.`));
2590
2932
  });
2591
2933
  program.command("del <name>").description("Delete an environment configuration").action((name) => {
2592
- const registries = config2.get("registries");
2934
+ const registries = getRegistries();
2593
2935
  if (!registries[name]) {
2594
2936
  console.log(chalk7.red(`Environment '${name}' not found.`));
2595
2937
  return;
@@ -2599,7 +2941,7 @@ program.command("del <name>").description("Delete an environment configuration")
2599
2941
  return;
2600
2942
  }
2601
2943
  delete registries[name];
2602
- config2.set("registries", registries);
2944
+ setRegistries(registries);
2603
2945
  const current = config2.get("current");
2604
2946
  if (current === name) {
2605
2947
  config2.set("current", "official");
@@ -2608,7 +2950,7 @@ program.command("del <name>").description("Delete an environment configuration")
2608
2950
  console.log(chalk7.green(`Environment '${name}' deleted.`));
2609
2951
  });
2610
2952
  program.command("rename <old> <new>").description("Rename an environment configuration").action((oldName, newName) => {
2611
- const registries = config2.get("registries");
2953
+ const registries = getRegistries();
2612
2954
  if (!registries[oldName]) {
2613
2955
  console.log(chalk7.red(`Environment '${oldName}' not found.`));
2614
2956
  return;
@@ -2623,7 +2965,7 @@ program.command("rename <old> <new>").description("Rename an environment configu
2623
2965
  }
2624
2966
  registries[newName] = registries[oldName];
2625
2967
  delete registries[oldName];
2626
- config2.set("registries", registries);
2968
+ setRegistries(registries);
2627
2969
  const current = config2.get("current");
2628
2970
  if (current === oldName) {
2629
2971
  config2.set("current", newName);
@@ -2631,7 +2973,7 @@ program.command("rename <old> <new>").description("Rename an environment configu
2631
2973
  console.log(chalk7.green(`Environment '${oldName}' renamed to '${newName}'.`));
2632
2974
  });
2633
2975
  program.command("cp <source> <target>").description("Copy an environment configuration").action(async (source, target) => {
2634
- const registries = config2.get("registries");
2976
+ const registries = getRegistries();
2635
2977
  if (!registries[source]) {
2636
2978
  console.log(chalk7.red(`Environment '${source}' not found.`));
2637
2979
  return;
@@ -2641,7 +2983,7 @@ program.command("cp <source> <target>").description("Copy an environment configu
2641
2983
  return;
2642
2984
  }
2643
2985
  registries[target] = { ...registries[source] };
2644
- config2.set("registries", registries);
2986
+ setRegistries(registries);
2645
2987
  console.log(chalk7.green(`Environment '${source}' copied to '${target}'.`));
2646
2988
  const { modify } = await inquirer.prompt([
2647
2989
  {
@@ -2653,37 +2995,9 @@ program.command("cp <source> <target>").description("Copy an environment configu
2653
2995
  ]);
2654
2996
  if (modify) {
2655
2997
  const current = registries[target];
2656
- const answers = await inquirer.prompt([
2657
- {
2658
- type: "input",
2659
- name: "ANTHROPIC_BASE_URL",
2660
- message: "ANTHROPIC_BASE_URL:",
2661
- default: current.ANTHROPIC_BASE_URL
2662
- },
2663
- {
2664
- type: "password",
2665
- name: "ANTHROPIC_API_KEY",
2666
- message: "ANTHROPIC_API_KEY (leave empty to keep current):"
2667
- },
2668
- {
2669
- type: "input",
2670
- name: "ANTHROPIC_MODEL",
2671
- message: "ANTHROPIC_MODEL:",
2672
- default: current.ANTHROPIC_MODEL
2673
- },
2674
- {
2675
- type: "input",
2676
- name: "ANTHROPIC_SMALL_FAST_MODEL",
2677
- message: "ANTHROPIC_SMALL_FAST_MODEL:",
2678
- default: current.ANTHROPIC_SMALL_FAST_MODEL
2679
- }
2680
- ]);
2681
- if (answers.ANTHROPIC_BASE_URL) current.ANTHROPIC_BASE_URL = answers.ANTHROPIC_BASE_URL;
2682
- if (answers.ANTHROPIC_API_KEY) current.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
2683
- if (answers.ANTHROPIC_MODEL) current.ANTHROPIC_MODEL = answers.ANTHROPIC_MODEL;
2684
- if (answers.ANTHROPIC_SMALL_FAST_MODEL) current.ANTHROPIC_SMALL_FAST_MODEL = answers.ANTHROPIC_SMALL_FAST_MODEL;
2685
- registries[target] = current;
2686
- config2.set("registries", registries);
2998
+ const answers = await promptForEnvironmentConfig(current, true);
2999
+ registries[target] = applyPromptAnswers(current, answers, true);
3000
+ setRegistries(registries);
2687
3001
  console.log(chalk7.green(`Environment '${target}' updated.`));
2688
3002
  }
2689
3003
  });
@@ -2692,25 +3006,22 @@ program.command("current").description("Show current environment name").action((
2692
3006
  console.log(chalk7.green(current));
2693
3007
  });
2694
3008
  program.command("env").description("Output environment variables for shell eval").option("--json", "Output as JSON").action((options) => {
2695
- const registries = config2.get("registries");
3009
+ const registries = getRegistries();
2696
3010
  const current = config2.get("current");
2697
3011
  const env = registries[current];
2698
3012
  if (!env) return;
2699
3013
  const outputEnv = { ...env };
2700
- if (outputEnv.ANTHROPIC_API_KEY) {
2701
- outputEnv.ANTHROPIC_API_KEY = decrypt(outputEnv.ANTHROPIC_API_KEY);
3014
+ if (outputEnv.ANTHROPIC_AUTH_TOKEN) {
3015
+ outputEnv.ANTHROPIC_AUTH_TOKEN = decrypt(outputEnv.ANTHROPIC_AUTH_TOKEN);
2702
3016
  }
2703
3017
  if (options.json) {
2704
3018
  console.log(JSON.stringify(outputEnv, null, 2));
2705
3019
  } else {
2706
- if (outputEnv.ANTHROPIC_BASE_URL) console.log(`export ANTHROPIC_BASE_URL="${outputEnv.ANTHROPIC_BASE_URL}"`);
2707
- if (outputEnv.ANTHROPIC_API_KEY) console.log(`export ANTHROPIC_API_KEY="${outputEnv.ANTHROPIC_API_KEY}"`);
2708
- if (outputEnv.ANTHROPIC_MODEL) console.log(`export ANTHROPIC_MODEL="${outputEnv.ANTHROPIC_MODEL}"`);
2709
- if (outputEnv.ANTHROPIC_SMALL_FAST_MODEL) console.log(`export ANTHROPIC_SMALL_FAST_MODEL="${outputEnv.ANTHROPIC_SMALL_FAST_MODEL}"`);
3020
+ buildShellEnvCommands(env).forEach((cmd) => console.log(cmd));
2710
3021
  }
2711
3022
  });
2712
3023
  program.command("run <command...>").description("Run a command with the current environment variables").action((command) => {
2713
- const registries = config2.get("registries");
3024
+ const registries = getRegistries();
2714
3025
  const current = config2.get("current");
2715
3026
  const envConfig = registries[current];
2716
3027
  if (!envConfig) {
@@ -2718,10 +3029,8 @@ program.command("run <command...>").description("Run a command with the current
2718
3029
  process.exit(1);
2719
3030
  }
2720
3031
  const env = { ...process.env };
2721
- if (envConfig.ANTHROPIC_BASE_URL) env.ANTHROPIC_BASE_URL = envConfig.ANTHROPIC_BASE_URL;
2722
- if (envConfig.ANTHROPIC_API_KEY) env.ANTHROPIC_API_KEY = decrypt(envConfig.ANTHROPIC_API_KEY || "");
2723
- if (envConfig.ANTHROPIC_MODEL) env.ANTHROPIC_MODEL = envConfig.ANTHROPIC_MODEL;
2724
- if (envConfig.ANTHROPIC_SMALL_FAST_MODEL) env.ANTHROPIC_SMALL_FAST_MODEL = envConfig.ANTHROPIC_SMALL_FAST_MODEL;
3032
+ clearManagedClaudeEnv(env);
3033
+ Object.assign(env, buildResolvedEnvVars(envConfig));
2725
3034
  const [cmd, ...args] = command;
2726
3035
  const child = spawn3(cmd, args, {
2727
3036
  env,
@@ -2907,7 +3216,7 @@ program.command("load <url>").description("\u4ECE\u8FDC\u7A0B\u670D\u52A1\u5668\
2907
3216
  program.command("launch").description(false).option("--env <name>", "\u73AF\u5883\u540D\u79F0").option("--perm <mode>", "\u6743\u9650\u6A21\u5F0F").option("--session-id <id>", "\u4F1A\u8BDD ID").option("--resume-session <id>", "\u6062\u590D\u4F1A\u8BDD ID").option("--working-dir <path>", "\u5DE5\u4F5C\u76EE\u5F55").option("--proxy-base-url <url>", "Desktop internal override for ANTHROPIC_BASE_URL").option("--anthropic-base-url <url>", "Deprecated alias for --proxy-base-url").action(async function() {
2908
3217
  const opts = this.opts();
2909
3218
  const envName = opts.env || config2.get("current");
2910
- const registries = config2.get("registries");
3219
+ const registries = getRegistries();
2911
3220
  const envConfig = registries[envName];
2912
3221
  if (!envConfig) {
2913
3222
  console.error(chalk7.red(`Environment '${envName}' not found.`));
@@ -2952,7 +3261,7 @@ program.action(async (options) => {
2952
3261
  showCurrentEnv(usageStats, usageLoading);
2953
3262
  console.log("");
2954
3263
  const defaultMode = config2.get("defaultMode");
2955
- const registries = config2.get("registries");
3264
+ const registries = getRegistries();
2956
3265
  const current = config2.get("current");
2957
3266
  const envConfig = registries[current];
2958
3267
  const { action } = await inquirer.prompt([
@@ -2999,37 +3308,9 @@ program.action(async (options) => {
2999
3308
  const envToEdit = registries[result.name];
3000
3309
  console.log(chalk7.yellow(`
3001
3310
  Editing environment '${result.name}'`));
3002
- const answers = await inquirer.prompt([
3003
- {
3004
- type: "input",
3005
- name: "ANTHROPIC_BASE_URL",
3006
- message: "ANTHROPIC_BASE_URL:",
3007
- default: envToEdit.ANTHROPIC_BASE_URL
3008
- },
3009
- {
3010
- type: "password",
3011
- name: "ANTHROPIC_API_KEY",
3012
- message: "ANTHROPIC_API_KEY (leave empty to keep current):"
3013
- },
3014
- {
3015
- type: "input",
3016
- name: "ANTHROPIC_MODEL",
3017
- message: "ANTHROPIC_MODEL:",
3018
- default: envToEdit.ANTHROPIC_MODEL
3019
- },
3020
- {
3021
- type: "input",
3022
- name: "ANTHROPIC_SMALL_FAST_MODEL",
3023
- message: "ANTHROPIC_SMALL_FAST_MODEL:",
3024
- default: envToEdit.ANTHROPIC_SMALL_FAST_MODEL
3025
- }
3026
- ]);
3027
- if (answers.ANTHROPIC_BASE_URL) envToEdit.ANTHROPIC_BASE_URL = answers.ANTHROPIC_BASE_URL;
3028
- if (answers.ANTHROPIC_API_KEY) envToEdit.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
3029
- if (answers.ANTHROPIC_MODEL) envToEdit.ANTHROPIC_MODEL = answers.ANTHROPIC_MODEL;
3030
- if (answers.ANTHROPIC_SMALL_FAST_MODEL) envToEdit.ANTHROPIC_SMALL_FAST_MODEL = answers.ANTHROPIC_SMALL_FAST_MODEL;
3031
- registries[result.name] = envToEdit;
3032
- config2.set("registries", registries);
3311
+ const answers = await promptForEnvironmentConfig(envToEdit, true);
3312
+ registries[result.name] = applyPromptAnswers(envToEdit, answers, true);
3313
+ setRegistries(registries);
3033
3314
  msg.success(`Environment '${result.name}' updated.`);
3034
3315
  await new Promise((resolve2) => setTimeout(resolve2, 800));
3035
3316
  } else if (result.action === "rename") {
@@ -3051,7 +3332,7 @@ Editing environment '${result.name}'`));
3051
3332
  ]);
3052
3333
  registries[newName] = registries[result.name];
3053
3334
  delete registries[result.name];
3054
- config2.set("registries", registries);
3335
+ setRegistries(registries);
3055
3336
  if (current === result.name) {
3056
3337
  config2.set("current", newName);
3057
3338
  }
@@ -3072,7 +3353,7 @@ Editing environment '${result.name}'`));
3072
3353
  }
3073
3354
  ]);
3074
3355
  registries[targetName] = { ...registries[result.name] };
3075
- config2.set("registries", registries);
3356
+ setRegistries(registries);
3076
3357
  msg.success(`Environment '${result.name}' copied to '${targetName}'.`);
3077
3358
  const { modify } = await inquirer.prompt([
3078
3359
  {
@@ -3084,37 +3365,9 @@ Editing environment '${result.name}'`));
3084
3365
  ]);
3085
3366
  if (modify) {
3086
3367
  const envToEdit = registries[targetName];
3087
- const editAnswers = await inquirer.prompt([
3088
- {
3089
- type: "input",
3090
- name: "ANTHROPIC_BASE_URL",
3091
- message: "ANTHROPIC_BASE_URL:",
3092
- default: envToEdit.ANTHROPIC_BASE_URL
3093
- },
3094
- {
3095
- type: "password",
3096
- name: "ANTHROPIC_API_KEY",
3097
- message: "ANTHROPIC_API_KEY (leave empty to keep current):"
3098
- },
3099
- {
3100
- type: "input",
3101
- name: "ANTHROPIC_MODEL",
3102
- message: "ANTHROPIC_MODEL:",
3103
- default: envToEdit.ANTHROPIC_MODEL
3104
- },
3105
- {
3106
- type: "input",
3107
- name: "ANTHROPIC_SMALL_FAST_MODEL",
3108
- message: "ANTHROPIC_SMALL_FAST_MODEL:",
3109
- default: envToEdit.ANTHROPIC_SMALL_FAST_MODEL
3110
- }
3111
- ]);
3112
- if (editAnswers.ANTHROPIC_BASE_URL) envToEdit.ANTHROPIC_BASE_URL = editAnswers.ANTHROPIC_BASE_URL;
3113
- if (editAnswers.ANTHROPIC_API_KEY) envToEdit.ANTHROPIC_API_KEY = encrypt(editAnswers.ANTHROPIC_API_KEY);
3114
- if (editAnswers.ANTHROPIC_MODEL) envToEdit.ANTHROPIC_MODEL = editAnswers.ANTHROPIC_MODEL;
3115
- if (editAnswers.ANTHROPIC_SMALL_FAST_MODEL) envToEdit.ANTHROPIC_SMALL_FAST_MODEL = editAnswers.ANTHROPIC_SMALL_FAST_MODEL;
3116
- registries[targetName] = envToEdit;
3117
- config2.set("registries", registries);
3368
+ const editAnswers = await promptForEnvironmentConfig(envToEdit, true);
3369
+ registries[targetName] = applyPromptAnswers(envToEdit, editAnswers, true);
3370
+ setRegistries(registries);
3118
3371
  msg.success(`Environment '${targetName}' updated.`);
3119
3372
  }
3120
3373
  await new Promise((resolve2) => setTimeout(resolve2, 800));
@@ -3133,7 +3386,7 @@ Editing environment '${result.name}'`));
3133
3386
  ]);
3134
3387
  if (confirm) {
3135
3388
  delete registries[result.name];
3136
- config2.set("registries", registries);
3389
+ setRegistries(registries);
3137
3390
  if (current === result.name) {
3138
3391
  config2.set("current", "official");
3139
3392
  msg.warning(`Deleted current environment. Switched back to 'official'.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccem",
3
- "version": "2.0.0-beta.3",
3
+ "version": "2.0.0-beta.6",
4
4
  "type": "module",
5
5
  "description": "Claude Code Environment Manager",
6
6
  "author": {