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.
- package/dist/index.js +439 -186
- 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-
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
24
|
-
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
34
|
-
|
|
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
|
|
818
|
-
const
|
|
819
|
-
const
|
|
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("
|
|
842
|
-
theme.muted("
|
|
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("
|
|
849
|
-
theme.muted("
|
|
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.
|
|
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.
|
|
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
|
|
2232
|
-
|
|
2233
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
2848
|
+
const registries = getRegistries();
|
|
2514
2849
|
const current = config2.get("current");
|
|
2515
2850
|
const table = new Table3({
|
|
2516
|
-
head: ["Name", "Base URL", "
|
|
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.
|
|
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 =
|
|
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
|
|
2560
|
-
|
|
2561
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
2657
|
-
|
|
2658
|
-
|
|
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 =
|
|
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.
|
|
2701
|
-
outputEnv.
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
2722
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
3003
|
-
|
|
3004
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3088
|
-
|
|
3089
|
-
|
|
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
|
-
|
|
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'.`);
|