ccem 2.0.0-beta.2 → 2.0.0-beta.5
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 +473 -196
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9,29 +9,111 @@ import Table3 from "cli-table3";
|
|
|
9
9
|
import { spawn as spawn3 } from "child_process";
|
|
10
10
|
import * as fs8 from "fs";
|
|
11
11
|
import * as path6 from "path";
|
|
12
|
-
import { fileURLToPath } from "url";
|
|
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 = {
|
|
@@ -338,6 +420,9 @@ import * as fsPromises from "fs/promises";
|
|
|
338
420
|
import * as path2 from "path";
|
|
339
421
|
import * as os from "os";
|
|
340
422
|
import * as readline from "readline";
|
|
423
|
+
import { fileURLToPath } from "url";
|
|
424
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
425
|
+
var __dirname = path2.dirname(__filename);
|
|
341
426
|
var CLAUDE_PROJECTS_DIR = path2.join(os.homedir(), ".claude", "projects");
|
|
342
427
|
var CCEM_DIR = path2.join(os.homedir(), ".ccem");
|
|
343
428
|
var CACHE_VERSION = 1;
|
|
@@ -811,9 +896,10 @@ var renderLogoWithEnvPanel = (envName, env, defaultMode) => {
|
|
|
811
896
|
const titleShort = theme.primary("CCEM");
|
|
812
897
|
const envLabel = theme.muted("Env: ") + theme.primary(envName);
|
|
813
898
|
const baseUrl = env.ANTHROPIC_BASE_URL || "-";
|
|
814
|
-
const
|
|
815
|
-
const
|
|
816
|
-
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) : "-";
|
|
817
903
|
const truncate = (s, max) => s.length > max ? s.slice(0, max - 3) + "..." : s;
|
|
818
904
|
const maskUrl = (url, max) => {
|
|
819
905
|
if (url.length <= max) return url;
|
|
@@ -835,15 +921,15 @@ var renderLogoWithEnvPanel = (envName, env, defaultMode) => {
|
|
|
835
921
|
if (isNarrow) {
|
|
836
922
|
envLines = [
|
|
837
923
|
envLabel,
|
|
838
|
-
theme.muted("
|
|
839
|
-
theme.muted("
|
|
924
|
+
theme.muted("Opus:".padEnd(labelWidth)) + theme.dim(truncate(opusModel, 25)),
|
|
925
|
+
theme.muted("Token:".padEnd(labelWidth)) + theme.dim(authToken)
|
|
840
926
|
];
|
|
841
927
|
} else {
|
|
842
928
|
envLines = [
|
|
843
929
|
envLabel + (defaultMode && PERMISSION_PRESETS[defaultMode] ? " " + theme.accent(`[${PERMISSION_PRESETS[defaultMode].name}]`) : ""),
|
|
844
930
|
theme.muted("URL:".padEnd(labelWidth)) + theme.dim(maskUrl(baseUrl, 40)),
|
|
845
|
-
theme.muted("
|
|
846
|
-
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)
|
|
847
933
|
];
|
|
848
934
|
}
|
|
849
935
|
const lines = [];
|
|
@@ -1318,12 +1404,26 @@ import { spawn } from "child_process";
|
|
|
1318
1404
|
import * as fs4 from "fs";
|
|
1319
1405
|
import * as path4 from "path";
|
|
1320
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
|
+
];
|
|
1321
1418
|
function buildEnvVars(envConfig) {
|
|
1322
1419
|
const vars = {};
|
|
1323
1420
|
if (envConfig.ANTHROPIC_BASE_URL) vars.ANTHROPIC_BASE_URL = envConfig.ANTHROPIC_BASE_URL;
|
|
1324
|
-
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;
|
|
1325
1425
|
if (envConfig.ANTHROPIC_MODEL) vars.ANTHROPIC_MODEL = envConfig.ANTHROPIC_MODEL;
|
|
1326
|
-
if (envConfig.
|
|
1426
|
+
if (envConfig.CLAUDE_CODE_SUBAGENT_MODEL) vars.CLAUDE_CODE_SUBAGENT_MODEL = envConfig.CLAUDE_CODE_SUBAGENT_MODEL;
|
|
1327
1427
|
return vars;
|
|
1328
1428
|
}
|
|
1329
1429
|
function buildPermArgs(modeName) {
|
|
@@ -1350,6 +1450,9 @@ function ensureSessionsDir() {
|
|
|
1350
1450
|
async function launchClaude(options) {
|
|
1351
1451
|
const { envConfig, permMode, workingDir, sessionId, resumeSessionId, silent } = options;
|
|
1352
1452
|
const env = { ...process.env };
|
|
1453
|
+
for (const key of MANAGED_CLAUDE_ENV_KEYS) {
|
|
1454
|
+
delete env[key];
|
|
1455
|
+
}
|
|
1353
1456
|
if (envConfig) {
|
|
1354
1457
|
Object.assign(env, buildEnvVars(envConfig));
|
|
1355
1458
|
}
|
|
@@ -1379,7 +1482,8 @@ async function launchClaude(options) {
|
|
|
1379
1482
|
return new Promise((resolve2) => {
|
|
1380
1483
|
const child = spawn("claude", args, {
|
|
1381
1484
|
stdio: "inherit",
|
|
1382
|
-
shell:
|
|
1485
|
+
shell: false,
|
|
1486
|
+
// 直接执行二进制,避免 shell 注入风险
|
|
1383
1487
|
env
|
|
1384
1488
|
});
|
|
1385
1489
|
child.on("exit", (code) => {
|
|
@@ -2143,7 +2247,9 @@ import crypto3 from "crypto";
|
|
|
2143
2247
|
import chalk6 from "chalk";
|
|
2144
2248
|
import Conf from "conf";
|
|
2145
2249
|
var config = new Conf({
|
|
2146
|
-
projectName: "claude-code-env-manager"
|
|
2250
|
+
projectName: "claude-code-env-manager",
|
|
2251
|
+
cwd: getCcemConfigDir()
|
|
2252
|
+
// 使用统一的配置目录
|
|
2147
2253
|
});
|
|
2148
2254
|
var decryptWithSecret = (encryptedBase64, secret) => {
|
|
2149
2255
|
const key = crypto3.scryptSync(secret, "ccem-salt", 32);
|
|
@@ -2171,7 +2277,11 @@ var loadFromRemote = async (url, secret) => {
|
|
|
2171
2277
|
console.log(chalk6.gray("Fetching from remote..."));
|
|
2172
2278
|
let response;
|
|
2173
2279
|
try {
|
|
2174
|
-
response = await fetch(url
|
|
2280
|
+
response = await fetch(url, {
|
|
2281
|
+
headers: {
|
|
2282
|
+
"X-CCEM-Key": secret
|
|
2283
|
+
}
|
|
2284
|
+
});
|
|
2175
2285
|
} catch (err) {
|
|
2176
2286
|
console.error(chalk6.red("Error: Failed to connect to server"));
|
|
2177
2287
|
console.error(chalk6.gray(err.message));
|
|
@@ -2218,9 +2328,10 @@ var loadFromRemote = async (url, secret) => {
|
|
|
2218
2328
|
for (const [name, envConfig] of Object.entries(decrypted.environments)) {
|
|
2219
2329
|
const uniqueName = getUniqueName(name, existingNames);
|
|
2220
2330
|
const renamed = uniqueName !== name;
|
|
2221
|
-
const
|
|
2222
|
-
|
|
2223
|
-
|
|
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);
|
|
2224
2335
|
}
|
|
2225
2336
|
registries[uniqueName] = configToSave;
|
|
2226
2337
|
existingNames.add(uniqueName);
|
|
@@ -2241,6 +2352,7 @@ Loaded ${results.length} environment(s) from remote:`));
|
|
|
2241
2352
|
}
|
|
2242
2353
|
}
|
|
2243
2354
|
console.log(chalk6.gray("\nRun 'ccem ls' to see all environments."));
|
|
2355
|
+
return results;
|
|
2244
2356
|
};
|
|
2245
2357
|
|
|
2246
2358
|
// src/cron-skill.ts
|
|
@@ -2386,11 +2498,52 @@ Replace \\\`TARGET_ID\\\` or \\\`TARGET_NAME\\\` with the user's selection.
|
|
|
2386
2498
|
`;
|
|
2387
2499
|
|
|
2388
2500
|
// src/index.ts
|
|
2389
|
-
var
|
|
2390
|
-
var __dirname2 = path6.dirname(
|
|
2501
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
2502
|
+
var __dirname2 = path6.dirname(__filename2);
|
|
2391
2503
|
var pkgPath = path6.resolve(__dirname2, "..", "package.json");
|
|
2392
2504
|
var pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
2393
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
|
+
};
|
|
2394
2547
|
ensureCcemDir();
|
|
2395
2548
|
var config2 = new Conf2({
|
|
2396
2549
|
projectName: "claude-code-env-manager",
|
|
@@ -2398,16 +2551,129 @@ var config2 = new Conf2({
|
|
|
2398
2551
|
// 使用新路径
|
|
2399
2552
|
defaults: {
|
|
2400
2553
|
registries: {
|
|
2401
|
-
|
|
2402
|
-
ANTHROPIC_BASE_URL: "https://api.anthropic.com",
|
|
2403
|
-
ANTHROPIC_MODEL: "claude-sonnet-4-5-20250929",
|
|
2404
|
-
ANTHROPIC_SMALL_FAST_MODEL: "claude-haiku-4-5-20251001"
|
|
2405
|
-
}
|
|
2554
|
+
official: DEFAULT_OFFICIAL_ENV
|
|
2406
2555
|
},
|
|
2407
2556
|
current: "official",
|
|
2408
2557
|
defaultMode: null
|
|
2409
2558
|
}
|
|
2410
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
|
+
};
|
|
2411
2677
|
var PERMISSION_MODES = ["yolo", "dev", "readonly", "safe", "ci", "audit"];
|
|
2412
2678
|
var usageStats = null;
|
|
2413
2679
|
var usageLoading = true;
|
|
@@ -2446,7 +2712,7 @@ program.name("ccem").description("Claude Code Environment Manager - \u7BA1\u7406
|
|
|
2446
2712
|
PERMISSION_MODES.forEach((mode) => {
|
|
2447
2713
|
const preset = PERMISSION_PRESETS[mode];
|
|
2448
2714
|
program.command(mode).description(`\u4E34\u65F6\u5E94\u7528 ${preset.name}\uFF0C\u9000\u51FA\u540E\u8FD8\u539F`).action(async () => {
|
|
2449
|
-
const registries =
|
|
2715
|
+
const registries = getRegistries();
|
|
2450
2716
|
const current = config2.get("current");
|
|
2451
2717
|
const envConfig = registries[current];
|
|
2452
2718
|
await runWithTempPermissions(mode, envConfig);
|
|
@@ -2455,15 +2721,18 @@ PERMISSION_MODES.forEach((mode) => {
|
|
|
2455
2721
|
var showCurrentEnv = (usageStats2, usageLoading2) => {
|
|
2456
2722
|
if (!process.stdout.isTTY) return;
|
|
2457
2723
|
const current = config2.get("current");
|
|
2458
|
-
const registries =
|
|
2724
|
+
const registries = getRegistries();
|
|
2459
2725
|
const env = registries[current];
|
|
2460
2726
|
const defaultMode = config2.get("defaultMode");
|
|
2461
2727
|
if (!env) return;
|
|
2462
2728
|
console.log(renderLogoWithEnvPanel(current, {
|
|
2463
2729
|
ANTHROPIC_BASE_URL: env.ANTHROPIC_BASE_URL,
|
|
2464
|
-
|
|
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,
|
|
2465
2734
|
ANTHROPIC_MODEL: env.ANTHROPIC_MODEL,
|
|
2466
|
-
|
|
2735
|
+
CLAUDE_CODE_SUBAGENT_MODEL: env.CLAUDE_CODE_SUBAGENT_MODEL
|
|
2467
2736
|
}, defaultMode));
|
|
2468
2737
|
console.log("");
|
|
2469
2738
|
console.log(renderUsageLine(usageStats2, usageLoading2));
|
|
@@ -2471,7 +2740,7 @@ var showCurrentEnv = (usageStats2, usageLoading2) => {
|
|
|
2471
2740
|
console.log("");
|
|
2472
2741
|
};
|
|
2473
2742
|
var switchEnvironment = async (name) => {
|
|
2474
|
-
const registries =
|
|
2743
|
+
const registries = getRegistries();
|
|
2475
2744
|
if (!registries[name]) {
|
|
2476
2745
|
console.error(chalk7.red(`Environment '${name}' not found.`));
|
|
2477
2746
|
return;
|
|
@@ -2484,11 +2753,7 @@ var switchEnvironment = async (name) => {
|
|
|
2484
2753
|
}
|
|
2485
2754
|
showCurrentEnv(null, false);
|
|
2486
2755
|
const env = registries[name];
|
|
2487
|
-
const exportCmds =
|
|
2488
|
-
if (env.ANTHROPIC_BASE_URL) exportCmds.push(`export ANTHROPIC_BASE_URL="${env.ANTHROPIC_BASE_URL}"`);
|
|
2489
|
-
if (env.ANTHROPIC_API_KEY) exportCmds.push(`export ANTHROPIC_API_KEY="${decrypt(env.ANTHROPIC_API_KEY)}"`);
|
|
2490
|
-
if (env.ANTHROPIC_MODEL) exportCmds.push(`export ANTHROPIC_MODEL="${env.ANTHROPIC_MODEL}"`);
|
|
2491
|
-
if (env.ANTHROPIC_SMALL_FAST_MODEL) exportCmds.push(`export ANTHROPIC_SMALL_FAST_MODEL="${env.ANTHROPIC_SMALL_FAST_MODEL}"`);
|
|
2756
|
+
const exportCmds = buildShellEnvCommands(env);
|
|
2492
2757
|
if (process.stdout.isTTY) {
|
|
2493
2758
|
console.log(chalk7.yellow("\nTo apply to current shell immediately, run:"));
|
|
2494
2759
|
console.log(chalk7.cyan("eval $(ccem env)"));
|
|
@@ -2498,11 +2763,92 @@ var switchEnvironment = async (name) => {
|
|
|
2498
2763
|
exportCmds.forEach((cmd) => console.log(cmd));
|
|
2499
2764
|
}
|
|
2500
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
|
+
};
|
|
2501
2847
|
program.command("ls").description("List all configured environments").action(() => {
|
|
2502
|
-
const registries =
|
|
2848
|
+
const registries = getRegistries();
|
|
2503
2849
|
const current = config2.get("current");
|
|
2504
2850
|
const table = new Table3({
|
|
2505
|
-
head: ["Name", "Base URL", "
|
|
2851
|
+
head: ["Name", "Base URL", "Opus"],
|
|
2506
2852
|
style: { head: ["cyan"] }
|
|
2507
2853
|
});
|
|
2508
2854
|
Object.keys(registries).forEach((name) => {
|
|
@@ -2511,7 +2857,7 @@ program.command("ls").description("List all configured environments").action(()
|
|
|
2511
2857
|
table.push([
|
|
2512
2858
|
prefix + name,
|
|
2513
2859
|
reg.ANTHROPIC_BASE_URL || "-",
|
|
2514
|
-
reg.
|
|
2860
|
+
reg.ANTHROPIC_DEFAULT_OPUS_MODEL || "-"
|
|
2515
2861
|
]);
|
|
2516
2862
|
});
|
|
2517
2863
|
console.log(table.toString());
|
|
@@ -2519,8 +2865,42 @@ program.command("ls").description("List all configured environments").action(()
|
|
|
2519
2865
|
program.command("use <name>").description("Switch to a specific environment").action(async (name) => {
|
|
2520
2866
|
await switchEnvironment(name);
|
|
2521
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
|
+
});
|
|
2522
2902
|
program.command("add <name>").description("Add a new environment configuration").action(async (name) => {
|
|
2523
|
-
const registries =
|
|
2903
|
+
const registries = getRegistries();
|
|
2524
2904
|
if (registries[name]) {
|
|
2525
2905
|
console.log(chalk7.red(`Environment '${name}' already exists.`));
|
|
2526
2906
|
return;
|
|
@@ -2545,40 +2925,13 @@ program.command("add <name>").description("Add a new environment configuration")
|
|
|
2545
2925
|
]);
|
|
2546
2926
|
presetConfig = ENV_PRESETS[presetName];
|
|
2547
2927
|
}
|
|
2548
|
-
const answers = await
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
name: "ANTHROPIC_BASE_URL",
|
|
2552
|
-
message: "Enter ANTHROPIC_BASE_URL:",
|
|
2553
|
-
default: presetConfig.ANTHROPIC_BASE_URL || "https://api.anthropic.com"
|
|
2554
|
-
},
|
|
2555
|
-
{
|
|
2556
|
-
type: "password",
|
|
2557
|
-
name: "ANTHROPIC_API_KEY",
|
|
2558
|
-
message: "Enter ANTHROPIC_API_KEY:"
|
|
2559
|
-
},
|
|
2560
|
-
{
|
|
2561
|
-
type: "input",
|
|
2562
|
-
name: "ANTHROPIC_MODEL",
|
|
2563
|
-
message: "Enter ANTHROPIC_MODEL:",
|
|
2564
|
-
default: presetConfig.ANTHROPIC_MODEL || "claude-sonnet-4-5-20250929"
|
|
2565
|
-
},
|
|
2566
|
-
{
|
|
2567
|
-
type: "input",
|
|
2568
|
-
name: "ANTHROPIC_SMALL_FAST_MODEL",
|
|
2569
|
-
message: "Enter ANTHROPIC_SMALL_FAST_MODEL:",
|
|
2570
|
-
default: presetConfig.ANTHROPIC_SMALL_FAST_MODEL || "claude-haiku-4-5-20251001"
|
|
2571
|
-
}
|
|
2572
|
-
]);
|
|
2573
|
-
if (answers.ANTHROPIC_API_KEY) {
|
|
2574
|
-
answers.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
|
|
2575
|
-
}
|
|
2576
|
-
registries[name] = answers;
|
|
2577
|
-
config2.set("registries", registries);
|
|
2928
|
+
const answers = await promptForEnvironmentConfig(presetConfig);
|
|
2929
|
+
registries[name] = applyPromptAnswers(normalizeEnvConfig(presetConfig), answers, false);
|
|
2930
|
+
setRegistries(registries);
|
|
2578
2931
|
console.log(chalk7.green(`Environment '${name}' added successfully.`));
|
|
2579
2932
|
});
|
|
2580
2933
|
program.command("del <name>").description("Delete an environment configuration").action((name) => {
|
|
2581
|
-
const registries =
|
|
2934
|
+
const registries = getRegistries();
|
|
2582
2935
|
if (!registries[name]) {
|
|
2583
2936
|
console.log(chalk7.red(`Environment '${name}' not found.`));
|
|
2584
2937
|
return;
|
|
@@ -2588,7 +2941,7 @@ program.command("del <name>").description("Delete an environment configuration")
|
|
|
2588
2941
|
return;
|
|
2589
2942
|
}
|
|
2590
2943
|
delete registries[name];
|
|
2591
|
-
|
|
2944
|
+
setRegistries(registries);
|
|
2592
2945
|
const current = config2.get("current");
|
|
2593
2946
|
if (current === name) {
|
|
2594
2947
|
config2.set("current", "official");
|
|
@@ -2597,7 +2950,7 @@ program.command("del <name>").description("Delete an environment configuration")
|
|
|
2597
2950
|
console.log(chalk7.green(`Environment '${name}' deleted.`));
|
|
2598
2951
|
});
|
|
2599
2952
|
program.command("rename <old> <new>").description("Rename an environment configuration").action((oldName, newName) => {
|
|
2600
|
-
const registries =
|
|
2953
|
+
const registries = getRegistries();
|
|
2601
2954
|
if (!registries[oldName]) {
|
|
2602
2955
|
console.log(chalk7.red(`Environment '${oldName}' not found.`));
|
|
2603
2956
|
return;
|
|
@@ -2612,7 +2965,7 @@ program.command("rename <old> <new>").description("Rename an environment configu
|
|
|
2612
2965
|
}
|
|
2613
2966
|
registries[newName] = registries[oldName];
|
|
2614
2967
|
delete registries[oldName];
|
|
2615
|
-
|
|
2968
|
+
setRegistries(registries);
|
|
2616
2969
|
const current = config2.get("current");
|
|
2617
2970
|
if (current === oldName) {
|
|
2618
2971
|
config2.set("current", newName);
|
|
@@ -2620,7 +2973,7 @@ program.command("rename <old> <new>").description("Rename an environment configu
|
|
|
2620
2973
|
console.log(chalk7.green(`Environment '${oldName}' renamed to '${newName}'.`));
|
|
2621
2974
|
});
|
|
2622
2975
|
program.command("cp <source> <target>").description("Copy an environment configuration").action(async (source, target) => {
|
|
2623
|
-
const registries =
|
|
2976
|
+
const registries = getRegistries();
|
|
2624
2977
|
if (!registries[source]) {
|
|
2625
2978
|
console.log(chalk7.red(`Environment '${source}' not found.`));
|
|
2626
2979
|
return;
|
|
@@ -2630,7 +2983,7 @@ program.command("cp <source> <target>").description("Copy an environment configu
|
|
|
2630
2983
|
return;
|
|
2631
2984
|
}
|
|
2632
2985
|
registries[target] = { ...registries[source] };
|
|
2633
|
-
|
|
2986
|
+
setRegistries(registries);
|
|
2634
2987
|
console.log(chalk7.green(`Environment '${source}' copied to '${target}'.`));
|
|
2635
2988
|
const { modify } = await inquirer.prompt([
|
|
2636
2989
|
{
|
|
@@ -2642,37 +2995,9 @@ program.command("cp <source> <target>").description("Copy an environment configu
|
|
|
2642
2995
|
]);
|
|
2643
2996
|
if (modify) {
|
|
2644
2997
|
const current = registries[target];
|
|
2645
|
-
const answers = await
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
name: "ANTHROPIC_BASE_URL",
|
|
2649
|
-
message: "ANTHROPIC_BASE_URL:",
|
|
2650
|
-
default: current.ANTHROPIC_BASE_URL
|
|
2651
|
-
},
|
|
2652
|
-
{
|
|
2653
|
-
type: "password",
|
|
2654
|
-
name: "ANTHROPIC_API_KEY",
|
|
2655
|
-
message: "ANTHROPIC_API_KEY (leave empty to keep current):"
|
|
2656
|
-
},
|
|
2657
|
-
{
|
|
2658
|
-
type: "input",
|
|
2659
|
-
name: "ANTHROPIC_MODEL",
|
|
2660
|
-
message: "ANTHROPIC_MODEL:",
|
|
2661
|
-
default: current.ANTHROPIC_MODEL
|
|
2662
|
-
},
|
|
2663
|
-
{
|
|
2664
|
-
type: "input",
|
|
2665
|
-
name: "ANTHROPIC_SMALL_FAST_MODEL",
|
|
2666
|
-
message: "ANTHROPIC_SMALL_FAST_MODEL:",
|
|
2667
|
-
default: current.ANTHROPIC_SMALL_FAST_MODEL
|
|
2668
|
-
}
|
|
2669
|
-
]);
|
|
2670
|
-
if (answers.ANTHROPIC_BASE_URL) current.ANTHROPIC_BASE_URL = answers.ANTHROPIC_BASE_URL;
|
|
2671
|
-
if (answers.ANTHROPIC_API_KEY) current.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
|
|
2672
|
-
if (answers.ANTHROPIC_MODEL) current.ANTHROPIC_MODEL = answers.ANTHROPIC_MODEL;
|
|
2673
|
-
if (answers.ANTHROPIC_SMALL_FAST_MODEL) current.ANTHROPIC_SMALL_FAST_MODEL = answers.ANTHROPIC_SMALL_FAST_MODEL;
|
|
2674
|
-
registries[target] = current;
|
|
2675
|
-
config2.set("registries", registries);
|
|
2998
|
+
const answers = await promptForEnvironmentConfig(current, true);
|
|
2999
|
+
registries[target] = applyPromptAnswers(current, answers, true);
|
|
3000
|
+
setRegistries(registries);
|
|
2676
3001
|
console.log(chalk7.green(`Environment '${target}' updated.`));
|
|
2677
3002
|
}
|
|
2678
3003
|
});
|
|
@@ -2681,25 +3006,22 @@ program.command("current").description("Show current environment name").action((
|
|
|
2681
3006
|
console.log(chalk7.green(current));
|
|
2682
3007
|
});
|
|
2683
3008
|
program.command("env").description("Output environment variables for shell eval").option("--json", "Output as JSON").action((options) => {
|
|
2684
|
-
const registries =
|
|
3009
|
+
const registries = getRegistries();
|
|
2685
3010
|
const current = config2.get("current");
|
|
2686
3011
|
const env = registries[current];
|
|
2687
3012
|
if (!env) return;
|
|
2688
3013
|
const outputEnv = { ...env };
|
|
2689
|
-
if (outputEnv.
|
|
2690
|
-
outputEnv.
|
|
3014
|
+
if (outputEnv.ANTHROPIC_AUTH_TOKEN) {
|
|
3015
|
+
outputEnv.ANTHROPIC_AUTH_TOKEN = decrypt(outputEnv.ANTHROPIC_AUTH_TOKEN);
|
|
2691
3016
|
}
|
|
2692
3017
|
if (options.json) {
|
|
2693
3018
|
console.log(JSON.stringify(outputEnv, null, 2));
|
|
2694
3019
|
} else {
|
|
2695
|
-
|
|
2696
|
-
if (outputEnv.ANTHROPIC_API_KEY) console.log(`export ANTHROPIC_API_KEY="${outputEnv.ANTHROPIC_API_KEY}"`);
|
|
2697
|
-
if (outputEnv.ANTHROPIC_MODEL) console.log(`export ANTHROPIC_MODEL="${outputEnv.ANTHROPIC_MODEL}"`);
|
|
2698
|
-
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));
|
|
2699
3021
|
}
|
|
2700
3022
|
});
|
|
2701
3023
|
program.command("run <command...>").description("Run a command with the current environment variables").action((command) => {
|
|
2702
|
-
const registries =
|
|
3024
|
+
const registries = getRegistries();
|
|
2703
3025
|
const current = config2.get("current");
|
|
2704
3026
|
const envConfig = registries[current];
|
|
2705
3027
|
if (!envConfig) {
|
|
@@ -2707,10 +3029,8 @@ program.command("run <command...>").description("Run a command with the current
|
|
|
2707
3029
|
process.exit(1);
|
|
2708
3030
|
}
|
|
2709
3031
|
const env = { ...process.env };
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
if (envConfig.ANTHROPIC_MODEL) env.ANTHROPIC_MODEL = envConfig.ANTHROPIC_MODEL;
|
|
2713
|
-
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));
|
|
2714
3034
|
const [cmd, ...args] = command;
|
|
2715
3035
|
const child = spawn3(cmd, args, {
|
|
2716
3036
|
env,
|
|
@@ -2879,20 +3199,33 @@ skillCmd.command("ls").description("\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 skills"
|
|
|
2879
3199
|
skillCmd.command("rm <name>").description("\u5220\u9664\u5DF2\u5B89\u88C5\u7684 skill").action((name) => {
|
|
2880
3200
|
removeSkill(name);
|
|
2881
3201
|
});
|
|
2882
|
-
program.command("load <url>").description("\u4ECE\u8FDC\u7A0B\u670D\u52A1\u5668\u52A0\u8F7D\u73AF\u5883\u914D\u7F6E").requiredOption("--secret <secret>", "\u89E3\u5BC6\u5BC6\u94A5").action(async (url, options) => {
|
|
2883
|
-
await loadFromRemote(url, options.secret);
|
|
3202
|
+
program.command("load <url>").description("\u4ECE\u8FDC\u7A0B\u670D\u52A1\u5668\u52A0\u8F7D\u73AF\u5883\u914D\u7F6E").requiredOption("--secret <secret>", "\u89E3\u5BC6\u5BC6\u94A5").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u7ED3\u679C\uFF08\u4F9B\u7A0B\u5E8F\u8C03\u7528\uFF09").action(async (url, options) => {
|
|
3203
|
+
const results = await loadFromRemote(url, options.secret);
|
|
3204
|
+
if (options.json) {
|
|
3205
|
+
console.log(JSON.stringify({
|
|
3206
|
+
count: results.length,
|
|
3207
|
+
environments: results.map((r) => ({
|
|
3208
|
+
name: r.name,
|
|
3209
|
+
original_name: r.originalName,
|
|
3210
|
+
// 使用 snake_case 匹配 Rust 结构体
|
|
3211
|
+
renamed: r.renamed
|
|
3212
|
+
}))
|
|
3213
|
+
}));
|
|
3214
|
+
}
|
|
2884
3215
|
});
|
|
2885
|
-
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").action(async function() {
|
|
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() {
|
|
2886
3217
|
const opts = this.opts();
|
|
2887
3218
|
const envName = opts.env || config2.get("current");
|
|
2888
|
-
const registries =
|
|
3219
|
+
const registries = getRegistries();
|
|
2889
3220
|
const envConfig = registries[envName];
|
|
2890
3221
|
if (!envConfig) {
|
|
2891
3222
|
console.error(chalk7.red(`Environment '${envName}' not found.`));
|
|
2892
3223
|
process.exit(1);
|
|
2893
3224
|
}
|
|
3225
|
+
const proxyBaseUrl = opts.proxyBaseUrl || opts.anthropicBaseUrl;
|
|
3226
|
+
const launchEnvConfig = proxyBaseUrl ? { ...envConfig, ANTHROPIC_BASE_URL: proxyBaseUrl } : envConfig;
|
|
2894
3227
|
await launchClaude({
|
|
2895
|
-
envConfig,
|
|
3228
|
+
envConfig: launchEnvConfig,
|
|
2896
3229
|
permMode: opts.perm,
|
|
2897
3230
|
workingDir: opts.workingDir,
|
|
2898
3231
|
sessionId: opts.sessionId,
|
|
@@ -2928,7 +3261,7 @@ program.action(async (options) => {
|
|
|
2928
3261
|
showCurrentEnv(usageStats, usageLoading);
|
|
2929
3262
|
console.log("");
|
|
2930
3263
|
const defaultMode = config2.get("defaultMode");
|
|
2931
|
-
const registries =
|
|
3264
|
+
const registries = getRegistries();
|
|
2932
3265
|
const current = config2.get("current");
|
|
2933
3266
|
const envConfig = registries[current];
|
|
2934
3267
|
const { action } = await inquirer.prompt([
|
|
@@ -2975,37 +3308,9 @@ program.action(async (options) => {
|
|
|
2975
3308
|
const envToEdit = registries[result.name];
|
|
2976
3309
|
console.log(chalk7.yellow(`
|
|
2977
3310
|
Editing environment '${result.name}'`));
|
|
2978
|
-
const answers = await
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
name: "ANTHROPIC_BASE_URL",
|
|
2982
|
-
message: "ANTHROPIC_BASE_URL:",
|
|
2983
|
-
default: envToEdit.ANTHROPIC_BASE_URL
|
|
2984
|
-
},
|
|
2985
|
-
{
|
|
2986
|
-
type: "password",
|
|
2987
|
-
name: "ANTHROPIC_API_KEY",
|
|
2988
|
-
message: "ANTHROPIC_API_KEY (leave empty to keep current):"
|
|
2989
|
-
},
|
|
2990
|
-
{
|
|
2991
|
-
type: "input",
|
|
2992
|
-
name: "ANTHROPIC_MODEL",
|
|
2993
|
-
message: "ANTHROPIC_MODEL:",
|
|
2994
|
-
default: envToEdit.ANTHROPIC_MODEL
|
|
2995
|
-
},
|
|
2996
|
-
{
|
|
2997
|
-
type: "input",
|
|
2998
|
-
name: "ANTHROPIC_SMALL_FAST_MODEL",
|
|
2999
|
-
message: "ANTHROPIC_SMALL_FAST_MODEL:",
|
|
3000
|
-
default: envToEdit.ANTHROPIC_SMALL_FAST_MODEL
|
|
3001
|
-
}
|
|
3002
|
-
]);
|
|
3003
|
-
if (answers.ANTHROPIC_BASE_URL) envToEdit.ANTHROPIC_BASE_URL = answers.ANTHROPIC_BASE_URL;
|
|
3004
|
-
if (answers.ANTHROPIC_API_KEY) envToEdit.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
|
|
3005
|
-
if (answers.ANTHROPIC_MODEL) envToEdit.ANTHROPIC_MODEL = answers.ANTHROPIC_MODEL;
|
|
3006
|
-
if (answers.ANTHROPIC_SMALL_FAST_MODEL) envToEdit.ANTHROPIC_SMALL_FAST_MODEL = answers.ANTHROPIC_SMALL_FAST_MODEL;
|
|
3007
|
-
registries[result.name] = envToEdit;
|
|
3008
|
-
config2.set("registries", registries);
|
|
3311
|
+
const answers = await promptForEnvironmentConfig(envToEdit, true);
|
|
3312
|
+
registries[result.name] = applyPromptAnswers(envToEdit, answers, true);
|
|
3313
|
+
setRegistries(registries);
|
|
3009
3314
|
msg.success(`Environment '${result.name}' updated.`);
|
|
3010
3315
|
await new Promise((resolve2) => setTimeout(resolve2, 800));
|
|
3011
3316
|
} else if (result.action === "rename") {
|
|
@@ -3027,7 +3332,7 @@ Editing environment '${result.name}'`));
|
|
|
3027
3332
|
]);
|
|
3028
3333
|
registries[newName] = registries[result.name];
|
|
3029
3334
|
delete registries[result.name];
|
|
3030
|
-
|
|
3335
|
+
setRegistries(registries);
|
|
3031
3336
|
if (current === result.name) {
|
|
3032
3337
|
config2.set("current", newName);
|
|
3033
3338
|
}
|
|
@@ -3048,7 +3353,7 @@ Editing environment '${result.name}'`));
|
|
|
3048
3353
|
}
|
|
3049
3354
|
]);
|
|
3050
3355
|
registries[targetName] = { ...registries[result.name] };
|
|
3051
|
-
|
|
3356
|
+
setRegistries(registries);
|
|
3052
3357
|
msg.success(`Environment '${result.name}' copied to '${targetName}'.`);
|
|
3053
3358
|
const { modify } = await inquirer.prompt([
|
|
3054
3359
|
{
|
|
@@ -3060,37 +3365,9 @@ Editing environment '${result.name}'`));
|
|
|
3060
3365
|
]);
|
|
3061
3366
|
if (modify) {
|
|
3062
3367
|
const envToEdit = registries[targetName];
|
|
3063
|
-
const editAnswers = await
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
name: "ANTHROPIC_BASE_URL",
|
|
3067
|
-
message: "ANTHROPIC_BASE_URL:",
|
|
3068
|
-
default: envToEdit.ANTHROPIC_BASE_URL
|
|
3069
|
-
},
|
|
3070
|
-
{
|
|
3071
|
-
type: "password",
|
|
3072
|
-
name: "ANTHROPIC_API_KEY",
|
|
3073
|
-
message: "ANTHROPIC_API_KEY (leave empty to keep current):"
|
|
3074
|
-
},
|
|
3075
|
-
{
|
|
3076
|
-
type: "input",
|
|
3077
|
-
name: "ANTHROPIC_MODEL",
|
|
3078
|
-
message: "ANTHROPIC_MODEL:",
|
|
3079
|
-
default: envToEdit.ANTHROPIC_MODEL
|
|
3080
|
-
},
|
|
3081
|
-
{
|
|
3082
|
-
type: "input",
|
|
3083
|
-
name: "ANTHROPIC_SMALL_FAST_MODEL",
|
|
3084
|
-
message: "ANTHROPIC_SMALL_FAST_MODEL:",
|
|
3085
|
-
default: envToEdit.ANTHROPIC_SMALL_FAST_MODEL
|
|
3086
|
-
}
|
|
3087
|
-
]);
|
|
3088
|
-
if (editAnswers.ANTHROPIC_BASE_URL) envToEdit.ANTHROPIC_BASE_URL = editAnswers.ANTHROPIC_BASE_URL;
|
|
3089
|
-
if (editAnswers.ANTHROPIC_API_KEY) envToEdit.ANTHROPIC_API_KEY = encrypt(editAnswers.ANTHROPIC_API_KEY);
|
|
3090
|
-
if (editAnswers.ANTHROPIC_MODEL) envToEdit.ANTHROPIC_MODEL = editAnswers.ANTHROPIC_MODEL;
|
|
3091
|
-
if (editAnswers.ANTHROPIC_SMALL_FAST_MODEL) envToEdit.ANTHROPIC_SMALL_FAST_MODEL = editAnswers.ANTHROPIC_SMALL_FAST_MODEL;
|
|
3092
|
-
registries[targetName] = envToEdit;
|
|
3093
|
-
config2.set("registries", registries);
|
|
3368
|
+
const editAnswers = await promptForEnvironmentConfig(envToEdit, true);
|
|
3369
|
+
registries[targetName] = applyPromptAnswers(envToEdit, editAnswers, true);
|
|
3370
|
+
setRegistries(registries);
|
|
3094
3371
|
msg.success(`Environment '${targetName}' updated.`);
|
|
3095
3372
|
}
|
|
3096
3373
|
await new Promise((resolve2) => setTimeout(resolve2, 800));
|
|
@@ -3109,7 +3386,7 @@ Editing environment '${result.name}'`));
|
|
|
3109
3386
|
]);
|
|
3110
3387
|
if (confirm) {
|
|
3111
3388
|
delete registries[result.name];
|
|
3112
|
-
|
|
3389
|
+
setRegistries(registries);
|
|
3113
3390
|
if (current === result.name) {
|
|
3114
3391
|
config2.set("current", "official");
|
|
3115
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
|
+
"version": "2.0.0-beta.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Claude Code Environment Manager",
|
|
6
6
|
"author": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"tsup": "^8.0.2",
|
|
37
37
|
"typescript": "^5.3.3",
|
|
38
38
|
"vitest": "^4.0.18",
|
|
39
|
-
"@ccem/core": "2.0.0-beta.
|
|
39
|
+
"@ccem/core": "2.0.0-beta.3"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"generate-logo": "bash scripts/generate-logo.sh",
|