ccem 2.0.0-beta → 2.0.0-beta.3
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 +476 -140
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -7,28 +7,346 @@ import inquirer from "inquirer";
|
|
|
7
7
|
import chalk7 from "chalk";
|
|
8
8
|
import Table3 from "cli-table3";
|
|
9
9
|
import { spawn as spawn3 } from "child_process";
|
|
10
|
-
import * as
|
|
11
|
-
import * as
|
|
12
|
-
import { fileURLToPath } from "url";
|
|
13
|
-
|
|
10
|
+
import * as fs8 from "fs";
|
|
11
|
+
import * as path6 from "path";
|
|
12
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13
|
+
|
|
14
|
+
// ../../packages/core/dist/chunk-YO7HO5AS.js
|
|
15
|
+
var ENV_PRESETS = {
|
|
16
|
+
"GLM": {
|
|
17
|
+
ANTHROPIC_BASE_URL: "https://open.bigmodel.cn/api/anthropic",
|
|
18
|
+
ANTHROPIC_MODEL: "glm-4.6",
|
|
19
|
+
ANTHROPIC_SMALL_FAST_MODEL: "glm-4.5-air"
|
|
20
|
+
},
|
|
21
|
+
"KIMI": {
|
|
22
|
+
ANTHROPIC_BASE_URL: "https://api.moonshot.cn/anthropic",
|
|
23
|
+
ANTHROPIC_MODEL: "kimi-k2-thinking-turbo",
|
|
24
|
+
ANTHROPIC_SMALL_FAST_MODEL: "kimi-k2-turbo-preview"
|
|
25
|
+
},
|
|
26
|
+
"MiniMax": {
|
|
27
|
+
ANTHROPIC_BASE_URL: "https://api.minimaxi.com/anthropic",
|
|
28
|
+
ANTHROPIC_MODEL: "MiniMax-M2",
|
|
29
|
+
ANTHROPIC_SMALL_FAST_MODEL: "MiniMax-M2"
|
|
30
|
+
},
|
|
31
|
+
"DeepSeek": {
|
|
32
|
+
ANTHROPIC_BASE_URL: "https://api.deepseek.com/anthropic",
|
|
33
|
+
ANTHROPIC_MODEL: "deepseek-chat",
|
|
34
|
+
ANTHROPIC_SMALL_FAST_MODEL: "deepseek-chat"
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var PERMISSION_PRESETS = {
|
|
38
|
+
"yolo": {
|
|
39
|
+
name: "YOLO \u6A21\u5F0F",
|
|
40
|
+
description: "\u5168\u90E8\u653E\u5F00\uFF0C\u65E0\u4EFB\u4F55\u9650\u5236",
|
|
41
|
+
permissionMode: "bypassPermissions",
|
|
42
|
+
permissions: {
|
|
43
|
+
allow: [
|
|
44
|
+
"Bash(*)",
|
|
45
|
+
"Read(*)",
|
|
46
|
+
"Edit(*)",
|
|
47
|
+
"Write(*)",
|
|
48
|
+
"WebFetch(*)",
|
|
49
|
+
"WebSearch(*)",
|
|
50
|
+
"Glob(*)",
|
|
51
|
+
"Grep(*)",
|
|
52
|
+
"LSP(*)",
|
|
53
|
+
"NotebookEdit(*)"
|
|
54
|
+
],
|
|
55
|
+
deny: []
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"dev": {
|
|
59
|
+
name: "\u5F00\u53D1\u6A21\u5F0F",
|
|
60
|
+
description: "\u65E5\u5E38\u5F00\u53D1\u6743\u9650\uFF0C\u4FDD\u62A4\u654F\u611F\u6587\u4EF6",
|
|
61
|
+
permissionMode: "acceptEdits",
|
|
62
|
+
permissions: {
|
|
63
|
+
allow: [
|
|
64
|
+
"Read(*)",
|
|
65
|
+
"Edit(*)",
|
|
66
|
+
"Write(*)",
|
|
67
|
+
"Glob(*)",
|
|
68
|
+
"Grep(*)",
|
|
69
|
+
"LSP(*)",
|
|
70
|
+
"NotebookEdit(*)",
|
|
71
|
+
"Bash(npm:*)",
|
|
72
|
+
"Bash(pnpm:*)",
|
|
73
|
+
"Bash(yarn:*)",
|
|
74
|
+
"Bash(bun:*)",
|
|
75
|
+
"Bash(node:*)",
|
|
76
|
+
"Bash(npx:*)",
|
|
77
|
+
"Bash(git:*)",
|
|
78
|
+
"Bash(tsc:*)",
|
|
79
|
+
"Bash(tsx:*)",
|
|
80
|
+
"Bash(eslint:*)",
|
|
81
|
+
"Bash(prettier:*)",
|
|
82
|
+
"Bash(jest:*)",
|
|
83
|
+
"Bash(vitest:*)",
|
|
84
|
+
"Bash(cargo:*)",
|
|
85
|
+
"Bash(python:*)",
|
|
86
|
+
"Bash(pip:*)",
|
|
87
|
+
"Bash(go:*)",
|
|
88
|
+
"Bash(make:*)",
|
|
89
|
+
"Bash(cmake:*)",
|
|
90
|
+
"Bash(ls:*)",
|
|
91
|
+
"Bash(cat:*)",
|
|
92
|
+
"Bash(head:*)",
|
|
93
|
+
"Bash(tail:*)",
|
|
94
|
+
"Bash(find:*)",
|
|
95
|
+
"Bash(wc:*)",
|
|
96
|
+
"Bash(mkdir:*)",
|
|
97
|
+
"Bash(cp:*)",
|
|
98
|
+
"Bash(mv:*)",
|
|
99
|
+
"Bash(touch:*)",
|
|
100
|
+
"WebSearch"
|
|
101
|
+
],
|
|
102
|
+
deny: [
|
|
103
|
+
"Read(.env)",
|
|
104
|
+
"Read(.env.*)",
|
|
105
|
+
"Read(**/secrets/**)",
|
|
106
|
+
"Read(**/*.pem)",
|
|
107
|
+
"Read(**/*.key)",
|
|
108
|
+
"Read(**/*credential*)",
|
|
109
|
+
"Bash(rm -rf:*)",
|
|
110
|
+
"Bash(sudo:*)",
|
|
111
|
+
"Bash(chmod:*)",
|
|
112
|
+
"Bash(chown:*)"
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"readonly": {
|
|
117
|
+
name: "\u53EA\u8BFB\u6A21\u5F0F",
|
|
118
|
+
description: "\u4EC5\u5141\u8BB8\u8BFB\u53D6\u548C\u641C\u7D22\uFF0C\u7981\u6B62\u4EFB\u4F55\u4FEE\u6539",
|
|
119
|
+
permissionMode: "plan",
|
|
120
|
+
permissions: {
|
|
121
|
+
allow: [
|
|
122
|
+
"Read(*)",
|
|
123
|
+
"Glob(*)",
|
|
124
|
+
"Grep(*)",
|
|
125
|
+
"LSP(*)",
|
|
126
|
+
"Bash(git status:*)",
|
|
127
|
+
"Bash(git log:*)",
|
|
128
|
+
"Bash(git diff:*)",
|
|
129
|
+
"Bash(git branch:*)",
|
|
130
|
+
"Bash(git show:*)",
|
|
131
|
+
"Bash(ls:*)",
|
|
132
|
+
"Bash(cat:*)",
|
|
133
|
+
"Bash(head:*)",
|
|
134
|
+
"Bash(tail:*)",
|
|
135
|
+
"Bash(find:*)",
|
|
136
|
+
"Bash(wc:*)",
|
|
137
|
+
"Bash(file:*)",
|
|
138
|
+
"WebSearch"
|
|
139
|
+
],
|
|
140
|
+
deny: [
|
|
141
|
+
"Edit(*)",
|
|
142
|
+
"Write(*)",
|
|
143
|
+
"NotebookEdit(*)",
|
|
144
|
+
"Bash(rm:*)",
|
|
145
|
+
"Bash(mv:*)",
|
|
146
|
+
"Bash(cp:*)",
|
|
147
|
+
"Bash(mkdir:*)",
|
|
148
|
+
"Bash(touch:*)",
|
|
149
|
+
"Bash(git add:*)",
|
|
150
|
+
"Bash(git commit:*)",
|
|
151
|
+
"Bash(git push:*)",
|
|
152
|
+
"Bash(git checkout:*)",
|
|
153
|
+
"Bash(git reset:*)",
|
|
154
|
+
"Bash(npm install:*)",
|
|
155
|
+
"Bash(pnpm install:*)",
|
|
156
|
+
"Bash(yarn add:*)"
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"safe": {
|
|
161
|
+
name: "\u5B89\u5168\u6A21\u5F0F",
|
|
162
|
+
description: "\u4FDD\u5B88\u6743\u9650\uFF0C\u9002\u5408\u4E0D\u719F\u6089\u7684\u4EE3\u7801\u5E93",
|
|
163
|
+
permissionMode: "default",
|
|
164
|
+
permissions: {
|
|
165
|
+
allow: [
|
|
166
|
+
"Read(*)",
|
|
167
|
+
"Glob(*)",
|
|
168
|
+
"Grep(*)",
|
|
169
|
+
"LSP(*)",
|
|
170
|
+
"Bash(git status:*)",
|
|
171
|
+
"Bash(git log:*)",
|
|
172
|
+
"Bash(git diff:*)",
|
|
173
|
+
"Bash(ls:*)",
|
|
174
|
+
"Bash(cat:*)",
|
|
175
|
+
"Bash(head:*)",
|
|
176
|
+
"Bash(tail:*)",
|
|
177
|
+
"Bash(find:*)",
|
|
178
|
+
"Bash(wc:*)"
|
|
179
|
+
],
|
|
180
|
+
deny: [
|
|
181
|
+
"Read(.env)",
|
|
182
|
+
"Read(.env.*)",
|
|
183
|
+
"Read(**/secrets/**)",
|
|
184
|
+
"Read(**/*.pem)",
|
|
185
|
+
"Read(**/*.key)",
|
|
186
|
+
"Read(**/*credential*)",
|
|
187
|
+
"Read(**/*password*)",
|
|
188
|
+
"Edit(*)",
|
|
189
|
+
"Write(*)",
|
|
190
|
+
"NotebookEdit(*)",
|
|
191
|
+
"Bash(curl:*)",
|
|
192
|
+
"Bash(wget:*)",
|
|
193
|
+
"Bash(ssh:*)",
|
|
194
|
+
"Bash(scp:*)",
|
|
195
|
+
"Bash(rm:*)",
|
|
196
|
+
"Bash(mv:*)",
|
|
197
|
+
"WebFetch(*)"
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"ci": {
|
|
202
|
+
name: "CI/CD \u6A21\u5F0F",
|
|
203
|
+
description: "\u9002\u5408\u81EA\u52A8\u5316\u6D41\u6C34\u7EBF\u7684\u6743\u9650",
|
|
204
|
+
permissionMode: "default",
|
|
205
|
+
permissions: {
|
|
206
|
+
allow: [
|
|
207
|
+
"Read(*)",
|
|
208
|
+
"Edit(*)",
|
|
209
|
+
"Write(*)",
|
|
210
|
+
"Glob(*)",
|
|
211
|
+
"Grep(*)",
|
|
212
|
+
"LSP(*)",
|
|
213
|
+
"Bash(npm:*)",
|
|
214
|
+
"Bash(pnpm:*)",
|
|
215
|
+
"Bash(yarn:*)",
|
|
216
|
+
"Bash(node:*)",
|
|
217
|
+
"Bash(git:*)",
|
|
218
|
+
"Bash(docker:*)",
|
|
219
|
+
"Bash(make:*)",
|
|
220
|
+
"Bash(cargo:*)",
|
|
221
|
+
"Bash(go:*)",
|
|
222
|
+
"Bash(python:*)",
|
|
223
|
+
"Bash(pip:*)",
|
|
224
|
+
"Bash(pytest:*)",
|
|
225
|
+
"Bash(jest:*)",
|
|
226
|
+
"Bash(vitest:*)"
|
|
227
|
+
],
|
|
228
|
+
deny: [
|
|
229
|
+
"Read(.env.local)",
|
|
230
|
+
"Read(**/secrets/**)",
|
|
231
|
+
"Bash(sudo:*)",
|
|
232
|
+
"Bash(ssh:*)",
|
|
233
|
+
"Bash(scp:*)",
|
|
234
|
+
"WebFetch(*)",
|
|
235
|
+
"WebSearch"
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"audit": {
|
|
240
|
+
name: "\u5BA1\u8BA1\u6A21\u5F0F",
|
|
241
|
+
description: "\u4EC5\u8BFB\u53D6\u548C\u641C\u7D22\uFF0C\u7528\u4E8E\u5B89\u5168\u5BA1\u8BA1",
|
|
242
|
+
permissionMode: "plan",
|
|
243
|
+
permissions: {
|
|
244
|
+
allow: [
|
|
245
|
+
"Read(*)",
|
|
246
|
+
"Glob(*)",
|
|
247
|
+
"Grep(*)",
|
|
248
|
+
"LSP(*)",
|
|
249
|
+
"Bash(git log:*)",
|
|
250
|
+
"Bash(git blame:*)",
|
|
251
|
+
"Bash(git show:*)",
|
|
252
|
+
"Bash(git diff:*)",
|
|
253
|
+
"Bash(ls:*)",
|
|
254
|
+
"Bash(find:*)",
|
|
255
|
+
"Bash(wc:*)",
|
|
256
|
+
"Bash(file:*)",
|
|
257
|
+
"Bash(stat:*)"
|
|
258
|
+
],
|
|
259
|
+
deny: [
|
|
260
|
+
"Edit(*)",
|
|
261
|
+
"Write(*)",
|
|
262
|
+
"NotebookEdit(*)",
|
|
263
|
+
"Bash(rm:*)",
|
|
264
|
+
"Bash(mv:*)",
|
|
265
|
+
"Bash(cp:*)",
|
|
266
|
+
"Bash(curl:*)",
|
|
267
|
+
"Bash(wget:*)",
|
|
268
|
+
"Bash(ssh:*)",
|
|
269
|
+
"WebFetch(*)"
|
|
270
|
+
]
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
var getPermissionModeNames = () => {
|
|
275
|
+
return Object.keys(PERMISSION_PRESETS);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// ../../packages/core/dist/index.js
|
|
279
|
+
import crypto from "crypto";
|
|
280
|
+
import fs from "fs";
|
|
281
|
+
import path from "path";
|
|
282
|
+
var ALGORITHM = "aes-256-cbc";
|
|
283
|
+
var SECRET_KEY = crypto.scryptSync("claude-code-env-manager-secret", "salt", 32);
|
|
284
|
+
var encrypt = (text) => {
|
|
285
|
+
if (!text) return text;
|
|
286
|
+
const iv = crypto.randomBytes(16);
|
|
287
|
+
const cipher = crypto.createCipheriv(ALGORITHM, SECRET_KEY, iv);
|
|
288
|
+
let encrypted = cipher.update(text, "utf8", "hex");
|
|
289
|
+
encrypted += cipher.final("hex");
|
|
290
|
+
return `enc:${iv.toString("hex")}:${encrypted}`;
|
|
291
|
+
};
|
|
292
|
+
var decrypt = (text) => {
|
|
293
|
+
if (!text || !text.startsWith("enc:")) return text;
|
|
294
|
+
try {
|
|
295
|
+
const parts = text.split(":");
|
|
296
|
+
if (parts.length !== 3) return text;
|
|
297
|
+
const iv = Buffer.from(parts[1], "hex");
|
|
298
|
+
const encryptedText = parts[2];
|
|
299
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, SECRET_KEY, iv);
|
|
300
|
+
let decrypted = decipher.update(encryptedText, "hex", "utf8");
|
|
301
|
+
decrypted += decipher.final("utf8");
|
|
302
|
+
return decrypted;
|
|
303
|
+
} catch {
|
|
304
|
+
return text;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
var getHomeDir = () => {
|
|
308
|
+
return process.env.HOME || process.env.USERPROFILE || "";
|
|
309
|
+
};
|
|
310
|
+
var getCcemConfigDir = () => {
|
|
311
|
+
return path.join(getHomeDir(), ".ccem");
|
|
312
|
+
};
|
|
313
|
+
var getCcemConfigPath = () => {
|
|
314
|
+
return path.join(getCcemConfigDir(), "config.json");
|
|
315
|
+
};
|
|
316
|
+
var ensureCcemDir = () => {
|
|
317
|
+
const ccemDir = getCcemConfigDir();
|
|
318
|
+
if (!fs.existsSync(ccemDir)) {
|
|
319
|
+
fs.mkdirSync(ccemDir, { recursive: true });
|
|
320
|
+
}
|
|
321
|
+
return ccemDir;
|
|
322
|
+
};
|
|
323
|
+
var getLegacyConfigPath = () => {
|
|
324
|
+
const home = getHomeDir();
|
|
325
|
+
if (process.platform === "darwin") {
|
|
326
|
+
return path.join(home, "Library", "Preferences", "claude-code-env-manager-nodejs", "config.json");
|
|
327
|
+
}
|
|
328
|
+
return path.join(home, ".config", "claude-code-env-manager-nodejs", "config.json");
|
|
329
|
+
};
|
|
14
330
|
|
|
15
331
|
// src/ui.ts
|
|
16
332
|
import chalk from "chalk";
|
|
17
333
|
import Table from "cli-table3";
|
|
18
|
-
import { PERMISSION_PRESETS } from "@ccem/core";
|
|
19
334
|
|
|
20
335
|
// src/usage.ts
|
|
21
|
-
import * as
|
|
336
|
+
import * as fs2 from "fs";
|
|
22
337
|
import * as fsPromises from "fs/promises";
|
|
23
|
-
import * as
|
|
338
|
+
import * as path2 from "path";
|
|
24
339
|
import * as os from "os";
|
|
25
340
|
import * as readline from "readline";
|
|
26
|
-
|
|
27
|
-
var
|
|
341
|
+
import { fileURLToPath } from "url";
|
|
342
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
343
|
+
var __dirname = path2.dirname(__filename);
|
|
344
|
+
var CLAUDE_PROJECTS_DIR = path2.join(os.homedir(), ".claude", "projects");
|
|
345
|
+
var CCEM_DIR = path2.join(os.homedir(), ".ccem");
|
|
28
346
|
var CACHE_VERSION = 1;
|
|
29
|
-
var getCachePath = () =>
|
|
30
|
-
var getPricesPath = () =>
|
|
31
|
-
async function
|
|
347
|
+
var getCachePath = () => path2.join(CCEM_DIR, "usage-cache.json");
|
|
348
|
+
var getPricesPath = () => path2.join(CCEM_DIR, "model-prices.json");
|
|
349
|
+
async function ensureCcemDir2() {
|
|
32
350
|
try {
|
|
33
351
|
await fsPromises.access(CCEM_DIR);
|
|
34
352
|
} catch {
|
|
@@ -37,7 +355,7 @@ async function ensureCcemDir() {
|
|
|
37
355
|
}
|
|
38
356
|
var LITELLM_PRICES_URL = "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
|
|
39
357
|
var getBundledPricesPath = () => {
|
|
40
|
-
return
|
|
358
|
+
return path2.join(__dirname, "..", "model-prices.json");
|
|
41
359
|
};
|
|
42
360
|
var DEFAULT_PRICES = {
|
|
43
361
|
"claude-opus-4-5": {
|
|
@@ -66,7 +384,7 @@ function normalizeModelName(model) {
|
|
|
66
384
|
var pricesCache = null;
|
|
67
385
|
async function loadPrices() {
|
|
68
386
|
if (pricesCache) return pricesCache;
|
|
69
|
-
await
|
|
387
|
+
await ensureCcemDir2();
|
|
70
388
|
const pricesPath = getPricesPath();
|
|
71
389
|
try {
|
|
72
390
|
const response = await fetch(LITELLM_PRICES_URL, { signal: AbortSignal.timeout(1e3) });
|
|
@@ -156,8 +474,8 @@ async function getFileMetaAsync(filePath) {
|
|
|
156
474
|
function loadCacheSync() {
|
|
157
475
|
try {
|
|
158
476
|
const cachePath = getCachePath();
|
|
159
|
-
if (!
|
|
160
|
-
const data = JSON.parse(
|
|
477
|
+
if (!fs2.existsSync(cachePath)) return null;
|
|
478
|
+
const data = JSON.parse(fs2.readFileSync(cachePath, "utf-8"));
|
|
161
479
|
if (data.version !== CACHE_VERSION) return null;
|
|
162
480
|
return data;
|
|
163
481
|
} catch {
|
|
@@ -216,7 +534,7 @@ function getUsageStatsFromCache() {
|
|
|
216
534
|
}
|
|
217
535
|
async function saveCacheAsync(cache) {
|
|
218
536
|
try {
|
|
219
|
-
await
|
|
537
|
+
await ensureCcemDir2();
|
|
220
538
|
await fsPromises.writeFile(getCachePath(), JSON.stringify(cache, null, 2));
|
|
221
539
|
} catch {
|
|
222
540
|
}
|
|
@@ -224,7 +542,7 @@ async function saveCacheAsync(cache) {
|
|
|
224
542
|
async function parseJSONLFileAsync(filePath, prices, signal) {
|
|
225
543
|
const entries = [];
|
|
226
544
|
try {
|
|
227
|
-
const fileStream =
|
|
545
|
+
const fileStream = fs2.createReadStream(filePath, { encoding: "utf-8" });
|
|
228
546
|
const rl = readline.createInterface({
|
|
229
547
|
input: fileStream,
|
|
230
548
|
crlfDelay: Infinity
|
|
@@ -278,14 +596,14 @@ async function getAllJSONLFilesAsync() {
|
|
|
278
596
|
if (!projectsDirExists) return files;
|
|
279
597
|
const projects = await fsPromises.readdir(CLAUDE_PROJECTS_DIR);
|
|
280
598
|
for (const project of projects) {
|
|
281
|
-
const projectPath =
|
|
599
|
+
const projectPath = path2.join(CLAUDE_PROJECTS_DIR, project);
|
|
282
600
|
try {
|
|
283
601
|
const stat2 = await fsPromises.stat(projectPath);
|
|
284
602
|
if (stat2.isDirectory()) {
|
|
285
603
|
const projectFiles = await fsPromises.readdir(projectPath);
|
|
286
604
|
for (const file of projectFiles) {
|
|
287
605
|
if (file.endsWith(".jsonl")) {
|
|
288
|
-
files.push(
|
|
606
|
+
files.push(path2.join(projectPath, file));
|
|
289
607
|
}
|
|
290
608
|
}
|
|
291
609
|
}
|
|
@@ -506,10 +824,10 @@ var renderLogoWithEnvPanel = (envName, env, defaultMode) => {
|
|
|
506
824
|
const parsed = new URL(url);
|
|
507
825
|
const protocol = parsed.protocol + "//";
|
|
508
826
|
const host = parsed.host;
|
|
509
|
-
const
|
|
827
|
+
const path7 = parsed.pathname + parsed.search;
|
|
510
828
|
const hostStart = host.slice(0, 8);
|
|
511
829
|
const hostEnd = host.slice(-4);
|
|
512
|
-
const pathPart =
|
|
830
|
+
const pathPart = path7.length > 10 ? path7.slice(0, 7) + "..." : path7;
|
|
513
831
|
return `${protocol}${hostStart}...${hostEnd}${pathPart}`;
|
|
514
832
|
} catch {
|
|
515
833
|
return truncate(url, max);
|
|
@@ -947,64 +1265,62 @@ var selectEnvWithKeys = (registries, current) => {
|
|
|
947
1265
|
};
|
|
948
1266
|
|
|
949
1267
|
// src/permissions.ts
|
|
950
|
-
import
|
|
1268
|
+
import fs5 from "fs";
|
|
951
1269
|
import chalk3 from "chalk";
|
|
952
1270
|
import Table2 from "cli-table3";
|
|
953
|
-
import { PERMISSION_PRESETS as PERMISSION_PRESETS3, getPermissionModeNames } from "@ccem/core";
|
|
954
1271
|
|
|
955
1272
|
// src/utils.ts
|
|
956
|
-
import
|
|
957
|
-
import
|
|
958
|
-
import
|
|
959
|
-
var
|
|
1273
|
+
import crypto2 from "crypto";
|
|
1274
|
+
import fs3 from "fs";
|
|
1275
|
+
import path3 from "path";
|
|
1276
|
+
var SECRET_KEY2 = crypto2.scryptSync("claude-code-env-manager-secret", "salt", 32);
|
|
960
1277
|
var findProjectRoot = () => {
|
|
961
1278
|
let currentDir = process.cwd();
|
|
962
|
-
const root =
|
|
1279
|
+
const root = path3.parse(currentDir).root;
|
|
963
1280
|
while (currentDir !== root) {
|
|
964
|
-
if (
|
|
1281
|
+
if (fs3.existsSync(path3.join(currentDir, ".git")) || fs3.existsSync(path3.join(currentDir, "package.json"))) {
|
|
965
1282
|
return currentDir;
|
|
966
1283
|
}
|
|
967
|
-
currentDir =
|
|
1284
|
+
currentDir = path3.dirname(currentDir);
|
|
968
1285
|
}
|
|
969
1286
|
return process.cwd();
|
|
970
1287
|
};
|
|
971
1288
|
var getSettingsPath = (useLocal = true) => {
|
|
972
1289
|
const projectRoot = findProjectRoot();
|
|
973
|
-
const claudeDir =
|
|
1290
|
+
const claudeDir = path3.join(projectRoot, ".claude");
|
|
974
1291
|
const filename = useLocal ? "settings.local.json" : "settings.json";
|
|
975
|
-
return
|
|
1292
|
+
return path3.join(claudeDir, filename);
|
|
976
1293
|
};
|
|
977
1294
|
var ensureClaudeDir = () => {
|
|
978
1295
|
const projectRoot = findProjectRoot();
|
|
979
|
-
const claudeDir =
|
|
980
|
-
if (!
|
|
981
|
-
|
|
1296
|
+
const claudeDir = path3.join(projectRoot, ".claude");
|
|
1297
|
+
if (!fs3.existsSync(claudeDir)) {
|
|
1298
|
+
fs3.mkdirSync(claudeDir, { recursive: true });
|
|
982
1299
|
}
|
|
983
1300
|
return claudeDir;
|
|
984
1301
|
};
|
|
985
|
-
var
|
|
1302
|
+
var getHomeDir2 = () => {
|
|
986
1303
|
return process.env.HOME || process.env.USERPROFILE || "";
|
|
987
1304
|
};
|
|
988
1305
|
var getGlobalClaudeConfigPath = () => {
|
|
989
|
-
return
|
|
1306
|
+
return path3.join(getHomeDir2(), ".claude.json");
|
|
990
1307
|
};
|
|
991
1308
|
var getGlobalClaudeSettingsPath = () => {
|
|
992
|
-
return
|
|
1309
|
+
return path3.join(getHomeDir2(), ".claude", "settings.json");
|
|
993
1310
|
};
|
|
994
1311
|
var ensureGlobalClaudeDir = () => {
|
|
995
|
-
const claudeDir =
|
|
996
|
-
if (!
|
|
997
|
-
|
|
1312
|
+
const claudeDir = path3.join(getHomeDir2(), ".claude");
|
|
1313
|
+
if (!fs3.existsSync(claudeDir)) {
|
|
1314
|
+
fs3.mkdirSync(claudeDir, { recursive: true });
|
|
998
1315
|
}
|
|
999
1316
|
return claudeDir;
|
|
1000
1317
|
};
|
|
1001
1318
|
|
|
1002
1319
|
// src/launcher.ts
|
|
1003
1320
|
import { spawn } from "child_process";
|
|
1004
|
-
import * as
|
|
1005
|
-
import * as
|
|
1321
|
+
import * as fs4 from "fs";
|
|
1322
|
+
import * as path4 from "path";
|
|
1006
1323
|
import chalk2 from "chalk";
|
|
1007
|
-
import { decrypt, PERMISSION_PRESETS as PERMISSION_PRESETS2, ensureCcemDir as ensureCcemDir2 } from "@ccem/core";
|
|
1008
1324
|
function buildEnvVars(envConfig) {
|
|
1009
1325
|
const vars = {};
|
|
1010
1326
|
if (envConfig.ANTHROPIC_BASE_URL) vars.ANTHROPIC_BASE_URL = envConfig.ANTHROPIC_BASE_URL;
|
|
@@ -1014,7 +1330,7 @@ function buildEnvVars(envConfig) {
|
|
|
1014
1330
|
return vars;
|
|
1015
1331
|
}
|
|
1016
1332
|
function buildPermArgs(modeName) {
|
|
1017
|
-
const preset =
|
|
1333
|
+
const preset = PERMISSION_PRESETS[modeName];
|
|
1018
1334
|
if (!preset) return [];
|
|
1019
1335
|
const args = ["--permission-mode", preset.permissionMode];
|
|
1020
1336
|
if (preset.permissions.allow.length > 0) {
|
|
@@ -1028,9 +1344,9 @@ function buildPermArgs(modeName) {
|
|
|
1028
1344
|
return args;
|
|
1029
1345
|
}
|
|
1030
1346
|
function ensureSessionsDir() {
|
|
1031
|
-
const dir =
|
|
1032
|
-
if (!
|
|
1033
|
-
|
|
1347
|
+
const dir = path4.join(ensureCcemDir(), "sessions");
|
|
1348
|
+
if (!fs4.existsSync(dir)) {
|
|
1349
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
1034
1350
|
}
|
|
1035
1351
|
return dir;
|
|
1036
1352
|
}
|
|
@@ -1043,7 +1359,7 @@ async function launchClaude(options) {
|
|
|
1043
1359
|
delete env.CLAUDECODE;
|
|
1044
1360
|
const args = [];
|
|
1045
1361
|
if (permMode) {
|
|
1046
|
-
const preset =
|
|
1362
|
+
const preset = PERMISSION_PRESETS[permMode];
|
|
1047
1363
|
if (preset) {
|
|
1048
1364
|
if (!silent) {
|
|
1049
1365
|
console.log(chalk2.green(`\u5DF2\u5E94\u7528 ${preset.name}\uFF08\u4E34\u65F6\uFF09`));
|
|
@@ -1066,14 +1382,15 @@ async function launchClaude(options) {
|
|
|
1066
1382
|
return new Promise((resolve2) => {
|
|
1067
1383
|
const child = spawn("claude", args, {
|
|
1068
1384
|
stdio: "inherit",
|
|
1069
|
-
shell:
|
|
1385
|
+
shell: false,
|
|
1386
|
+
// 直接执行二进制,避免 shell 注入风险
|
|
1070
1387
|
env
|
|
1071
1388
|
});
|
|
1072
1389
|
child.on("exit", (code) => {
|
|
1073
1390
|
if (sessionId) {
|
|
1074
1391
|
try {
|
|
1075
|
-
|
|
1076
|
-
|
|
1392
|
+
fs4.writeFileSync(
|
|
1393
|
+
path4.join(sessionsDir, `${sessionId}.exit`),
|
|
1077
1394
|
String(code ?? 0)
|
|
1078
1395
|
);
|
|
1079
1396
|
} catch {
|
|
@@ -1090,14 +1407,14 @@ async function launchClaude(options) {
|
|
|
1090
1407
|
|
|
1091
1408
|
// src/permissions.ts
|
|
1092
1409
|
var readSettings = (settingsPath) => {
|
|
1093
|
-
if (
|
|
1410
|
+
if (fs5.existsSync(settingsPath)) {
|
|
1094
1411
|
try {
|
|
1095
|
-
const content =
|
|
1412
|
+
const content = fs5.readFileSync(settingsPath, "utf-8");
|
|
1096
1413
|
return JSON.parse(content);
|
|
1097
1414
|
} catch {
|
|
1098
1415
|
console.warn(chalk3.yellow(`\u8B66\u544A: \u65E0\u6CD5\u89E3\u6790 ${settingsPath}\uFF0C\u5C06\u521B\u5EFA\u5907\u4EFD`));
|
|
1099
1416
|
const backupPath = settingsPath + ".error." + Date.now();
|
|
1100
|
-
|
|
1417
|
+
fs5.copyFileSync(settingsPath, backupPath);
|
|
1101
1418
|
console.log(chalk3.gray(`\u5907\u4EFD\u5DF2\u4FDD\u5B58\u5230: ${backupPath}`));
|
|
1102
1419
|
return {};
|
|
1103
1420
|
}
|
|
@@ -1106,7 +1423,7 @@ var readSettings = (settingsPath) => {
|
|
|
1106
1423
|
};
|
|
1107
1424
|
var writeSettings = (settingsPath, config3) => {
|
|
1108
1425
|
ensureClaudeDir();
|
|
1109
|
-
|
|
1426
|
+
fs5.writeFileSync(settingsPath, JSON.stringify(config3, null, 2) + "\n");
|
|
1110
1427
|
};
|
|
1111
1428
|
var mergePermissions = (existing, preset) => {
|
|
1112
1429
|
const existingAllow = existing.permissions?.allow || [];
|
|
@@ -1122,7 +1439,7 @@ var mergePermissions = (existing, preset) => {
|
|
|
1122
1439
|
};
|
|
1123
1440
|
};
|
|
1124
1441
|
var applyPermissionMode = (modeName) => {
|
|
1125
|
-
const preset =
|
|
1442
|
+
const preset = PERMISSION_PRESETS[modeName];
|
|
1126
1443
|
if (!preset) {
|
|
1127
1444
|
console.error(chalk3.red(`\u672A\u77E5\u7684\u6743\u9650\u6A21\u5F0F: ${modeName}`));
|
|
1128
1445
|
console.log(chalk3.yellow("\u53EF\u7528\u6A21\u5F0F: " + getPermissionModeNames().join(", ")));
|
|
@@ -1138,14 +1455,14 @@ var applyPermissionMode = (modeName) => {
|
|
|
1138
1455
|
};
|
|
1139
1456
|
var resetPermissions = () => {
|
|
1140
1457
|
const settingsPath = getSettingsPath(true);
|
|
1141
|
-
if (!
|
|
1458
|
+
if (!fs5.existsSync(settingsPath)) {
|
|
1142
1459
|
console.log(chalk3.yellow("\u6CA1\u6709\u81EA\u5B9A\u4E49\u6743\u9650\u914D\u7F6E\u9700\u8981\u91CD\u7F6E"));
|
|
1143
1460
|
return;
|
|
1144
1461
|
}
|
|
1145
1462
|
const config3 = readSettings(settingsPath);
|
|
1146
1463
|
delete config3.permissions;
|
|
1147
1464
|
if (Object.keys(config3).length === 0) {
|
|
1148
|
-
|
|
1465
|
+
fs5.unlinkSync(settingsPath);
|
|
1149
1466
|
console.log(chalk3.green("\u5DF2\u5220\u9664\u914D\u7F6E\u6587\u4EF6\uFF08\u6587\u4EF6\u4E3A\u7A7A\uFF09"));
|
|
1150
1467
|
} else {
|
|
1151
1468
|
writeSettings(settingsPath, config3);
|
|
@@ -1155,7 +1472,7 @@ var resetPermissions = () => {
|
|
|
1155
1472
|
};
|
|
1156
1473
|
var showCurrentMode = () => {
|
|
1157
1474
|
const settingsPath = getSettingsPath(true);
|
|
1158
|
-
if (!
|
|
1475
|
+
if (!fs5.existsSync(settingsPath)) {
|
|
1159
1476
|
console.log(chalk3.yellow("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49\u6743\u9650"));
|
|
1160
1477
|
console.log(chalk3.gray(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${settingsPath}`));
|
|
1161
1478
|
return;
|
|
@@ -1165,7 +1482,7 @@ var showCurrentMode = () => {
|
|
|
1165
1482
|
console.log(chalk3.yellow("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49\u6743\u9650"));
|
|
1166
1483
|
return;
|
|
1167
1484
|
}
|
|
1168
|
-
const matchedPreset = Object.entries(
|
|
1485
|
+
const matchedPreset = Object.entries(PERMISSION_PRESETS).find(([_, preset]) => {
|
|
1169
1486
|
const configAllow = new Set(config3.permissions?.allow || []);
|
|
1170
1487
|
const configDeny = new Set(config3.permissions?.deny || []);
|
|
1171
1488
|
const presetAllow = new Set(preset.permissions.allow);
|
|
@@ -1197,7 +1514,7 @@ var listAvailableModes = () => {
|
|
|
1197
1514
|
style: { head: ["cyan"] },
|
|
1198
1515
|
colWidths: [15, 15, 50]
|
|
1199
1516
|
});
|
|
1200
|
-
Object.entries(
|
|
1517
|
+
Object.entries(PERMISSION_PRESETS).forEach(([key, preset]) => {
|
|
1201
1518
|
table.push([preset.name, `--${key}`, preset.description]);
|
|
1202
1519
|
});
|
|
1203
1520
|
console.log(chalk3.bold("\u53EF\u7528\u6743\u9650\u6A21\u5F0F:\n"));
|
|
@@ -1206,7 +1523,7 @@ var listAvailableModes = () => {
|
|
|
1206
1523
|
console.log(chalk3.gray("\u6C38\u4E45\u6A21\u5F0F: ccem setup perms --<mode>"));
|
|
1207
1524
|
};
|
|
1208
1525
|
var runWithTempPermissions = async (modeName, envConfig) => {
|
|
1209
|
-
const preset =
|
|
1526
|
+
const preset = PERMISSION_PRESETS[modeName];
|
|
1210
1527
|
if (!preset) {
|
|
1211
1528
|
console.error(chalk3.red(`\u672A\u77E5\u7684\u6743\u9650\u6A21\u5F0F: ${modeName}`));
|
|
1212
1529
|
console.log(chalk3.yellow("\u53EF\u7528\u6A21\u5F0F: " + getPermissionModeNames().join(", ")));
|
|
@@ -1216,13 +1533,13 @@ var runWithTempPermissions = async (modeName, envConfig) => {
|
|
|
1216
1533
|
};
|
|
1217
1534
|
|
|
1218
1535
|
// src/setup.ts
|
|
1219
|
-
import
|
|
1536
|
+
import fs6 from "fs";
|
|
1220
1537
|
import chalk4 from "chalk";
|
|
1221
1538
|
import { spawn as spawn2 } from "child_process";
|
|
1222
1539
|
var readJsonFile = (filePath) => {
|
|
1223
|
-
if (
|
|
1540
|
+
if (fs6.existsSync(filePath)) {
|
|
1224
1541
|
try {
|
|
1225
|
-
const content =
|
|
1542
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
1226
1543
|
return JSON.parse(content);
|
|
1227
1544
|
} catch {
|
|
1228
1545
|
console.warn(chalk4.yellow(`\u8B66\u544A: \u65E0\u6CD5\u89E3\u6790 ${filePath}`));
|
|
@@ -1232,7 +1549,7 @@ var readJsonFile = (filePath) => {
|
|
|
1232
1549
|
return {};
|
|
1233
1550
|
};
|
|
1234
1551
|
var writeJsonFile = (filePath, data) => {
|
|
1235
|
-
|
|
1552
|
+
fs6.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n");
|
|
1236
1553
|
};
|
|
1237
1554
|
var setupOnboarding = () => {
|
|
1238
1555
|
const configPath = getGlobalClaudeConfigPath();
|
|
@@ -1354,8 +1671,8 @@ var runSetupInit = async () => {
|
|
|
1354
1671
|
|
|
1355
1672
|
// src/skills.ts
|
|
1356
1673
|
import { execSync } from "child_process";
|
|
1357
|
-
import * as
|
|
1358
|
-
import * as
|
|
1674
|
+
import * as fs7 from "fs";
|
|
1675
|
+
import * as path5 from "path";
|
|
1359
1676
|
import chalk5 from "chalk";
|
|
1360
1677
|
var SKILL_GROUPS = {
|
|
1361
1678
|
official: { label: "\u5B98\u65B9", icon: "\u{1F3E2}" },
|
|
@@ -1524,12 +1841,12 @@ function parseGitHubUrl(url) {
|
|
|
1524
1841
|
};
|
|
1525
1842
|
}
|
|
1526
1843
|
function getSkillsDir() {
|
|
1527
|
-
return
|
|
1844
|
+
return path5.join(process.cwd(), ".claude", "skills");
|
|
1528
1845
|
}
|
|
1529
1846
|
function ensureSkillsDir() {
|
|
1530
1847
|
const skillsDir = getSkillsDir();
|
|
1531
|
-
if (!
|
|
1532
|
-
|
|
1848
|
+
if (!fs7.existsSync(skillsDir)) {
|
|
1849
|
+
fs7.mkdirSync(skillsDir, { recursive: true });
|
|
1533
1850
|
} else {
|
|
1534
1851
|
cleanupTempDirs(skillsDir);
|
|
1535
1852
|
}
|
|
@@ -1537,11 +1854,11 @@ function ensureSkillsDir() {
|
|
|
1537
1854
|
}
|
|
1538
1855
|
function cleanupTempDirs(skillsDir) {
|
|
1539
1856
|
try {
|
|
1540
|
-
const entries =
|
|
1857
|
+
const entries = fs7.readdirSync(skillsDir, { withFileTypes: true });
|
|
1541
1858
|
for (const entry of entries) {
|
|
1542
1859
|
if (entry.isDirectory() && entry.name.startsWith(".tmp-")) {
|
|
1543
|
-
const tmpPath =
|
|
1544
|
-
|
|
1860
|
+
const tmpPath = path5.join(skillsDir, entry.name);
|
|
1861
|
+
fs7.rmSync(tmpPath, { recursive: true });
|
|
1545
1862
|
}
|
|
1546
1863
|
}
|
|
1547
1864
|
} catch {
|
|
@@ -1549,24 +1866,24 @@ function cleanupTempDirs(skillsDir) {
|
|
|
1549
1866
|
}
|
|
1550
1867
|
function downloadSkillWithGit(owner, repo, branch, repoPath, targetName) {
|
|
1551
1868
|
const skillsDir = ensureSkillsDir();
|
|
1552
|
-
const targetDir =
|
|
1553
|
-
if (
|
|
1869
|
+
const targetDir = path5.join(skillsDir, targetName);
|
|
1870
|
+
if (fs7.existsSync(targetDir)) {
|
|
1554
1871
|
console.log(chalk5.yellow(`Skill "${targetName}" already exists. Updating...`));
|
|
1555
|
-
|
|
1872
|
+
fs7.rmSync(targetDir, { recursive: true });
|
|
1556
1873
|
}
|
|
1557
1874
|
const repoUrl = `https://github.com/${owner}/${repo}.git`;
|
|
1558
|
-
const tempDir =
|
|
1875
|
+
const tempDir = path5.join(skillsDir, `.tmp-${Date.now()}`);
|
|
1559
1876
|
try {
|
|
1560
|
-
|
|
1877
|
+
fs7.mkdirSync(tempDir, { recursive: true });
|
|
1561
1878
|
execSync(`git init`, { cwd: tempDir, stdio: "pipe" });
|
|
1562
1879
|
execSync(`git remote add origin ${repoUrl}`, { cwd: tempDir, stdio: "pipe" });
|
|
1563
1880
|
execSync(`git config core.sparseCheckout true`, { cwd: tempDir, stdio: "pipe" });
|
|
1564
|
-
const sparseFile =
|
|
1565
|
-
|
|
1881
|
+
const sparseFile = path5.join(tempDir, ".git", "info", "sparse-checkout");
|
|
1882
|
+
fs7.writeFileSync(sparseFile, repoPath ? `${repoPath}/
|
|
1566
1883
|
` : "*\n");
|
|
1567
1884
|
execSync(`git pull --depth=1 origin ${branch}`, { cwd: tempDir, stdio: "pipe" });
|
|
1568
|
-
const sourceDir = repoPath ?
|
|
1569
|
-
if (!
|
|
1885
|
+
const sourceDir = repoPath ? path5.join(tempDir, repoPath) : tempDir;
|
|
1886
|
+
if (!fs7.existsSync(sourceDir)) {
|
|
1570
1887
|
throw new Error(`Path "${repoPath}" not found in repository`);
|
|
1571
1888
|
}
|
|
1572
1889
|
copyDir(sourceDir, targetDir);
|
|
@@ -1577,22 +1894,22 @@ function downloadSkillWithGit(owner, repo, branch, repoPath, targetName) {
|
|
|
1577
1894
|
console.error(chalk5.red(`Failed to download skill: ${errMsg}`));
|
|
1578
1895
|
return false;
|
|
1579
1896
|
} finally {
|
|
1580
|
-
if (
|
|
1581
|
-
|
|
1897
|
+
if (fs7.existsSync(tempDir)) {
|
|
1898
|
+
fs7.rmSync(tempDir, { recursive: true });
|
|
1582
1899
|
}
|
|
1583
1900
|
}
|
|
1584
1901
|
}
|
|
1585
1902
|
function copyDir(src, dest) {
|
|
1586
|
-
|
|
1587
|
-
const entries =
|
|
1903
|
+
fs7.mkdirSync(dest, { recursive: true });
|
|
1904
|
+
const entries = fs7.readdirSync(src, { withFileTypes: true });
|
|
1588
1905
|
for (const entry of entries) {
|
|
1589
1906
|
if (entry.name === ".git") continue;
|
|
1590
|
-
const srcPath =
|
|
1591
|
-
const destPath =
|
|
1907
|
+
const srcPath = path5.join(src, entry.name);
|
|
1908
|
+
const destPath = path5.join(dest, entry.name);
|
|
1592
1909
|
if (entry.isDirectory()) {
|
|
1593
1910
|
copyDir(srcPath, destPath);
|
|
1594
1911
|
} else {
|
|
1595
|
-
|
|
1912
|
+
fs7.copyFileSync(srcPath, destPath);
|
|
1596
1913
|
}
|
|
1597
1914
|
}
|
|
1598
1915
|
}
|
|
@@ -1638,7 +1955,7 @@ function addSkillFromGitHub(urlOrPreset) {
|
|
|
1638
1955
|
}
|
|
1639
1956
|
let skillName;
|
|
1640
1957
|
if (parsed.path) {
|
|
1641
|
-
skillName =
|
|
1958
|
+
skillName = path5.basename(parsed.path);
|
|
1642
1959
|
} else {
|
|
1643
1960
|
skillName = parsed.repo;
|
|
1644
1961
|
}
|
|
@@ -1652,23 +1969,23 @@ function addSkillFromGitHub(urlOrPreset) {
|
|
|
1652
1969
|
}
|
|
1653
1970
|
function listInstalledSkills() {
|
|
1654
1971
|
const skillsDir = getSkillsDir();
|
|
1655
|
-
if (!
|
|
1972
|
+
if (!fs7.existsSync(skillsDir)) {
|
|
1656
1973
|
return [];
|
|
1657
1974
|
}
|
|
1658
|
-
const entries =
|
|
1975
|
+
const entries = fs7.readdirSync(skillsDir, { withFileTypes: true });
|
|
1659
1976
|
return entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => ({
|
|
1660
1977
|
name: entry.name,
|
|
1661
|
-
path:
|
|
1978
|
+
path: path5.join(skillsDir, entry.name)
|
|
1662
1979
|
}));
|
|
1663
1980
|
}
|
|
1664
1981
|
function removeSkill(name) {
|
|
1665
1982
|
const skillsDir = getSkillsDir();
|
|
1666
|
-
const targetDir =
|
|
1667
|
-
if (!
|
|
1983
|
+
const targetDir = path5.join(skillsDir, name);
|
|
1984
|
+
if (!fs7.existsSync(targetDir)) {
|
|
1668
1985
|
console.error(chalk5.red(`Skill "${name}" not found`));
|
|
1669
1986
|
return false;
|
|
1670
1987
|
}
|
|
1671
|
-
|
|
1988
|
+
fs7.rmSync(targetDir, { recursive: true });
|
|
1672
1989
|
console.log(chalk5.green(`Removed skill "${name}"`));
|
|
1673
1990
|
return true;
|
|
1674
1991
|
}
|
|
@@ -1826,19 +2143,20 @@ async function runSkillSelector() {
|
|
|
1826
2143
|
}
|
|
1827
2144
|
|
|
1828
2145
|
// src/remote.ts
|
|
1829
|
-
import
|
|
2146
|
+
import crypto3 from "crypto";
|
|
1830
2147
|
import chalk6 from "chalk";
|
|
1831
2148
|
import Conf from "conf";
|
|
1832
|
-
import { encrypt } from "@ccem/core";
|
|
1833
2149
|
var config = new Conf({
|
|
1834
|
-
projectName: "claude-code-env-manager"
|
|
2150
|
+
projectName: "claude-code-env-manager",
|
|
2151
|
+
cwd: getCcemConfigDir()
|
|
2152
|
+
// 使用统一的配置目录
|
|
1835
2153
|
});
|
|
1836
2154
|
var decryptWithSecret = (encryptedBase64, secret) => {
|
|
1837
|
-
const key =
|
|
2155
|
+
const key = crypto3.scryptSync(secret, "ccem-salt", 32);
|
|
1838
2156
|
const combined = Buffer.from(encryptedBase64, "base64");
|
|
1839
2157
|
const iv = combined.subarray(0, 16);
|
|
1840
2158
|
const encryptedHex = combined.subarray(16).toString("hex");
|
|
1841
|
-
const decipher =
|
|
2159
|
+
const decipher = crypto3.createDecipheriv("aes-256-cbc", key, iv);
|
|
1842
2160
|
let decrypted = decipher.update(encryptedHex, "hex", "utf8");
|
|
1843
2161
|
decrypted += decipher.final("utf8");
|
|
1844
2162
|
return decrypted;
|
|
@@ -1859,7 +2177,11 @@ var loadFromRemote = async (url, secret) => {
|
|
|
1859
2177
|
console.log(chalk6.gray("Fetching from remote..."));
|
|
1860
2178
|
let response;
|
|
1861
2179
|
try {
|
|
1862
|
-
response = await fetch(url
|
|
2180
|
+
response = await fetch(url, {
|
|
2181
|
+
headers: {
|
|
2182
|
+
"X-CCEM-Key": secret
|
|
2183
|
+
}
|
|
2184
|
+
});
|
|
1863
2185
|
} catch (err) {
|
|
1864
2186
|
console.error(chalk6.red("Error: Failed to connect to server"));
|
|
1865
2187
|
console.error(chalk6.gray(err.message));
|
|
@@ -1929,6 +2251,7 @@ Loaded ${results.length} environment(s) from remote:`));
|
|
|
1929
2251
|
}
|
|
1930
2252
|
}
|
|
1931
2253
|
console.log(chalk6.gray("\nRun 'ccem ls' to see all environments."));
|
|
2254
|
+
return results;
|
|
1932
2255
|
};
|
|
1933
2256
|
|
|
1934
2257
|
// src/cron-skill.ts
|
|
@@ -2074,12 +2397,12 @@ Replace \\\`TARGET_ID\\\` or \\\`TARGET_NAME\\\` with the user's selection.
|
|
|
2074
2397
|
`;
|
|
2075
2398
|
|
|
2076
2399
|
// src/index.ts
|
|
2077
|
-
var
|
|
2078
|
-
var __dirname2 =
|
|
2079
|
-
var pkgPath =
|
|
2080
|
-
var pkg = JSON.parse(
|
|
2400
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
2401
|
+
var __dirname2 = path6.dirname(__filename2);
|
|
2402
|
+
var pkgPath = path6.resolve(__dirname2, "..", "package.json");
|
|
2403
|
+
var pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
2081
2404
|
var program = new Command();
|
|
2082
|
-
|
|
2405
|
+
ensureCcemDir();
|
|
2083
2406
|
var config2 = new Conf2({
|
|
2084
2407
|
projectName: "claude-code-env-manager",
|
|
2085
2408
|
cwd: getCcemConfigDir(),
|
|
@@ -2132,7 +2455,7 @@ var initUsageStats = (onUpdate) => {
|
|
|
2132
2455
|
};
|
|
2133
2456
|
program.name("ccem").description("Claude Code Environment Manager - \u7BA1\u7406 Claude Code \u73AF\u5883\u53D8\u91CF\u548C\u6743\u9650").version(pkg.version).option("--mode", "\u67E5\u770B\u5F53\u524D\u6743\u9650\u6A21\u5F0F").option("--list-modes", "\u5217\u51FA\u6240\u6709\u53EF\u7528\u6743\u9650\u6A21\u5F0F");
|
|
2134
2457
|
PERMISSION_MODES.forEach((mode) => {
|
|
2135
|
-
const preset =
|
|
2458
|
+
const preset = PERMISSION_PRESETS[mode];
|
|
2136
2459
|
program.command(mode).description(`\u4E34\u65F6\u5E94\u7528 ${preset.name}\uFF0C\u9000\u51FA\u540E\u8FD8\u539F`).action(async () => {
|
|
2137
2460
|
const registries = config2.get("registries");
|
|
2138
2461
|
const current = config2.get("current");
|
|
@@ -2149,7 +2472,7 @@ var showCurrentEnv = (usageStats2, usageLoading2) => {
|
|
|
2149
2472
|
if (!env) return;
|
|
2150
2473
|
console.log(renderLogoWithEnvPanel(current, {
|
|
2151
2474
|
ANTHROPIC_BASE_URL: env.ANTHROPIC_BASE_URL,
|
|
2152
|
-
ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY ?
|
|
2475
|
+
ANTHROPIC_API_KEY: env.ANTHROPIC_API_KEY ? decrypt(env.ANTHROPIC_API_KEY) : void 0,
|
|
2153
2476
|
ANTHROPIC_MODEL: env.ANTHROPIC_MODEL,
|
|
2154
2477
|
ANTHROPIC_SMALL_FAST_MODEL: env.ANTHROPIC_SMALL_FAST_MODEL
|
|
2155
2478
|
}, defaultMode));
|
|
@@ -2174,7 +2497,7 @@ var switchEnvironment = async (name) => {
|
|
|
2174
2497
|
const env = registries[name];
|
|
2175
2498
|
const exportCmds = [];
|
|
2176
2499
|
if (env.ANTHROPIC_BASE_URL) exportCmds.push(`export ANTHROPIC_BASE_URL="${env.ANTHROPIC_BASE_URL}"`);
|
|
2177
|
-
if (env.ANTHROPIC_API_KEY) exportCmds.push(`export ANTHROPIC_API_KEY="${
|
|
2500
|
+
if (env.ANTHROPIC_API_KEY) exportCmds.push(`export ANTHROPIC_API_KEY="${decrypt(env.ANTHROPIC_API_KEY)}"`);
|
|
2178
2501
|
if (env.ANTHROPIC_MODEL) exportCmds.push(`export ANTHROPIC_MODEL="${env.ANTHROPIC_MODEL}"`);
|
|
2179
2502
|
if (env.ANTHROPIC_SMALL_FAST_MODEL) exportCmds.push(`export ANTHROPIC_SMALL_FAST_MODEL="${env.ANTHROPIC_SMALL_FAST_MODEL}"`);
|
|
2180
2503
|
if (process.stdout.isTTY) {
|
|
@@ -2259,7 +2582,7 @@ program.command("add <name>").description("Add a new environment configuration")
|
|
|
2259
2582
|
}
|
|
2260
2583
|
]);
|
|
2261
2584
|
if (answers.ANTHROPIC_API_KEY) {
|
|
2262
|
-
answers.ANTHROPIC_API_KEY =
|
|
2585
|
+
answers.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
|
|
2263
2586
|
}
|
|
2264
2587
|
registries[name] = answers;
|
|
2265
2588
|
config2.set("registries", registries);
|
|
@@ -2356,7 +2679,7 @@ program.command("cp <source> <target>").description("Copy an environment configu
|
|
|
2356
2679
|
}
|
|
2357
2680
|
]);
|
|
2358
2681
|
if (answers.ANTHROPIC_BASE_URL) current.ANTHROPIC_BASE_URL = answers.ANTHROPIC_BASE_URL;
|
|
2359
|
-
if (answers.ANTHROPIC_API_KEY) current.ANTHROPIC_API_KEY =
|
|
2682
|
+
if (answers.ANTHROPIC_API_KEY) current.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
|
|
2360
2683
|
if (answers.ANTHROPIC_MODEL) current.ANTHROPIC_MODEL = answers.ANTHROPIC_MODEL;
|
|
2361
2684
|
if (answers.ANTHROPIC_SMALL_FAST_MODEL) current.ANTHROPIC_SMALL_FAST_MODEL = answers.ANTHROPIC_SMALL_FAST_MODEL;
|
|
2362
2685
|
registries[target] = current;
|
|
@@ -2375,7 +2698,7 @@ program.command("env").description("Output environment variables for shell eval"
|
|
|
2375
2698
|
if (!env) return;
|
|
2376
2699
|
const outputEnv = { ...env };
|
|
2377
2700
|
if (outputEnv.ANTHROPIC_API_KEY) {
|
|
2378
|
-
outputEnv.ANTHROPIC_API_KEY =
|
|
2701
|
+
outputEnv.ANTHROPIC_API_KEY = decrypt(outputEnv.ANTHROPIC_API_KEY);
|
|
2379
2702
|
}
|
|
2380
2703
|
if (options.json) {
|
|
2381
2704
|
console.log(JSON.stringify(outputEnv, null, 2));
|
|
@@ -2396,7 +2719,7 @@ program.command("run <command...>").description("Run a command with the current
|
|
|
2396
2719
|
}
|
|
2397
2720
|
const env = { ...process.env };
|
|
2398
2721
|
if (envConfig.ANTHROPIC_BASE_URL) env.ANTHROPIC_BASE_URL = envConfig.ANTHROPIC_BASE_URL;
|
|
2399
|
-
if (envConfig.ANTHROPIC_API_KEY) env.ANTHROPIC_API_KEY =
|
|
2722
|
+
if (envConfig.ANTHROPIC_API_KEY) env.ANTHROPIC_API_KEY = decrypt(envConfig.ANTHROPIC_API_KEY || "");
|
|
2400
2723
|
if (envConfig.ANTHROPIC_MODEL) env.ANTHROPIC_MODEL = envConfig.ANTHROPIC_MODEL;
|
|
2401
2724
|
if (envConfig.ANTHROPIC_SMALL_FAST_MODEL) env.ANTHROPIC_SMALL_FAST_MODEL = envConfig.ANTHROPIC_SMALL_FAST_MODEL;
|
|
2402
2725
|
const [cmd, ...args] = command;
|
|
@@ -2436,14 +2759,14 @@ setupCmd.command("default-mode").description("\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u96
|
|
|
2436
2759
|
for (const mode of PERMISSION_MODES) {
|
|
2437
2760
|
if (options[mode]) {
|
|
2438
2761
|
config2.set("defaultMode", mode);
|
|
2439
|
-
console.log(chalk7.green(`\u5DF2\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F: ${
|
|
2762
|
+
console.log(chalk7.green(`\u5DF2\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F: ${PERMISSION_PRESETS[mode].name}`));
|
|
2440
2763
|
console.log(chalk7.gray(`\u4E0B\u6B21\u542F\u52A8 ccem \u65F6\u5C06\u9ED8\u8BA4\u4F7F\u7528\u6B64\u6A21\u5F0F`));
|
|
2441
2764
|
return;
|
|
2442
2765
|
}
|
|
2443
2766
|
}
|
|
2444
2767
|
const currentDefault = config2.get("defaultMode");
|
|
2445
|
-
if (currentDefault &&
|
|
2446
|
-
console.log(chalk7.green(`\u5F53\u524D\u9ED8\u8BA4\u6A21\u5F0F: ${
|
|
2768
|
+
if (currentDefault && PERMISSION_PRESETS[currentDefault]) {
|
|
2769
|
+
console.log(chalk7.green(`\u5F53\u524D\u9ED8\u8BA4\u6A21\u5F0F: ${PERMISSION_PRESETS[currentDefault].name}`));
|
|
2447
2770
|
} else {
|
|
2448
2771
|
console.log(chalk7.yellow("\u672A\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F"));
|
|
2449
2772
|
}
|
|
@@ -2459,28 +2782,28 @@ setupCmd.command("migrate").description("\u8FC1\u79FB\u65E7\u7248\u914D\u7F6E\u5
|
|
|
2459
2782
|
const newConfigPath = getCcemConfigPath();
|
|
2460
2783
|
const legacyConfigPath = getLegacyConfigPath();
|
|
2461
2784
|
console.log(chalk7.cyan("\n\u{1F504} \u914D\u7F6E\u8FC1\u79FB\n"));
|
|
2462
|
-
if (!
|
|
2785
|
+
if (!fs8.existsSync(legacyConfigPath)) {
|
|
2463
2786
|
console.log(chalk7.yellow("\u672A\u627E\u5230\u65E7\u7248\u914D\u7F6E\u6587\u4EF6"));
|
|
2464
2787
|
console.log(chalk7.gray(` \u65E7\u8DEF\u5F84: ${legacyConfigPath}`));
|
|
2465
2788
|
return;
|
|
2466
2789
|
}
|
|
2467
|
-
if (
|
|
2790
|
+
if (fs8.existsSync(newConfigPath) && !options.force) {
|
|
2468
2791
|
console.log(chalk7.green("\u2713 \u914D\u7F6E\u5DF2\u5728\u65B0\u8DEF\u5F84"));
|
|
2469
2792
|
console.log(chalk7.gray(` \u8DEF\u5F84: ${newConfigPath}`));
|
|
2470
2793
|
console.log(chalk7.gray("\n\u4F7F\u7528 --force \u5F3A\u5236\u91CD\u65B0\u8FC1\u79FB"));
|
|
2471
2794
|
return;
|
|
2472
2795
|
}
|
|
2473
2796
|
try {
|
|
2474
|
-
|
|
2475
|
-
|
|
2797
|
+
ensureCcemDir();
|
|
2798
|
+
fs8.copyFileSync(legacyConfigPath, newConfigPath);
|
|
2476
2799
|
console.log(chalk7.green("\u2713 \u914D\u7F6E\u5DF2\u8FC1\u79FB"));
|
|
2477
2800
|
console.log(chalk7.gray(` \u4ECE: ${legacyConfigPath}`));
|
|
2478
2801
|
console.log(chalk7.gray(` \u5230: ${newConfigPath}`));
|
|
2479
2802
|
if (options.clean) {
|
|
2480
|
-
|
|
2481
|
-
const legacyDir =
|
|
2803
|
+
fs8.unlinkSync(legacyConfigPath);
|
|
2804
|
+
const legacyDir = path6.dirname(legacyConfigPath);
|
|
2482
2805
|
try {
|
|
2483
|
-
|
|
2806
|
+
fs8.rmdirSync(legacyDir);
|
|
2484
2807
|
} catch {
|
|
2485
2808
|
}
|
|
2486
2809
|
console.log(chalk7.green("\u2713 \u5DF2\u5220\u9664\u65E7\u914D\u7F6E\u6587\u4EF6"));
|
|
@@ -2491,13 +2814,13 @@ setupCmd.command("migrate").description("\u8FC1\u79FB\u65E7\u7248\u914D\u7F6E\u5
|
|
|
2491
2814
|
});
|
|
2492
2815
|
setupCmd.command("cron").description("\u5B89\u88C5 ccem-cron skill \u5230 Claude Code\uFF08~/.claude/skills/\uFF09").option("--force", "\u5F3A\u5236\u8986\u76D6\u5DF2\u6709\u6587\u4EF6").action(async function() {
|
|
2493
2816
|
const options = this.opts();
|
|
2494
|
-
const skillDir =
|
|
2495
|
-
const targetPath =
|
|
2496
|
-
if (!
|
|
2497
|
-
|
|
2817
|
+
const skillDir = path6.join(process.env.HOME || "~", ".claude", "skills");
|
|
2818
|
+
const targetPath = path6.join(skillDir, "ccem-cron.md");
|
|
2819
|
+
if (!fs8.existsSync(skillDir)) {
|
|
2820
|
+
fs8.mkdirSync(skillDir, { recursive: true });
|
|
2498
2821
|
console.log(chalk7.gray(`\u521B\u5EFA\u76EE\u5F55: ${skillDir}`));
|
|
2499
2822
|
}
|
|
2500
|
-
if (
|
|
2823
|
+
if (fs8.existsSync(targetPath) && !options.force) {
|
|
2501
2824
|
const { overwrite } = await inquirer.prompt([
|
|
2502
2825
|
{
|
|
2503
2826
|
type: "confirm",
|
|
@@ -2511,7 +2834,7 @@ setupCmd.command("cron").description("\u5B89\u88C5 ccem-cron skill \u5230 Claude
|
|
|
2511
2834
|
return;
|
|
2512
2835
|
}
|
|
2513
2836
|
}
|
|
2514
|
-
|
|
2837
|
+
fs8.writeFileSync(targetPath, CCEM_CRON_SKILL_CONTENT, "utf-8");
|
|
2515
2838
|
console.log(chalk7.green(`\u2713 \u5DF2\u5B89\u88C5 ccem-cron skill`));
|
|
2516
2839
|
console.log(chalk7.gray(` \u8DEF\u5F84: ${targetPath}`));
|
|
2517
2840
|
console.log(chalk7.cyan(`
|
|
@@ -2567,10 +2890,21 @@ skillCmd.command("ls").description("\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 skills"
|
|
|
2567
2890
|
skillCmd.command("rm <name>").description("\u5220\u9664\u5DF2\u5B89\u88C5\u7684 skill").action((name) => {
|
|
2568
2891
|
removeSkill(name);
|
|
2569
2892
|
});
|
|
2570
|
-
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) => {
|
|
2571
|
-
await loadFromRemote(url, options.secret);
|
|
2893
|
+
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) => {
|
|
2894
|
+
const results = await loadFromRemote(url, options.secret);
|
|
2895
|
+
if (options.json) {
|
|
2896
|
+
console.log(JSON.stringify({
|
|
2897
|
+
count: results.length,
|
|
2898
|
+
environments: results.map((r) => ({
|
|
2899
|
+
name: r.name,
|
|
2900
|
+
original_name: r.originalName,
|
|
2901
|
+
// 使用 snake_case 匹配 Rust 结构体
|
|
2902
|
+
renamed: r.renamed
|
|
2903
|
+
}))
|
|
2904
|
+
}));
|
|
2905
|
+
}
|
|
2572
2906
|
});
|
|
2573
|
-
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() {
|
|
2907
|
+
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() {
|
|
2574
2908
|
const opts = this.opts();
|
|
2575
2909
|
const envName = opts.env || config2.get("current");
|
|
2576
2910
|
const registries = config2.get("registries");
|
|
@@ -2579,8 +2913,10 @@ program.command("launch").description(false).option("--env <name>", "\u73AF\u588
|
|
|
2579
2913
|
console.error(chalk7.red(`Environment '${envName}' not found.`));
|
|
2580
2914
|
process.exit(1);
|
|
2581
2915
|
}
|
|
2916
|
+
const proxyBaseUrl = opts.proxyBaseUrl || opts.anthropicBaseUrl;
|
|
2917
|
+
const launchEnvConfig = proxyBaseUrl ? { ...envConfig, ANTHROPIC_BASE_URL: proxyBaseUrl } : envConfig;
|
|
2582
2918
|
await launchClaude({
|
|
2583
|
-
envConfig,
|
|
2919
|
+
envConfig: launchEnvConfig,
|
|
2584
2920
|
permMode: opts.perm,
|
|
2585
2921
|
workingDir: opts.workingDir,
|
|
2586
2922
|
sessionId: opts.sessionId,
|
|
@@ -2689,7 +3025,7 @@ Editing environment '${result.name}'`));
|
|
|
2689
3025
|
}
|
|
2690
3026
|
]);
|
|
2691
3027
|
if (answers.ANTHROPIC_BASE_URL) envToEdit.ANTHROPIC_BASE_URL = answers.ANTHROPIC_BASE_URL;
|
|
2692
|
-
if (answers.ANTHROPIC_API_KEY) envToEdit.ANTHROPIC_API_KEY =
|
|
3028
|
+
if (answers.ANTHROPIC_API_KEY) envToEdit.ANTHROPIC_API_KEY = encrypt(answers.ANTHROPIC_API_KEY);
|
|
2693
3029
|
if (answers.ANTHROPIC_MODEL) envToEdit.ANTHROPIC_MODEL = answers.ANTHROPIC_MODEL;
|
|
2694
3030
|
if (answers.ANTHROPIC_SMALL_FAST_MODEL) envToEdit.ANTHROPIC_SMALL_FAST_MODEL = answers.ANTHROPIC_SMALL_FAST_MODEL;
|
|
2695
3031
|
registries[result.name] = envToEdit;
|
|
@@ -2774,7 +3110,7 @@ Editing environment '${result.name}'`));
|
|
|
2774
3110
|
}
|
|
2775
3111
|
]);
|
|
2776
3112
|
if (editAnswers.ANTHROPIC_BASE_URL) envToEdit.ANTHROPIC_BASE_URL = editAnswers.ANTHROPIC_BASE_URL;
|
|
2777
|
-
if (editAnswers.ANTHROPIC_API_KEY) envToEdit.ANTHROPIC_API_KEY =
|
|
3113
|
+
if (editAnswers.ANTHROPIC_API_KEY) envToEdit.ANTHROPIC_API_KEY = encrypt(editAnswers.ANTHROPIC_API_KEY);
|
|
2778
3114
|
if (editAnswers.ANTHROPIC_MODEL) envToEdit.ANTHROPIC_MODEL = editAnswers.ANTHROPIC_MODEL;
|
|
2779
3115
|
if (editAnswers.ANTHROPIC_SMALL_FAST_MODEL) envToEdit.ANTHROPIC_SMALL_FAST_MODEL = editAnswers.ANTHROPIC_SMALL_FAST_MODEL;
|
|
2780
3116
|
registries[targetName] = envToEdit;
|
|
@@ -2839,7 +3175,7 @@ Editing environment '${result.name}'`));
|
|
|
2839
3175
|
await new Promise((resolve2) => setTimeout(resolve2, 800));
|
|
2840
3176
|
} else if (selectedMode !== "back") {
|
|
2841
3177
|
config2.set("defaultMode", selectedMode);
|
|
2842
|
-
msg.success(`Default mode set: ${
|
|
3178
|
+
msg.success(`Default mode set: ${PERMISSION_PRESETS[selectedMode].name}`);
|
|
2843
3179
|
await new Promise((resolve2) => setTimeout(resolve2, 800));
|
|
2844
3180
|
}
|
|
2845
3181
|
} else {
|
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.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Claude Code Environment Manager",
|
|
6
6
|
"author": {
|
|
@@ -16,18 +16,7 @@
|
|
|
16
16
|
"bin": {
|
|
17
17
|
"ccem": "./dist/index.js"
|
|
18
18
|
},
|
|
19
|
-
"scripts": {
|
|
20
|
-
"generate-logo": "bash scripts/generate-logo.sh",
|
|
21
|
-
"build": "tsup",
|
|
22
|
-
"dev": "tsup --watch",
|
|
23
|
-
"start": "node dist/index.js",
|
|
24
|
-
"postinstall": "node ./scripts/migrate.js",
|
|
25
|
-
"test": "vitest",
|
|
26
|
-
"test:run": "vitest run",
|
|
27
|
-
"test:coverage": "vitest run --coverage"
|
|
28
|
-
},
|
|
29
19
|
"dependencies": {
|
|
30
|
-
"@ccem/core": "workspace:*",
|
|
31
20
|
"chalk": "^4.1.2",
|
|
32
21
|
"cli-table3": "^0.6.3",
|
|
33
22
|
"commander": "^12.0.0",
|
|
@@ -46,6 +35,17 @@
|
|
|
46
35
|
"asciify-image": "^0.1.10",
|
|
47
36
|
"tsup": "^8.0.2",
|
|
48
37
|
"typescript": "^5.3.3",
|
|
49
|
-
"vitest": "^4.0.18"
|
|
38
|
+
"vitest": "^4.0.18",
|
|
39
|
+
"@ccem/core": "2.0.0-beta.3"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"generate-logo": "bash scripts/generate-logo.sh",
|
|
43
|
+
"build": "tsup",
|
|
44
|
+
"dev": "tsup --watch",
|
|
45
|
+
"start": "node dist/index.js",
|
|
46
|
+
"postinstall": "node ./scripts/migrate.js",
|
|
47
|
+
"test": "vitest",
|
|
48
|
+
"test:run": "vitest run",
|
|
49
|
+
"test:coverage": "vitest run --coverage"
|
|
50
50
|
}
|
|
51
|
-
}
|
|
51
|
+
}
|