ccem 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +198 -27
  2. package/dist/index.js +22 -18
  3. package/package.json +4 -1
package/README.md CHANGED
@@ -4,18 +4,32 @@
4
4
 
5
5
  切换 API 服务商、配置权限模式、查看用量统计、安装 Skills。
6
6
 
7
+ [![npm version](https://img.shields.io/npm/v/ccem.svg)](https://www.npmjs.com/package/ccem)
8
+ [![license](https://img.shields.io/npm/l/ccem.svg)](https://github.com/genuifx/claude-code-env-manager/blob/main/LICENSE)
9
+
7
10
  ![Demo](./index.png)
8
11
 
9
12
  ## 这工具干嘛的
10
13
 
11
14
  用 Claude Code 的人可能会遇到几个烦心事:
12
15
 
13
- - 想用国产模型(GLM、KIMI、DeepSeek)但每次都要手动设置环境变量
16
+ - 想用国产模型(GLM、KIMI、DeepSeek、MiniMax)但每次都要手动设置环境变量
14
17
  - 每次执行命令都要点"允许",烦死了,但又不想用 `--dangerously-skip-permissions`
15
18
  - 想知道这个月花了多少钱,但 Claude 没有用量统计界面
19
+ - 团队想共享 API 配置,但不想把密钥明文传来传去
20
+ - 想快速安装官方和社区的 Skills,但手动 clone 太麻烦
16
21
 
17
22
  ccem 就是解决这些问题的。
18
23
 
24
+ ## 功能特性
25
+
26
+ - 🔄 **环境切换** - 一键切换 API 服务商(官方/GLM/KIMI/DeepSeek/MiniMax)
27
+ - 🔐 **权限管理** - 6 种预设权限模式,在安全和便捷之间找平衡
28
+ - 📊 **用量统计** - 日历热力图 + 按模型统计 + 费用计算
29
+ - 🛠️ **Skill 管理** - 从官方/GitHub/Plugin Marketplace 安装 Skills
30
+ - 🌐 **远程配置** - 团队共享 API 配置,加密传输
31
+ - ⚡ **性能优化** - 增量缓存、流式解析、后台更新
32
+
19
33
  ## 安装
20
34
 
21
35
  ```bash
@@ -32,7 +46,8 @@ npx ccem
32
46
  ccem # 进入交互菜单
33
47
  ccem add kimi # 添加 KIMI 环境,自动填好 URL 和模型
34
48
  ccem use kimi # 切换到 KIMI
35
- ccem dev # 用开发模式启动 Claude Code
49
+ ccem dev # 用开发模式启动 Claude Code(临时)
50
+ ccem --mode # 查看当前权限模式
36
51
  ```
37
52
 
38
53
  ![Demo](./demo.png)
@@ -50,7 +65,7 @@ ccem dev # 用开发模式启动 Claude Code
50
65
  | Start Claude Code | 启动,如果设了默认权限模式会自动带上 |
51
66
  | Switch Environment | 切换 API 环境 |
52
67
  | Permission Mode | 选个权限模式再启动 |
53
- | View Usage | 看用量和花费 |
68
+ | View Usage | 看用量和花费(带日历热力图) |
54
69
  | Set Default Mode | 设置默认权限模式 |
55
70
 
56
71
  ### 命令
@@ -70,12 +85,14 @@ ccem run <command> # 带着环境变量跑命令
70
85
 
71
86
  添加环境时可以选预设,省得自己填 URL:
72
87
 
73
- | 预设 | Base URL | 模型 |
74
- |------|----------|------|
75
- | GLM(智谱) | `https://open.bigmodel.cn/api/anthropic` | glm-4.6 |
76
- | KIMI(月之暗面) | `https://api.moonshot.cn/anthropic` | kimi-k2-thinking-turbo |
77
- | MiniMax | `https://api.minimaxi.com/anthropic` | MiniMax-M2 |
78
- | DeepSeek | `https://api.deepseek.com/anthropic` | deepseek-chat |
88
+ | 预设 | Base URL | 主模型 | 快速模型 |
89
+ |------|----------|--------|----------|
90
+ | GLM(智谱) | `https://open.bigmodel.cn/api/anthropic` | glm-4.6 | glm-4.5-air |
91
+ | KIMI(月之暗面) | `https://api.moonshot.cn/anthropic` | kimi-k2-thinking-turbo | kimi-k2-turbo-preview |
92
+ | MiniMax | `https://api.minimaxi.com/anthropic` | MiniMax-M2 | MiniMax-M2 |
93
+ | DeepSeek | `https://api.deepseek.com/anthropic` | deepseek-chat | deepseek-chat |
94
+
95
+ > 💡 **官方环境**:默认使用 `claude-sonnet-4-5-20250929` 和 `claude-haiku-4-5-20251001`
79
96
 
80
97
  ### Shell 集成
81
98
 
@@ -126,7 +143,7 @@ ccem ci # CI
126
143
  ccem audit # 审计
127
144
  ```
128
145
 
129
- 实现方式是通过 `--allowedTools` 和 `--disallowedTools` 参数传给 Claude Code。
146
+ 实现方式是通过 `--permission-mode`、`--allowedTools` 和 `--disallowedTools` 参数传给 Claude Code。
130
147
 
131
148
  ### 永久模式
132
149
 
@@ -200,9 +217,12 @@ ccem --list-modes # 列出所有模式
200
217
 
201
218
  ccem 会读 Claude Code 的日志(在 `~/.claude/projects/` 下面的 JSONL 文件),统计 token 用量和费用。
202
219
 
203
- 价格数据从 LiteLLM 的 GitHub 仓库拉取,会缓存到本地。
220
+ 价格数据从 LiteLLM 的 GitHub 仓库拉取,会缓存到本地。如果网络不可用,会依次尝试:
221
+ 1. 本地缓存(`~/.ccem/model-prices.json`)
222
+ 2. 内置价格文件(随 ccem 安装)
223
+ 3. 默认价格(Claude Opus/Sonnet/Haiku)
204
224
 
205
- 交互菜单里选 "View Usage" 可以看详细统计:
225
+ 交互菜单里选 "View Usage" 可以看详细统计,包括**日历热力图**:
206
226
 
207
227
  ```
208
228
  Token Usage Statistics
@@ -210,38 +230,76 @@ ccem 会读 Claude Code 的日志(在 `~/.claude/projects/` 下面的 JSONL
210
230
  Oct Nov Dec Jan
211
231
  Mon · ░ ▒ ▓ █ ░ · ▒ ...
212
232
  Tue ░ ▒ · █ ▓ ░ ▒ · ...
233
+ Wed ▒ ▓ █ ░ · ▒ ▓ █ ...
213
234
  ...
214
235
 
215
236
  Less · ░ ▒ ▓ █ More
216
237
 
238
+ ────────────────────────────────────────────────────────
217
239
  Period Input Output Cache Read Cost
218
240
  Today 12.5K 8.2K 45.3K $0.15
219
241
  This Week 89.2K 52.1K 312.4K $1.23
220
242
  All Time 1.2M 823.5K 4.5M $15.67
221
243
 
244
+ ────────────────────────────────────────────────────────
222
245
  By Model
223
246
  claude-sonnet-4-5 823.5K $12.34
224
247
  claude-haiku-4-5 412.3K $3.33
225
248
  ```
226
249
 
227
- 日志解析结果会缓存到 `~/.ccem/usage-cache.json`,下次打开会先显示缓存数据,后台更新。
250
+ ### 性能优化
251
+
252
+ - **增量缓存**:日志解析结果缓存到 `~/.ccem/usage-cache.json`,只解析新增/修改的文件
253
+ - **后台更新**:打开菜单时先显示缓存数据,后台异步更新
254
+ - **流式解析**:大文件使用流式读取(readline),避免内存占用过高
255
+ - **并发控制**:限制并发解析数量(5 个),避免阻塞事件循环
256
+ - **缓存版本**:缓存结构变更时自动失效重建
228
257
 
229
258
  ---
230
259
 
231
260
  ## Skill 管理
232
261
 
233
- 可以从 GitHub Claude Code 的 Skills。装完会放到当前目录的 `.claude/skills/` 下面。
262
+ 可以从 GitHub Plugin Marketplace 安装 Claude Code 的 Skills。装完会放到当前目录的 `.claude/skills/` 下面。
234
263
 
235
264
  ```bash
236
- ccem skill add # 交互选择
265
+ ccem skill add # 交互选择(Tab 切换分组)
237
266
  ccem skill add <name> # 装预设的
238
267
  ccem skill add <github-url> # 从 GitHub 装
239
268
  ccem skill ls # 列出已装的
240
269
  ccem skill rm <name> # 删掉
241
270
  ```
242
271
 
272
+ ### 交互式选择器
273
+
274
+ 运行 `ccem skill add` 会打开分组选择界面(使用 Ink 渲染):
275
+
276
+ ```
277
+ 🏢 官方 ⭐ 精选 📦 其他
278
+
279
+ ──────────────────────────────────────────────────
280
+ ❯ frontend-design - 创建高质量前端界面设计
281
+ skill-creator - 创建新的 Claude Code skills
282
+ web-artifacts-builder - 构建可交互的 Web 组件
283
+ ...
284
+ 输入自定义 GitHub URL
285
+
286
+ Tab 切换分组 | ↑↓ 选择 | Enter 确认 | Esc 取消
287
+ ```
288
+
289
+ ### 安装方式
290
+
291
+ ccem 支持三种安装方式:
292
+
293
+ | 类型 | 说明 | 示例 |
294
+ |------|------|------|
295
+ | preset | 官方预设,从 anthropics/skills 仓库安装 | `ccem skill add frontend-design` |
296
+ | github | 从任意 GitHub 仓库/子目录安装 | `ccem skill add owner/repo` |
297
+ | plugin | 从 Plugin Marketplace 安装(实验性) | 通过交互菜单选择 |
298
+
243
299
  ### 预设列表
244
300
 
301
+ #### 🏢 官方 Skills
302
+
245
303
  | Skill | 干嘛用 |
246
304
  |-------|--------|
247
305
  | frontend-design | 前端界面设计 |
@@ -261,14 +319,114 @@ ccem skill rm <name> # 删掉
261
319
  | internal-comms | 内部通信文档 |
262
320
  | slack-gif-creator | 做 Slack GIF |
263
321
 
322
+ #### ⭐ 精选 Skills
323
+
324
+ | Skill | 干嘛用 |
325
+ |-------|--------|
326
+ | superpowers | Claude Code Plan 模式升级版,连续追问讨论确定开发方案 |
327
+ | ui-ux-pro-max | 专业 UI/UX 设计 |
328
+ | Humanizer-zh | 去除文本中 AI 生成痕迹,改写得更自然 |
329
+
330
+ #### 📦 其他 Skills
331
+
332
+ | Skill | 干嘛用 |
333
+ |-------|--------|
334
+ | skill-writer | 指导用户为 Claude Code 创建代理技能 |
335
+
264
336
  ### 从 GitHub 装
265
337
 
338
+ 支持多种 URL 格式:
339
+
266
340
  ```bash
341
+ # 完整 URL
267
342
  ccem skill add https://github.com/owner/repo
268
343
  ccem skill add https://github.com/owner/repo/tree/main/path/to/skill
344
+
345
+ # 简写格式
269
346
  ccem skill add owner/repo
270
347
  ```
271
348
 
349
+ > 💡 使用 git sparse-checkout 只下载指定目录,不会 clone 整个仓库
350
+
351
+ ---
352
+
353
+ ## 远程配置加载
354
+
355
+ 团队可以部署一个配置服务器,成员用 `ccem load` 命令拉取共享的环境配置。
356
+
357
+ ### 客户端使用
358
+
359
+ ```bash
360
+ ccem load https://your-server.com/api/env?key=YOUR_KEY --secret YOUR_SECRET
361
+ ```
362
+
363
+ - `key`:服务器分配的访问密钥
364
+ - `secret`:服务器启动时生成的解密密钥
365
+
366
+ 加载成功后,环境会自动添加到本地配置。如果名称冲突,会自动重命名(如 `kimi` → `kimi-remote`)。
367
+
368
+ ### 服务端部署
369
+
370
+ 服务端代码在 `server/` 目录下。
371
+
372
+ #### 1. 配置文件
373
+
374
+ **keys.json** - 访问密钥配置:
375
+ ```json
376
+ {
377
+ "team-key-abc123": {
378
+ "environments": ["kimi", "glm"]
379
+ },
380
+ "personal-key-xyz": {
381
+ "environments": ["deepseek"]
382
+ }
383
+ }
384
+ ```
385
+
386
+ **environments.json** - 环境配置:
387
+ ```json
388
+ {
389
+ "kimi": {
390
+ "ANTHROPIC_BASE_URL": "https://api.moonshot.cn/anthropic",
391
+ "ANTHROPIC_API_KEY": "sk-xxx",
392
+ "ANTHROPIC_MODEL": "kimi-k2-thinking-turbo"
393
+ },
394
+ "glm": {
395
+ "ANTHROPIC_BASE_URL": "https://open.bigmodel.cn/api/anthropic",
396
+ "ANTHROPIC_API_KEY": "xxx.xxx",
397
+ "ANTHROPIC_MODEL": "glm-4.6"
398
+ }
399
+ }
400
+ ```
401
+
402
+ #### 2. 启动服务
403
+
404
+ ```bash
405
+ cd server
406
+ npm install
407
+ node index.js
408
+ ```
409
+
410
+ 启动后会显示 `secret`,分发给团队成员用于 `--secret` 参数。
411
+
412
+ #### 3. 安全特性
413
+
414
+ - **AES-256-CBC 加密**:API Key 在传输中加密
415
+ - **Rate Limiting**:每分钟最多 10 次请求
416
+ - **指数退避**:连续失败后冷却时间递增(最长 30 分钟)
417
+ - **Helmet**:安全响应头
418
+ - **热加载**:修改配置文件无需重启服务
419
+
420
+ #### 4. 生产部署
421
+
422
+ 推荐使用 PM2:
423
+
424
+ ```bash
425
+ pm2 start ecosystem.config.cjs
426
+ ```
427
+
428
+ 配合 nginx 反代,记得设置 `trust proxy`。
429
+
272
430
  ---
273
431
 
274
432
  ## 初始化
@@ -282,8 +440,8 @@ ccem setup init
282
440
  会做三件事:
283
441
 
284
442
  1. 设置 `hasCompletedOnboarding: true`,跳过新手引导
285
- 2. 禁用遥测(设置 `DISABLE_TELEMETRY=1` 等环境变量)
286
- 3. 装 `chrome-devtools` MCP 工具
443
+ 2. 禁用遥测(设置 `DISABLE_TELEMETRY=1`、`DISABLE_ERROR_REPORTING=1`、`DISABLE_BUG_COMMAND=1`)
444
+ 3. 装 `chrome-devtools` MCP 工具(用于浏览器调试)
287
445
 
288
446
  配置写到:
289
447
  - `~/.claude.json`
@@ -306,17 +464,18 @@ ccem setup init
306
464
  | `ccem env` | 输出环境变量 |
307
465
  | `ccem env --json` | JSON 格式 |
308
466
  | `ccem run <cmd>` | 带环境变量跑命令 |
467
+ | `ccem load <url> --secret <s>` | 从远程加载配置 |
309
468
 
310
469
  ### 权限(临时)
311
470
 
312
471
  | 命令 | 说明 |
313
472
  |------|------|
314
- | `ccem yolo` | YOLO 模式 |
315
- | `ccem dev` | 开发模式 |
316
- | `ccem readonly` | 只读模式 |
317
- | `ccem safe` | 安全模式 |
318
- | `ccem ci` | CI 模式 |
319
- | `ccem audit` | 审计模式 |
473
+ | `ccem yolo` | 🔓 YOLO 模式(全部放开) |
474
+ | `ccem dev` | 💻 开发模式 |
475
+ | `ccem readonly` | 👀 只读模式 |
476
+ | `ccem safe` | 🛡️ 安全模式 |
477
+ | `ccem ci` | 🔧 CI 模式 |
478
+ | `ccem audit` | 🔍 审计模式 |
320
479
  | `ccem --mode` | 看当前模式 |
321
480
  | `ccem --list-modes` | 列出所有模式 |
322
481
 
@@ -334,7 +493,7 @@ ccem setup init
334
493
 
335
494
  | 命令 | 说明 |
336
495
  |------|------|
337
- | `ccem skill add` | 交互添加 |
496
+ | `ccem skill add` | 交互添加(分组选择) |
338
497
  | `ccem skill add <name>` | 添加预设 |
339
498
  | `ccem skill add <url>` | 从 GitHub 添加 |
340
499
  | `ccem skill ls` | 列出已装 |
@@ -352,14 +511,26 @@ ccem setup init
352
511
 
353
512
  | 路径 | 内容 |
354
513
  |------|------|
355
- | `~/.config/claude-code-env-manager/` | 环境配置 |
356
- | `~/.ccem/usage-cache.json` | 用量缓存 |
357
- | `~/.ccem/model-prices.json` | 价格缓存 |
514
+ | `~/.config/claude-code-env-manager/` | 环境配置(加密存储 API Key) |
515
+ | `~/.ccem/usage-cache.json` | 用量缓存(增量解析结果) |
516
+ | `~/.ccem/model-prices.json` | 价格缓存(从 LiteLLM 拉取) |
358
517
  | `.claude/settings.json` | 项目权限配置 |
359
518
  | `.claude/skills/` | 已装的 skills |
360
519
 
361
520
  ---
362
521
 
522
+ ## 技术栈
523
+
524
+ - **CLI 框架**: Commander.js
525
+ - **配置存储**: Conf(加密存储敏感信息)
526
+ - **交互界面**: Inquirer.js + Ink (React for CLI)
527
+ - **表格渲染**: cli-table3
528
+ - **样式**: Chalk
529
+
530
+ ## Contributing
531
+
532
+ 欢迎提 Issue 和 PR!
533
+
363
534
  ## License
364
535
 
365
536
  MIT
package/dist/index.js CHANGED
@@ -1,21 +1,25 @@
1
1
  #!/usr/bin/env node
2
- import{Command as io}from"commander";import ao from"conf";import U from"inquirer";import d from"chalk";import kt from"cli-table3";import{spawn as Et}from"child_process";import*as he from"readline";import*as Rt from"fs";import*as fe from"path";import{fileURLToPath as co}from"url";import ae from"crypto";import X from"fs";import B from"path";var De="aes-256-cbc",He=ae.scryptSync("claude-code-env-manager-secret","salt",32),$e=e=>{if(!e)return e;let t=ae.randomBytes(16),o=ae.createCipheriv(De,He,t),n=o.update(e,"utf8","hex");return n+=o.final("hex"),`enc:${t.toString("hex")}:${n}`},j=e=>{if(!e||!e.startsWith("enc:"))return e;try{let t=e.split(":");if(t.length!==3)return e;let o=Buffer.from(t[1],"hex"),n=t[2],s=ae.createDecipheriv(De,He,o),i=s.update(n,"hex","utf8");return i+=s.final("utf8"),i}catch{return e}},Ue=()=>{let e=process.cwd(),t=B.parse(e).root;for(;e!==t;){if(X.existsSync(B.join(e,".git"))||X.existsSync(B.join(e,"package.json")))return e;e=B.dirname(e)}return process.cwd()},ce=(e=!0)=>{let t=Ue(),o=B.join(t,".claude"),n=e?"settings.local.json":"settings.json";return B.join(o,n)},Fe=()=>{let e=Ue(),t=B.join(e,".claude");return X.existsSync(t)||X.mkdirSync(t,{recursive:!0}),t},_e=()=>process.env.HOME||process.env.USERPROFILE||"",Se=()=>B.join(_e(),".claude.json"),Pe=()=>B.join(_e(),".claude","settings.json"),je=()=>{let e=B.join(_e(),".claude");return X.existsSync(e)||X.mkdirSync(e,{recursive:!0}),e};var Ae={GLM:{ANTHROPIC_BASE_URL:"https://open.bigmodel.cn/api/anthropic",ANTHROPIC_MODEL:"glm-4.6",ANTHROPIC_SMALL_FAST_MODEL:"glm-4.5-air"},KIMI:{ANTHROPIC_BASE_URL:"https://api.moonshot.cn/anthropic",ANTHROPIC_MODEL:"kimi-k2-thinking-turbo",ANTHROPIC_SMALL_FAST_MODEL:"kimi-k2-turbo-preview"},MiniMax:{ANTHROPIC_BASE_URL:"https://api.minimaxi.com/anthropic",ANTHROPIC_MODEL:"MiniMax-M2",ANTHROPIC_SMALL_FAST_MODEL:"MiniMax-M2"},DeepSeek:{ANTHROPIC_BASE_URL:"https://api.deepseek.com/anthropic",ANTHROPIC_MODEL:"deepseek-chat",ANTHROPIC_SMALL_FAST_MODEL:"deepseek-chat"}},O={yolo:{name:"YOLO \u6A21\u5F0F",description:"\u5168\u90E8\u653E\u5F00\uFF0C\u65E0\u4EFB\u4F55\u9650\u5236",permissionMode:"bypassPermissions",permissions:{allow:["Bash(*)","Read(*)","Edit(*)","Write(*)","WebFetch(*)","WebSearch(*)","Glob(*)","Grep(*)","LSP(*)","NotebookEdit(*)"],deny:[]}},dev:{name:"\u5F00\u53D1\u6A21\u5F0F",description:"\u65E5\u5E38\u5F00\u53D1\u6743\u9650\uFF0C\u4FDD\u62A4\u654F\u611F\u6587\u4EF6",permissionMode:"acceptEdits",permissions:{allow:["Read(*)","Edit(*)","Write(*)","Glob(*)","Grep(*)","LSP(*)","NotebookEdit(*)","Bash(npm:*)","Bash(pnpm:*)","Bash(yarn:*)","Bash(bun:*)","Bash(node:*)","Bash(npx:*)","Bash(git:*)","Bash(tsc:*)","Bash(tsx:*)","Bash(eslint:*)","Bash(prettier:*)","Bash(jest:*)","Bash(vitest:*)","Bash(cargo:*)","Bash(python:*)","Bash(pip:*)","Bash(go:*)","Bash(make:*)","Bash(cmake:*)","Bash(ls:*)","Bash(cat:*)","Bash(head:*)","Bash(tail:*)","Bash(find:*)","Bash(wc:*)","Bash(mkdir:*)","Bash(cp:*)","Bash(mv:*)","Bash(touch:*)","WebSearch"],deny:["Read(.env)","Read(.env.*)","Read(**/secrets/**)","Read(**/*.pem)","Read(**/*.key)","Read(**/*credential*)","Bash(rm -rf:*)","Bash(sudo:*)","Bash(chmod:*)","Bash(chown:*)"]}},readonly:{name:"\u53EA\u8BFB\u6A21\u5F0F",description:"\u4EC5\u5141\u8BB8\u8BFB\u53D6\u548C\u641C\u7D22\uFF0C\u7981\u6B62\u4EFB\u4F55\u4FEE\u6539",permissionMode:"plan",permissions:{allow:["Read(*)","Glob(*)","Grep(*)","LSP(*)","Bash(git status:*)","Bash(git log:*)","Bash(git diff:*)","Bash(git branch:*)","Bash(git show:*)","Bash(ls:*)","Bash(cat:*)","Bash(head:*)","Bash(tail:*)","Bash(find:*)","Bash(wc:*)","Bash(file:*)","WebSearch"],deny:["Edit(*)","Write(*)","NotebookEdit(*)","Bash(rm:*)","Bash(mv:*)","Bash(cp:*)","Bash(mkdir:*)","Bash(touch:*)","Bash(git add:*)","Bash(git commit:*)","Bash(git push:*)","Bash(git checkout:*)","Bash(git reset:*)","Bash(npm install:*)","Bash(pnpm install:*)","Bash(yarn add:*)"]}},safe:{name:"\u5B89\u5168\u6A21\u5F0F",description:"\u4FDD\u5B88\u6743\u9650\uFF0C\u9002\u5408\u4E0D\u719F\u6089\u7684\u4EE3\u7801\u5E93",permissionMode:"default",permissions:{allow:["Read(*)","Glob(*)","Grep(*)","LSP(*)","Bash(git status:*)","Bash(git log:*)","Bash(git diff:*)","Bash(ls:*)","Bash(cat:*)","Bash(head:*)","Bash(tail:*)","Bash(find:*)","Bash(wc:*)"],deny:["Read(.env)","Read(.env.*)","Read(**/secrets/**)","Read(**/*.pem)","Read(**/*.key)","Read(**/*credential*)","Read(**/*password*)","Edit(*)","Write(*)","NotebookEdit(*)","Bash(curl:*)","Bash(wget:*)","Bash(ssh:*)","Bash(scp:*)","Bash(rm:*)","Bash(mv:*)","WebFetch(*)"]}},ci:{name:"CI/CD \u6A21\u5F0F",description:"\u9002\u5408\u81EA\u52A8\u5316\u6D41\u6C34\u7EBF\u7684\u6743\u9650",permissionMode:"default",permissions:{allow:["Read(*)","Edit(*)","Write(*)","Glob(*)","Grep(*)","LSP(*)","Bash(npm:*)","Bash(pnpm:*)","Bash(yarn:*)","Bash(node:*)","Bash(git:*)","Bash(docker:*)","Bash(make:*)","Bash(cargo:*)","Bash(go:*)","Bash(python:*)","Bash(pip:*)","Bash(pytest:*)","Bash(jest:*)","Bash(vitest:*)"],deny:["Read(.env.local)","Read(**/secrets/**)","Bash(sudo:*)","Bash(ssh:*)","Bash(scp:*)","WebFetch(*)","WebSearch"]}},audit:{name:"\u5BA1\u8BA1\u6A21\u5F0F",description:"\u4EC5\u8BFB\u53D6\u548C\u641C\u7D22\uFF0C\u7528\u4E8E\u5B89\u5168\u5BA1\u8BA1",permissionMode:"plan",permissions:{allow:["Read(*)","Glob(*)","Grep(*)","LSP(*)","Bash(git log:*)","Bash(git blame:*)","Bash(git show:*)","Bash(git diff:*)","Bash(ls:*)","Bash(find:*)","Bash(wc:*)","Bash(file:*)","Bash(stat:*)"],deny:["Edit(*)","Write(*)","NotebookEdit(*)","Bash(rm:*)","Bash(mv:*)","Bash(cp:*)","Bash(curl:*)","Bash(wget:*)","Bash(ssh:*)","WebFetch(*)"]}}},Ce=()=>Object.keys(O);import N from"chalk";import Je from"cli-table3";import*as Y from"fs";import*as I from"fs/promises";import*as G from"path";import*as ke from"os";import*as Ge from"readline";var Te=G.join(ke.homedir(),".claude","projects"),le=G.join(ke.homedir(),".ccem"),Ee=1,Re=()=>G.join(le,"usage-cache.json"),xt=()=>G.join(le,"model-prices.json");async function Ke(){try{await I.access(le)}catch{await I.mkdir(le,{recursive:!0})}}var Lt="https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",bt=()=>G.join(__dirname,"..","model-prices.json"),Z={"claude-opus-4-5":{input_cost_per_token:5e-6,output_cost_per_token:25e-6,cache_read_input_token_cost:5e-7,cache_creation_input_token_cost:625e-8},"claude-sonnet-4-5":{input_cost_per_token:3e-6,output_cost_per_token:15e-6,cache_read_input_token_cost:3e-7,cache_creation_input_token_cost:375e-8},"claude-haiku-4-5":{input_cost_per_token:1e-6,output_cost_per_token:5e-6,cache_read_input_token_cost:1e-7,cache_creation_input_token_cost:125e-8}};function de(e){return e.replace(/-20\d{6}.*$/,"").replace(/-v\d+:\d+$/,"").replace(/^anthropic\./,"").replace(/^vertex_ai\//,"").replace(/@.*$/,"")}var Q=null;async function Nt(){if(Q)return Q;await Ke();let e=xt();try{let t=await fetch(Lt,{signal:AbortSignal.timeout(1e3)});if(t.ok){let o=await t.json(),n={};for(let[s,i]of Object.entries(o))i.input_cost_per_token&&i.output_cost_per_token&&(n[s]={input_cost_per_token:i.input_cost_per_token,output_cost_per_token:i.output_cost_per_token,cache_read_input_token_cost:i.cache_read_input_token_cost,cache_creation_input_token_cost:i.cache_creation_input_token_cost});return await I.writeFile(e,JSON.stringify(n,null,2)),Q=n,n}}catch{}try{let t=await I.readFile(e,"utf-8"),o=JSON.parse(t);return Q=o,o}catch{}try{let t=bt(),o=await I.readFile(t,"utf-8"),n=JSON.parse(o);return Q=n,n}catch{}return Q=Z,Z}function Bt(e,t){if(t[e])return t[e];let o=de(e);if(t[o])return t[o];for(let[n,s]of Object.entries(t))if(n.includes(o)||o.includes(de(n)))return s;return e.includes("opus")?Z["claude-opus-4-5"]:e.includes("sonnet")?Z["claude-sonnet-4-5"]:e.includes("haiku")?Z["claude-haiku-4-5"]:Z["claude-sonnet-4-5"]}function vt(e,t){return e.inputTokens*t.input_cost_per_token+e.outputTokens*t.output_cost_per_token+e.cacheReadTokens*(t.cache_read_input_token_cost||0)+e.cacheCreationTokens*(t.cache_creation_input_token_cost||0)}function v(){return{inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,cost:0}}function D(e,t){return{inputTokens:e.inputTokens+t.inputTokens,outputTokens:e.outputTokens+t.outputTokens,cacheReadTokens:e.cacheReadTokens+t.cacheReadTokens,cacheCreationTokens:e.cacheCreationTokens+t.cacheCreationTokens,cost:e.cost+t.cost}}async function Dt(e){try{let t=await I.stat(e);return{mtime:t.mtimeMs,size:t.size}}catch{return null}}function Ht(){try{let e=Re();if(!Y.existsSync(e))return null;let t=JSON.parse(Y.readFileSync(e,"utf-8"));return t.version!==Ee?null:t}catch{return null}}async function $t(){try{let e=Re(),t=await I.readFile(e,"utf-8"),o=JSON.parse(t);return o.version!==Ee?null:o}catch{return null}}function We(){let e=Ht();if(!e)return null;let t=new Date,o=new Date(t.getFullYear(),t.getMonth(),t.getDate()),n=new Date(o);n.setDate(n.getDate()-n.getDay());let s={today:v(),week:v(),total:v(),dailyHistory:{},byModel:{},lastUpdated:t.toISOString()};for(let i of Object.values(e.files))for(let a of i.stats.entries){let c=new Date(a.timestamp),l=a.timestamp.split("T")[0];s.total=D(s.total,a.usage),s.dailyHistory[l]||(s.dailyHistory[l]=v()),s.dailyHistory[l]=D(s.dailyHistory[l],a.usage);let m=de(a.model);s.byModel[m]||(s.byModel[m]=v()),s.byModel[m]=D(s.byModel[m],a.usage),c>=o&&(s.today=D(s.today,a.usage)),c>=n&&(s.week=D(s.week,a.usage))}return s}async function Ut(e){try{await Ke(),await I.writeFile(Re(),JSON.stringify(e,null,2))}catch{}}async function Ft(e,t,o){let n=[];try{let s=Y.createReadStream(e,{encoding:"utf-8"}),i=Ge.createInterface({input:s,crlfDelay:1/0}),a=0;for await(let c of i){if(a++,a%100===0){if(o?.aborted)throw i.close(),s.destroy(),new Error("Aborted");a%1e3===0&&await new Promise(l=>setTimeout(l,0))}if(c.trim())try{let l=JSON.parse(c);if(l.type!=="assistant"||!l.message?.usage)continue;let m=l.message.model||"unknown",f=l.message.usage,y={inputTokens:f.input_tokens||0,outputTokens:f.output_tokens||0,cacheReadTokens:f.cache_read_input_tokens||0,cacheCreationTokens:f.cache_creation_input_tokens||0},p=Bt(m,t),_=vt(y,p);n.push({timestamp:l.timestamp||new Date().toISOString(),model:m,usage:{...y,cost:_}})}catch{}}}catch(s){if(s.message==="Aborted")throw s}return{entries:n}}async function jt(){let e=[];try{if(!await I.access(Te).then(()=>!0).catch(()=>!1))return e;let o=await I.readdir(Te);for(let n of o){let s=G.join(Te,n);try{if((await I.stat(s)).isDirectory()){let a=await I.readdir(s);for(let c of a)c.endsWith(".jsonl")&&e.push(G.join(s,c))}}catch{}}}catch{}return e}async function Ye(e){if(e?.aborted)throw new Error("Aborted");let t=await Nt();if(e?.aborted)throw new Error("Aborted");let o=await jt();if(e?.aborted)throw new Error("Aborted");let n=await $t(),s={version:Ee,files:{},lastUpdated:new Date().toISOString()},i=[],a=5,c=[];for(let p=0;p<o.length;p+=a)c.push(o.slice(p,p+a));for(let p of c){if(e?.aborted)throw new Error("Aborted");let _=p.map(async g=>{let S=await Dt(g);if(!S)return null;let R=n?.files[g],k=R&&R.meta.mtime===S.mtime&&R.meta.size===S.size,E;return k?E=R.stats:(E=await Ft(g,t,e),await new Promise(C=>setTimeout(C,0))),{file:g,meta:S,stats:E}}),u=await Promise.all(_);for(let g of u)g&&(s.files[g.file]={meta:g.meta,stats:g.stats},i.push(...g.stats.entries))}e?.aborted||Ut(s).catch(()=>{});let l=new Date,m=new Date(l.getFullYear(),l.getMonth(),l.getDate()),f=new Date(m);f.setDate(f.getDate()-f.getDay());let y={today:v(),week:v(),total:v(),dailyHistory:{},byModel:{},lastUpdated:l.toISOString()};for(let p of i){let _=new Date(p.timestamp),u=p.timestamp.split("T")[0];y.total=D(y.total,p.usage),y.dailyHistory[u]||(y.dailyHistory[u]=v()),y.dailyHistory[u]=D(y.dailyHistory[u],p.usage);let g=de(p.model);y.byModel[g]||(y.byModel[g]=v()),y.byModel[g]=D(y.byModel[g],p.usage),_>=m&&(y.today=D(y.today,p.usage)),_>=f&&(y.week=D(y.week,p.usage))}return y}function b(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"K":e.toString()}function ee(e){return e>=1||e>=.01?"$"+e.toFixed(2):"$"+e.toFixed(4)}function J(e){return e.inputTokens+e.outputTokens+e.cacheReadTokens+e.cacheCreationTokens}var r={primary:N.hex("#89B4FA"),accent:N.hex("#CBA6F7"),success:N.hex("#A6E3A1"),warning:N.hex("#F9E2AF"),danger:N.hex("#F38BA8"),text:N.white,muted:N.hex("#6C7086"),dim:N.hex("#45475A")},ze=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],we=0,se=null,Gt=()=>r.primary(ze[we]),Ve=e=>{se||(se=setInterval(()=>{we=(we+1)%ze.length,e()},80))},pe=()=>{se&&(clearInterval(se),se=null)};var qe=()=>process.stdout.columns||80,Xe=(e,t,o)=>{let n=N.hex("#89B4FA"),s=N.hex("#45475A"),i=N.hex("#6C7086"),a=qe(),c=a<60,l=a<45,m=r.primary("CCEM")+" "+r.muted("Claude Code Env Manager"),f=r.primary("CCEM"),y=r.muted("Env: ")+r.primary(e),p=t.ANTHROPIC_BASE_URL||"-",_=t.ANTHROPIC_MODEL||"-",u=t.ANTHROPIC_SMALL_FAST_MODEL||"-",g=t.ANTHROPIC_API_KEY?t.ANTHROPIC_API_KEY.slice(0,2)+"\u2022\u2022\u2022\u2022"+t.ANTHROPIC_API_KEY.slice(-4):"-",S=(w,F)=>w.length>F?w.slice(0,F-3)+"...":w,R=(w,F)=>{if(w.length<=F)return w;try{let $=new URL(w),wt=$.protocol+"//",ve=$.host,ye=$.pathname+$.search,Ot=ve.slice(0,8),Mt=ve.slice(-4),It=ye.length>10?ye.slice(0,7)+"...":ye;return`${wt}${Ot}...${Mt}${It}`}catch{return S(w,F)}},k=7,E;c?E=[y,r.muted("Model:".padEnd(k))+r.dim(S(_,25)),r.muted("Key:".padEnd(k))+r.dim(g)]:E=[y+(o&&O[o]?" "+r.accent(`[${O[o].name}]`):""),r.muted("URL:".padEnd(k))+r.dim(R(p,40)),r.muted("Model:".padEnd(k))+r.dim(S(_,15))+" "+r.muted("Fast:".padEnd(k))+r.dim(S(u,15)),r.muted("Key:".padEnd(k))+r.dim(g)];let C=[];if(l)C.push(` ${i("*")} ${s("\u2584\u2588\u2584")} ${i("*")}`),C.push(` ${i("*")} ${n("\u2590\u259B\u2588\u2588\u2588\u2588\u2588\u259C\u258C")} ${i("*")}`),C.push(` ${i("*")} ${n("\u259D\u259C\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u259B\u2598")} ${i("*")}`),C.push(` ${i("*")} ${n("\u2598\u2598 \u259D\u259D")} ${i("*")}`),C.push(""),C.push(f),C.push(""),E.forEach(w=>C.push(w));else{let w=c?" ":" ";C.push(""),C.push(` ${s("\u2584\u2588\u2588\u2584")} ${w}${c?f:m}`),C.push(` ${i("*")} ${n("\u2590\u259B\u2588\u2588\u2588\u2588\u2588\u259C\u258C")} ${i("*")} ${w}${E[0]||""}`),C.push(` ${i("*")} ${n("\u259D\u259C\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u259B\u2598")} ${i("*")} ${w}${E[1]||""}`),C.push(` ${i("*")} ${n("\u2598\u2598 \u259D\u259D")} ${i("*")} ${w}${E[2]||""}`),E[3]&&C.push(` ${w}${E[3]}`)}return C.join(`
3
- `)},Qe=(e,t)=>{if(t)return r.muted(" Usage: ")+Gt()+r.dim(" Loading...");if(!e)return r.muted(" Usage: ")+r.dim("No data");let n=qe()<70,s=J(e.today),i=J(e.week),a=J(e.total);return n?r.muted(" Usage: ")+r.text("Today ")+r.primary(b(s))+r.dim(" | ")+r.text("Week ")+r.primary(b(i))+r.dim(" | ")+r.text("Total ")+r.primary(b(a)):r.muted(" Usage: ")+r.text("Today ")+r.primary(b(s).padStart(6))+r.dim(` (${ee(e.today.cost)})`)+r.dim(" | ")+r.text("Week ")+r.primary(b(i).padStart(6))+r.dim(` (${ee(e.week.cost)})`)+r.dim(" | ")+r.text("Total ")+r.primary(b(a).padStart(6))+r.dim(` (${ee(e.total.cost)})`)},Ze=()=>{let e=process.stdout.columns||80;return r.dim("\u2500".repeat(e))};var Oe=e=>{let t="Start Claude Code";return e&&O[e]&&(t=`Start Claude Code ${r.muted(`(${O[e].name})`)}`),[{name:r.success(t),value:"start",short:"Start"},{name:r.primary("Switch Environment"),value:"switch",short:"Switch"},{name:r.primary("Permission Mode"),value:"perm",short:"Permission"},{name:r.accent("View Usage"),value:"usage",short:"Usage"},{name:r.text("Set Default Mode"),value:"setDefault",short:"Default"},{name:r.muted("Exit"),value:"exit",short:"Exit"}]},Kt={yolo:r.danger,dev:r.success,readonly:r.primary,safe:r.warning,ci:r.accent,audit:r.primary},Me=(e,t=!1)=>{let n=["yolo","dev","readonly","safe","ci","audit"].map(s=>{let i=O[s],a=Kt[s],l=t&&s===e?r.success(" *"):"";return{name:a(i.name.padEnd(12))+r.muted(i.description)+l,value:s,short:i.name}});return t&&n.push({name:r.muted("Clear default"),value:"clear",short:"Clear"}),n.push({name:r.muted("Back"),value:"back",short:"Back"}),n},et=(e,t)=>Object.keys(e).map(o=>{let n=o===t,s=n?r.success(" *"):"";return{name:(n?r.primary(o):r.text(o))+s,value:o,short:o}}),ne={success:e=>console.log(r.success("\u2713 ")+r.text(e)),error:e=>console.log(r.danger("\u2717 ")+r.text(e)),warning:e=>console.log(r.warning("! ")+r.text(e)),info:e=>console.log(r.primary("\u203A ")+r.text(e))},tt=()=>r.muted("Starting Claude Code...");var Wt=(e,t=6)=>{let o=[],n=new Date,s=new Date(n);s.setMonth(s.getMonth()-t);let i=s.getDay(),a=s.getDate()-i+(i===0?-6:1);s.setDate(a),s.setHours(0,0,0,0);let c=[],l=new Date(s);for(;(l<=n||l.getDay()!==1)&&(c.push(l.toISOString().split("T")[0]),l.setDate(l.getDate()+1),!(l>n&&l.getDay()===1)););let m=0;for(let S of c){let R=e.dailyHistory[S];if(R){let k=J(R);k>m&&(m=k)}}let f=" ",y=-1,p=Math.ceil(c.length/7);for(let S=0;S<p;S++){let R=S*7;if(R<c.length){let k=new Date(c[R]),E=k.getMonth();if(E!==y&&S<p-1){let C=k.toLocaleString("default",{month:"short"});f+=r.muted(C),y=E}}}f=" ";let _=-1;for(let S=0;S<p;S++){let R=S*7;if(R>=c.length)break;let k=new Date(c[R]),E=k.getMonth();if(E!==_){let C=k.toLocaleString("default",{month:"short"});f+=r.muted(C.padEnd(4)),S++,_=E}else f+=" "}o.push(f);let u=["Mon","","Wed","","Fri","","Sun"],g=[" ","\u2591","\u2592","\u2593","\u2588"];for(let S=0;S<7;S++){let R=r.muted((u[S]||"").padEnd(4)+" ");for(let k=0;k<p;k++){let E=k*7+S;if(E<c.length){let C=c[E];if(new Date(C)>n)R+=" ";else{let w=e.dailyHistory[C],F=w?J(w):0,$=0;F>0&&(m===0?$=0:$=Math.ceil(F/m*4)),R+=($===0?r.dim("\xB7"):r.primary(g[$]))+" "}}}o.push(R)}return o.push(""),o.push(" "+r.dim("Less ")+r.dim("\xB7")+" "+r.primary(g[1])+" "+r.primary(g[2])+" "+r.primary(g[3])+" "+r.primary(g[4])+" "+r.dim(" More")),o.join(`
4
- `)},ot=e=>{let t=[];t.push(""),t.push(r.primary(" Token Usage Statistics")),t.push(r.dim("\u2500".repeat(60))),t.push(""),t.push(Wt(e)),t.push(""),t.push(r.dim("\u2500".repeat(60)));let o=new Je({head:[r.muted("Period"),r.muted("Input"),r.muted("Output"),r.muted("Cache Read"),r.muted("Cost")],style:{head:[],border:[]},chars:{top:"","top-mid":"","top-left":"","top-right":"",bottom:"","bottom-mid":"","bottom-left":"","bottom-right":"",left:" ","left-mid":"",mid:"","mid-mid":"",right:"","right-mid":"",middle:" "}}),n=(i,a)=>[r.text(i),r.primary(b(a.inputTokens)),r.primary(b(a.outputTokens)),r.primary(b(a.cacheReadTokens)),r.success(ee(a.cost))];o.push(n("Today",e.today)),o.push(n("This Week",e.week)),o.push(n("All Time",e.total)),t.push(o.toString());let s=Object.entries(e.byModel).sort((i,a)=>a[1].cost-i[1].cost);if(s.length>0){t.push(""),t.push(r.dim("\u2500".repeat(60))),t.push(r.muted(" By Model")),t.push("");let i=new Je({head:[r.muted("Model"),r.muted("Tokens"),r.muted("Cost")],style:{head:[],border:[]},chars:{top:"","top-mid":"","top-left":"","top-right":"",bottom:"","bottom-mid":"","bottom-left":"","bottom-right":"",left:" ","left-mid":"",mid:"","mid-mid":"",right:"","right-mid":"",middle:" "}});for(let[a,c]of s){let l=J(c);i.push([r.text(a),r.primary(b(l)),r.success(ee(c.cost))])}t.push(i.toString())}return t.push(""),t.push(r.dim("\u2500".repeat(60))),t.push(r.muted(` Last updated: ${new Date(e.lastUpdated).toLocaleString()}`)),t.join(`
5
- `)};import z from"fs";import A from"chalk";import st from"cli-table3";import{spawn as Yt}from"child_process";var Ie=e=>{if(z.existsSync(e))try{let t=z.readFileSync(e,"utf-8");return JSON.parse(t)}catch{console.warn(A.yellow(`\u8B66\u544A: \u65E0\u6CD5\u89E3\u6790 ${e}\uFF0C\u5C06\u521B\u5EFA\u5907\u4EFD`));let t=e+".error."+Date.now();return z.copyFileSync(e,t),console.log(A.gray(`\u5907\u4EFD\u5DF2\u4FDD\u5B58\u5230: ${t}`)),{}}return{}},nt=(e,t)=>{Fe(),z.writeFileSync(e,JSON.stringify(t,null,2)+`
6
- `)},Jt=(e,t)=>{let o=e.permissions?.allow||[],n=e.permissions?.deny||[],s=[...new Set([...t.allow,...o])],i=[...new Set([...t.deny,...n])];return{...e,permissions:{allow:s,deny:i}}},rt=e=>{let t=O[e];t||(console.error(A.red(`\u672A\u77E5\u7684\u6743\u9650\u6A21\u5F0F: ${e}`)),console.log(A.yellow("\u53EF\u7528\u6A21\u5F0F: "+Ce().join(", "))),process.exit(1));let o=ce(!0),n=Ie(o),s=Jt(n,t.permissions);nt(o,s),console.log(A.green(`\u5DF2\u5E94\u7528 ${t.name}`)),console.log(A.gray(`\u914D\u7F6E\u5DF2\u5199\u5165: ${o}`)),console.log(A.gray(`\u8BF4\u660E: ${t.description}`))},it=()=>{let e=ce(!0);if(!z.existsSync(e)){console.log(A.yellow("\u6CA1\u6709\u81EA\u5B9A\u4E49\u6743\u9650\u914D\u7F6E\u9700\u8981\u91CD\u7F6E"));return}let t=Ie(e);delete t.permissions,Object.keys(t).length===0?(z.unlinkSync(e),console.log(A.green("\u5DF2\u5220\u9664\u914D\u7F6E\u6587\u4EF6\uFF08\u6587\u4EF6\u4E3A\u7A7A\uFF09"))):(nt(e,t),console.log(A.green("\u6743\u9650\u914D\u7F6E\u5DF2\u91CD\u7F6E"))),console.log(A.gray(`\u6587\u4EF6: ${e}`))},at=()=>{let e=ce(!0);if(!z.existsSync(e)){console.log(A.yellow("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49\u6743\u9650")),console.log(A.gray(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${e}`));return}let t=Ie(e);if(!t.permissions){console.log(A.yellow("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49\u6743\u9650"));return}let o=Object.entries(O).find(([a,c])=>{let l=new Set(t.permissions?.allow||[]),m=new Set(t.permissions?.deny||[]),f=new Set(c.permissions.allow),y=new Set(c.permissions.deny),p=c.permissions.allow.every(u=>l.has(u)),_=c.permissions.deny.every(u=>m.has(u));return p&&_});console.log(o?A.green(`\u5F53\u524D\u6A21\u5F0F: ${o[0]} (${o[1].name})`):A.yellow("\u5F53\u524D\u6A21\u5F0F: \u81EA\u5B9A\u4E49")),console.log(A.gray(`\u914D\u7F6E\u6587\u4EF6: ${e}`));let n=new st({head:["\u7C7B\u578B","\u89C4\u5219"],style:{head:["cyan"]},colWidths:[10,70]}),s=t.permissions.allow||[],i=t.permissions.deny||[];n.push(["Allow",s.length>0?s.join(`
7
- `):"(\u65E0)"]),n.push(["Deny",i.length>0?i.join(`
8
- `):"(\u65E0)"]),console.log(n.toString())},ct=()=>{let e=new st({head:["\u6A21\u5F0F","\u6807\u5FD7","\u8BF4\u660E"],style:{head:["cyan"]},colWidths:[15,15,50]});Object.entries(O).forEach(([t,o])=>{e.push([o.name,`--${t}`,o.description])}),console.log(A.bold(`\u53EF\u7528\u6743\u9650\u6A21\u5F0F:
9
- `)),console.log(e.toString()),console.log(A.gray(`
10
- \u4E34\u65F6\u6A21\u5F0F: ccem <mode>`)),console.log(A.gray("\u6C38\u4E45\u6A21\u5F0F: ccem setup perms --<mode>"))},ue=async(e,t)=>{let o=O[e];o||(console.error(A.red(`\u672A\u77E5\u7684\u6743\u9650\u6A21\u5F0F: ${e}`)),console.log(A.yellow("\u53EF\u7528\u6A21\u5F0F: "+Ce().join(", "))),process.exit(1));let n=[];if(n.push("--permission-mode",o.permissionMode),o.permissions.allow.length>0){let i=o.permissions.allow.map(a=>`"${a}"`).join(" ");n.push("--allowedTools",i)}if(o.permissions.deny.length>0){let i=o.permissions.deny.map(a=>`"${a}"`).join(" ");n.push("--disallowedTools",i)}console.log(A.green(`\u5DF2\u5E94\u7528 ${o.name}\uFF08\u4E34\u65F6\uFF09`)),console.log(A.gray(`\u8BF4\u660E: ${o.description}`)),console.log("");let s={...process.env};return t&&(t.ANTHROPIC_BASE_URL&&(s.ANTHROPIC_BASE_URL=t.ANTHROPIC_BASE_URL),t.ANTHROPIC_API_KEY&&(s.ANTHROPIC_API_KEY=j(t.ANTHROPIC_API_KEY)),t.ANTHROPIC_MODEL&&(s.ANTHROPIC_MODEL=t.ANTHROPIC_MODEL),t.ANTHROPIC_SMALL_FAST_MODEL&&(s.ANTHROPIC_SMALL_FAST_MODEL=t.ANTHROPIC_SMALL_FAST_MODEL)),new Promise(i=>{let a=Yt("claude",n,{stdio:"inherit",shell:!0,env:s});a.on("exit",c=>{process.exit(c??0)}),a.on("error",c=>{console.error(A.red(`\u542F\u52A8 Claude Code \u5931\u8D25: ${c.message}`)),process.exit(1)})})};import xe from"fs";import P from"chalk";import{spawn as zt}from"child_process";var lt=e=>{if(xe.existsSync(e))try{let t=xe.readFileSync(e,"utf-8");return JSON.parse(t)}catch{return console.warn(P.yellow(`\u8B66\u544A: \u65E0\u6CD5\u89E3\u6790 ${e}`)),{}}return{}},dt=(e,t)=>{xe.writeFileSync(e,JSON.stringify(t,null,2)+`
11
- `)},Vt=()=>{let e=Se();try{let t=lt(e);return t.hasCompletedOnboarding===!0?(console.log(P.gray(" \u2713 hasCompletedOnboarding \u5DF2\u8BBE\u7F6E")),!0):(t.hasCompletedOnboarding=!0,dt(e,t),console.log(P.green(" \u2713 \u5DF2\u8BBE\u7F6E hasCompletedOnboarding: true")),!0)}catch(t){return console.error(P.red(` \u2717 \u8BBE\u7F6E hasCompletedOnboarding \u5931\u8D25: ${t}`)),!1}},qt=()=>{let e=Pe();try{je();let t=lt(e);(!t.env||typeof t.env!="object")&&(t.env={});let o=t.env,n={DISABLE_BUG_COMMAND:"1",DISABLE_ERROR_REPORTING:"1",DISABLE_TELEMETRY:"1"},s=!1;for(let[i,a]of Object.entries(n))o[i]!==a&&(o[i]=a,s=!0);return s?(dt(e,t),console.log(P.green(" \u2713 \u5DF2\u914D\u7F6E\u73AF\u5883\u53D8\u91CF:")),console.log(P.gray(" DISABLE_BUG_COMMAND=1")),console.log(P.gray(" DISABLE_ERROR_REPORTING=1")),console.log(P.gray(" DISABLE_TELEMETRY=1")),!0):(console.log(P.gray(" \u2713 \u73AF\u5883\u53D8\u91CF\u5DF2\u914D\u7F6E")),!0)}catch(t){return console.error(P.red(` \u2717 \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF\u5931\u8D25: ${t}`)),!1}},Xt=()=>new Promise(e=>{console.log(P.cyan(" \u2192 \u6B63\u5728\u6DFB\u52A0 chrome-devtools MCP \u5DE5\u5177..."));let t=zt("claude",["mcp","add","chrome-devtools","npx","chrome-devtools-mcp@latest","--scope","user"],{stdio:"pipe",shell:!0}),o="",n="";t.stdout?.on("data",s=>{o+=s.toString()}),t.stderr?.on("data",s=>{n+=s.toString()}),t.on("exit",s=>{s===0?(console.log(P.green(" \u2713 \u5DF2\u6DFB\u52A0 chrome-devtools MCP \u5DE5\u5177")),e(!0)):n.includes("already exists")||o.includes("already exists")?(console.log(P.gray(" \u2713 chrome-devtools MCP \u5DE5\u5177\u5DF2\u5B58\u5728")),e(!0)):(console.error(P.red(` \u2717 \u6DFB\u52A0 MCP \u5DE5\u5177\u5931\u8D25 (code: ${s})`)),n&&console.error(P.gray(` ${n.trim()}`)),e(!1))}),t.on("error",s=>{console.error(P.red(` \u2717 \u6267\u884C claude \u547D\u4EE4\u5931\u8D25: ${s.message}`)),console.log(P.yellow(" \u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5 Claude Code CLI")),e(!1)})}),pt=async()=>{console.log(P.bold(`
2
+ import{Command as uo}from"commander";import go from"conf";import k from"inquirer";import u from"chalk";import Ot from"cli-table3";import{spawn as It}from"child_process";import*as wt from"fs";import*as ye from"path";import{fileURLToPath as fo}from"url";import le from"crypto";import ee from"fs";import B from"path";var be="aes-256-cbc",De=le.scryptSync("claude-code-env-manager-secret","salt",32),J=e=>{if(!e)return e;let t=le.randomBytes(16),o=le.createCipheriv(be,De,t),s=o.update(e,"utf8","hex");return s+=o.final("hex"),`enc:${t.toString("hex")}:${s}`},Y=e=>{if(!e||!e.startsWith("enc:"))return e;try{let t=e.split(":");if(t.length!==3)return e;let o=Buffer.from(t[1],"hex"),s=t[2],n=le.createDecipheriv(be,De,o),i=n.update(s,"hex","utf8");return i+=n.final("utf8"),i}catch{return e}},Be=()=>{let e=process.cwd(),t=B.parse(e).root;for(;e!==t;){if(ee.existsSync(B.join(e,".git"))||ee.existsSync(B.join(e,"package.json")))return e;e=B.dirname(e)}return process.cwd()},de=(e=!0)=>{let t=Be(),o=B.join(t,".claude"),s=e?"settings.local.json":"settings.json";return B.join(o,s)},$e=()=>{let e=Be(),t=B.join(e,".claude");return ee.existsSync(t)||ee.mkdirSync(t,{recursive:!0}),t},Ae=()=>process.env.HOME||process.env.USERPROFILE||"",Pe=()=>B.join(Ae(),".claude.json"),Se=()=>B.join(Ae(),".claude","settings.json"),Ue=()=>{let e=B.join(Ae(),".claude");return ee.existsSync(e)||ee.mkdirSync(e,{recursive:!0}),e};var Re={GLM:{ANTHROPIC_BASE_URL:"https://open.bigmodel.cn/api/anthropic",ANTHROPIC_MODEL:"glm-4.6",ANTHROPIC_SMALL_FAST_MODEL:"glm-4.5-air"},KIMI:{ANTHROPIC_BASE_URL:"https://api.moonshot.cn/anthropic",ANTHROPIC_MODEL:"kimi-k2-thinking-turbo",ANTHROPIC_SMALL_FAST_MODEL:"kimi-k2-turbo-preview"},MiniMax:{ANTHROPIC_BASE_URL:"https://api.minimaxi.com/anthropic",ANTHROPIC_MODEL:"MiniMax-M2",ANTHROPIC_SMALL_FAST_MODEL:"MiniMax-M2"},DeepSeek:{ANTHROPIC_BASE_URL:"https://api.deepseek.com/anthropic",ANTHROPIC_MODEL:"deepseek-chat",ANTHROPIC_SMALL_FAST_MODEL:"deepseek-chat"}},w={yolo:{name:"YOLO \u6A21\u5F0F",description:"\u5168\u90E8\u653E\u5F00\uFF0C\u65E0\u4EFB\u4F55\u9650\u5236",permissionMode:"bypassPermissions",permissions:{allow:["Bash(*)","Read(*)","Edit(*)","Write(*)","WebFetch(*)","WebSearch(*)","Glob(*)","Grep(*)","LSP(*)","NotebookEdit(*)"],deny:[]}},dev:{name:"\u5F00\u53D1\u6A21\u5F0F",description:"\u65E5\u5E38\u5F00\u53D1\u6743\u9650\uFF0C\u4FDD\u62A4\u654F\u611F\u6587\u4EF6",permissionMode:"acceptEdits",permissions:{allow:["Read(*)","Edit(*)","Write(*)","Glob(*)","Grep(*)","LSP(*)","NotebookEdit(*)","Bash(npm:*)","Bash(pnpm:*)","Bash(yarn:*)","Bash(bun:*)","Bash(node:*)","Bash(npx:*)","Bash(git:*)","Bash(tsc:*)","Bash(tsx:*)","Bash(eslint:*)","Bash(prettier:*)","Bash(jest:*)","Bash(vitest:*)","Bash(cargo:*)","Bash(python:*)","Bash(pip:*)","Bash(go:*)","Bash(make:*)","Bash(cmake:*)","Bash(ls:*)","Bash(cat:*)","Bash(head:*)","Bash(tail:*)","Bash(find:*)","Bash(wc:*)","Bash(mkdir:*)","Bash(cp:*)","Bash(mv:*)","Bash(touch:*)","WebSearch"],deny:["Read(.env)","Read(.env.*)","Read(**/secrets/**)","Read(**/*.pem)","Read(**/*.key)","Read(**/*credential*)","Bash(rm -rf:*)","Bash(sudo:*)","Bash(chmod:*)","Bash(chown:*)"]}},readonly:{name:"\u53EA\u8BFB\u6A21\u5F0F",description:"\u4EC5\u5141\u8BB8\u8BFB\u53D6\u548C\u641C\u7D22\uFF0C\u7981\u6B62\u4EFB\u4F55\u4FEE\u6539",permissionMode:"plan",permissions:{allow:["Read(*)","Glob(*)","Grep(*)","LSP(*)","Bash(git status:*)","Bash(git log:*)","Bash(git diff:*)","Bash(git branch:*)","Bash(git show:*)","Bash(ls:*)","Bash(cat:*)","Bash(head:*)","Bash(tail:*)","Bash(find:*)","Bash(wc:*)","Bash(file:*)","WebSearch"],deny:["Edit(*)","Write(*)","NotebookEdit(*)","Bash(rm:*)","Bash(mv:*)","Bash(cp:*)","Bash(mkdir:*)","Bash(touch:*)","Bash(git add:*)","Bash(git commit:*)","Bash(git push:*)","Bash(git checkout:*)","Bash(git reset:*)","Bash(npm install:*)","Bash(pnpm install:*)","Bash(yarn add:*)"]}},safe:{name:"\u5B89\u5168\u6A21\u5F0F",description:"\u4FDD\u5B88\u6743\u9650\uFF0C\u9002\u5408\u4E0D\u719F\u6089\u7684\u4EE3\u7801\u5E93",permissionMode:"default",permissions:{allow:["Read(*)","Glob(*)","Grep(*)","LSP(*)","Bash(git status:*)","Bash(git log:*)","Bash(git diff:*)","Bash(ls:*)","Bash(cat:*)","Bash(head:*)","Bash(tail:*)","Bash(find:*)","Bash(wc:*)"],deny:["Read(.env)","Read(.env.*)","Read(**/secrets/**)","Read(**/*.pem)","Read(**/*.key)","Read(**/*credential*)","Read(**/*password*)","Edit(*)","Write(*)","NotebookEdit(*)","Bash(curl:*)","Bash(wget:*)","Bash(ssh:*)","Bash(scp:*)","Bash(rm:*)","Bash(mv:*)","WebFetch(*)"]}},ci:{name:"CI/CD \u6A21\u5F0F",description:"\u9002\u5408\u81EA\u52A8\u5316\u6D41\u6C34\u7EBF\u7684\u6743\u9650",permissionMode:"default",permissions:{allow:["Read(*)","Edit(*)","Write(*)","Glob(*)","Grep(*)","LSP(*)","Bash(npm:*)","Bash(pnpm:*)","Bash(yarn:*)","Bash(node:*)","Bash(git:*)","Bash(docker:*)","Bash(make:*)","Bash(cargo:*)","Bash(go:*)","Bash(python:*)","Bash(pip:*)","Bash(pytest:*)","Bash(jest:*)","Bash(vitest:*)"],deny:["Read(.env.local)","Read(**/secrets/**)","Bash(sudo:*)","Bash(ssh:*)","Bash(scp:*)","WebFetch(*)","WebSearch"]}},audit:{name:"\u5BA1\u8BA1\u6A21\u5F0F",description:"\u4EC5\u8BFB\u53D6\u548C\u641C\u7D22\uFF0C\u7528\u4E8E\u5B89\u5168\u5BA1\u8BA1",permissionMode:"plan",permissions:{allow:["Read(*)","Glob(*)","Grep(*)","LSP(*)","Bash(git log:*)","Bash(git blame:*)","Bash(git show:*)","Bash(git diff:*)","Bash(ls:*)","Bash(find:*)","Bash(wc:*)","Bash(file:*)","Bash(stat:*)"],deny:["Edit(*)","Write(*)","NotebookEdit(*)","Bash(rm:*)","Bash(mv:*)","Bash(cp:*)","Bash(curl:*)","Bash(wget:*)","Bash(ssh:*)","WebFetch(*)"]}}},Ee=()=>Object.keys(w);import D from"chalk";import Ge from"cli-table3";import*as z from"fs";import*as M from"fs/promises";import*as G from"path";import*as Ce from"os";import*as Fe from"readline";var Te=G.join(Ce.homedir(),".claude","projects"),pe=G.join(Ce.homedir(),".ccem"),Oe=1,Ie=()=>G.join(pe,"usage-cache.json"),vt=()=>G.join(pe,"model-prices.json");async function je(){try{await M.access(pe)}catch{await M.mkdir(pe,{recursive:!0})}}var Ht="https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",bt=()=>G.join(__dirname,"..","model-prices.json"),oe={"claude-opus-4-5":{input_cost_per_token:5e-6,output_cost_per_token:25e-6,cache_read_input_token_cost:5e-7,cache_creation_input_token_cost:625e-8},"claude-sonnet-4-5":{input_cost_per_token:3e-6,output_cost_per_token:15e-6,cache_read_input_token_cost:3e-7,cache_creation_input_token_cost:375e-8},"claude-haiku-4-5":{input_cost_per_token:1e-6,output_cost_per_token:5e-6,cache_read_input_token_cost:1e-7,cache_creation_input_token_cost:125e-8}};function me(e){return e.replace(/-20\d{6}.*$/,"").replace(/-v\d+:\d+$/,"").replace(/^anthropic\./,"").replace(/^vertex_ai\//,"").replace(/@.*$/,"")}var te=null;async function Dt(){if(te)return te;await je();let e=vt();try{let t=await fetch(Ht,{signal:AbortSignal.timeout(1e3)});if(t.ok){let o=await t.json(),s={};for(let[n,i]of Object.entries(o))i.input_cost_per_token&&i.output_cost_per_token&&(s[n]={input_cost_per_token:i.input_cost_per_token,output_cost_per_token:i.output_cost_per_token,cache_read_input_token_cost:i.cache_read_input_token_cost,cache_creation_input_token_cost:i.cache_creation_input_token_cost});return await M.writeFile(e,JSON.stringify(s,null,2)),te=s,s}}catch{}try{let t=await M.readFile(e,"utf-8"),o=JSON.parse(t);return te=o,o}catch{}try{let t=bt(),o=await M.readFile(t,"utf-8"),s=JSON.parse(o);return te=s,s}catch{}return te=oe,oe}function Bt(e,t){if(t[e])return t[e];let o=me(e);if(t[o])return t[o];for(let[s,n]of Object.entries(t))if(s.includes(o)||o.includes(me(s)))return n;return e.includes("opus")?oe["claude-opus-4-5"]:e.includes("sonnet")?oe["claude-sonnet-4-5"]:e.includes("haiku")?oe["claude-haiku-4-5"]:oe["claude-sonnet-4-5"]}function $t(e,t){return e.inputTokens*t.input_cost_per_token+e.outputTokens*t.output_cost_per_token+e.cacheReadTokens*(t.cache_read_input_token_cost||0)+e.cacheCreationTokens*(t.cache_creation_input_token_cost||0)}function $(){return{inputTokens:0,outputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,cost:0}}function U(e,t){return{inputTokens:e.inputTokens+t.inputTokens,outputTokens:e.outputTokens+t.outputTokens,cacheReadTokens:e.cacheReadTokens+t.cacheReadTokens,cacheCreationTokens:e.cacheCreationTokens+t.cacheCreationTokens,cost:e.cost+t.cost}}async function Ut(e){try{let t=await M.stat(e);return{mtime:t.mtimeMs,size:t.size}}catch{return null}}function Ft(){try{let e=Ie();if(!z.existsSync(e))return null;let t=JSON.parse(z.readFileSync(e,"utf-8"));return t.version!==Oe?null:t}catch{return null}}async function jt(){try{let e=Ie(),t=await M.readFile(e,"utf-8"),o=JSON.parse(t);return o.version!==Oe?null:o}catch{return null}}function Ke(){let e=Ft();if(!e)return null;let t=new Date,o=new Date(t.getFullYear(),t.getMonth(),t.getDate()),s=new Date(o);s.setDate(s.getDate()-s.getDay());let n={today:$(),week:$(),total:$(),dailyHistory:{},byModel:{},lastUpdated:t.toISOString()};for(let i of Object.values(e.files))for(let a of i.stats.entries){let l=new Date(a.timestamp),c=a.timestamp.split("T")[0];n.total=U(n.total,a.usage),n.dailyHistory[c]||(n.dailyHistory[c]=$()),n.dailyHistory[c]=U(n.dailyHistory[c],a.usage);let p=me(a.model);n.byModel[p]||(n.byModel[p]=$()),n.byModel[p]=U(n.byModel[p],a.usage),l>=o&&(n.today=U(n.today,a.usage)),l>=s&&(n.week=U(n.week,a.usage))}return n}async function Kt(e){try{await je(),await M.writeFile(Ie(),JSON.stringify(e,null,2))}catch{}}async function Yt(e,t,o){let s=[];try{let n=z.createReadStream(e,{encoding:"utf-8"}),i=Fe.createInterface({input:n,crlfDelay:1/0}),a=0;for await(let l of i){if(a++,a%100===0){if(o?.aborted)throw i.close(),n.destroy(),new Error("Aborted");a%1e3===0&&await new Promise(c=>setTimeout(c,0))}if(l.trim())try{let c=JSON.parse(l);if(c.type!=="assistant"||!c.message?.usage)continue;let p=c.message.model||"unknown",d=c.message.usage,_={inputTokens:d.input_tokens||0,outputTokens:d.output_tokens||0,cacheReadTokens:d.cache_read_input_tokens||0,cacheCreationTokens:d.cache_creation_input_tokens||0},m=Bt(p,t),g=$t(_,m);s.push({timestamp:c.timestamp||new Date().toISOString(),model:p,usage:{..._,cost:g}})}catch{}}}catch(n){if(n.message==="Aborted")throw n}return{entries:s}}async function Gt(){let e=[];try{if(!await M.access(Te).then(()=>!0).catch(()=>!1))return e;let o=await M.readdir(Te);for(let s of o){let n=G.join(Te,s);try{if((await M.stat(n)).isDirectory()){let a=await M.readdir(n);for(let l of a)l.endsWith(".jsonl")&&e.push(G.join(n,l))}}catch{}}}catch{}return e}async function Ye(e){if(e?.aborted)throw new Error("Aborted");let t=await Dt();if(e?.aborted)throw new Error("Aborted");let o=await Gt();if(e?.aborted)throw new Error("Aborted");let s=await jt(),n={version:Oe,files:{},lastUpdated:new Date().toISOString()},i=[],a=5,l=[];for(let m=0;m<o.length;m+=a)l.push(o.slice(m,m+a));for(let m of l){if(e?.aborted)throw new Error("Aborted");let g=m.map(async y=>{let A=await Ut(y);if(!A)return null;let C=s?.files[y],T=C&&C.meta.mtime===A.mtime&&C.meta.size===A.size,O;return T?O=C.stats:(O=await Yt(y,t,e),await new Promise(R=>setTimeout(R,0))),{file:y,meta:A,stats:O}}),h=await Promise.all(g);for(let y of h)y&&(n.files[y.file]={meta:y.meta,stats:y.stats},i.push(...y.stats.entries))}e?.aborted||Kt(n).catch(()=>{});let c=new Date,p=new Date(c.getFullYear(),c.getMonth(),c.getDate()),d=new Date(p);d.setDate(d.getDate()-d.getDay());let _={today:$(),week:$(),total:$(),dailyHistory:{},byModel:{},lastUpdated:c.toISOString()};for(let m of i){let g=new Date(m.timestamp),h=m.timestamp.split("T")[0];_.total=U(_.total,m.usage),_.dailyHistory[h]||(_.dailyHistory[h]=$()),_.dailyHistory[h]=U(_.dailyHistory[h],m.usage);let y=me(m.model);_.byModel[y]||(_.byModel[y]=$()),_.byModel[y]=U(_.byModel[y],m.usage),g>=p&&(_.today=U(_.today,m.usage)),g>=d&&(_.week=U(_.week,m.usage))}return _}function b(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"K":e.toString()}function ne(e){return e>=1||e>=.01?"$"+e.toFixed(2):"$"+e.toFixed(4)}function q(e){return e.inputTokens+e.outputTokens+e.cacheReadTokens+e.cacheCreationTokens}var r={primary:D.hex("#89B4FA"),accent:D.hex("#CBA6F7"),success:D.hex("#A6E3A1"),warning:D.hex("#F9E2AF"),danger:D.hex("#F38BA8"),text:D.white,muted:D.hex("#6C7086"),dim:D.hex("#45475A")},We=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],we=0,re=null,Wt=()=>r.primary(We[we]),Je=e=>{re||(re=setInterval(()=>{we=(we+1)%We.length,e()},80))},ue=()=>{re&&(clearInterval(re),re=null)};var ze=()=>process.stdout.columns||80,qe=(e,t,o)=>{let s=D.hex("#89B4FA"),n=D.hex("#45475A"),i=D.hex("#6C7086"),a=ze(),l=a<60,c=a<45,p=r.primary("CCEM")+" "+r.muted("Claude Code Env Manager"),d=r.primary("CCEM"),_=r.muted("Env: ")+r.primary(e),m=t.ANTHROPIC_BASE_URL||"-",g=t.ANTHROPIC_MODEL||"-",h=t.ANTHROPIC_SMALL_FAST_MODEL||"-",y=t.ANTHROPIC_API_KEY?t.ANTHROPIC_API_KEY.slice(0,2)+"\u2022\u2022\u2022\u2022"+t.ANTHROPIC_API_KEY.slice(-4):"-",A=(I,K)=>I.length>K?I.slice(0,K-3)+"...":I,C=(I,K)=>{if(I.length<=K)return I;try{let j=new URL(I),Mt=j.protocol+"//",He=j.host,_e=j.pathname+j.search,kt=He.slice(0,8),Nt=He.slice(-4),xt=_e.length>10?_e.slice(0,7)+"...":_e;return`${Mt}${kt}...${Nt}${xt}`}catch{return A(I,K)}},T=7,O;l?O=[_,r.muted("Model:".padEnd(T))+r.dim(A(g,25)),r.muted("Key:".padEnd(T))+r.dim(y)]:O=[_+(o&&w[o]?" "+r.accent(`[${w[o].name}]`):""),r.muted("URL:".padEnd(T))+r.dim(C(m,40)),r.muted("Model:".padEnd(T))+r.dim(A(g,15))+" "+r.muted("Fast:".padEnd(T))+r.dim(A(h,15)),r.muted("Key:".padEnd(T))+r.dim(y)];let R=[];if(c)R.push(` ${i("*")} ${n("\u2584\u2588\u2584")} ${i("*")}`),R.push(` ${i("*")} ${s("\u2590\u259B\u2588\u2588\u2588\u2588\u2588\u259C\u258C")} ${i("*")}`),R.push(` ${i("*")} ${s("\u259D\u259C\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u259B\u2598")} ${i("*")}`),R.push(` ${i("*")} ${s("\u2598\u2598 \u259D\u259D")} ${i("*")}`),R.push(""),R.push(d),R.push(""),O.forEach(I=>R.push(I));else{let I=l?" ":" ";R.push(""),R.push(` ${n("\u2584\u2588\u2588\u2584")} ${I}${l?d:p}`),R.push(` ${i("*")} ${s("\u2590\u259B\u2588\u2588\u2588\u2588\u2588\u259C\u258C")} ${i("*")} ${I}${O[0]||""}`),R.push(` ${i("*")} ${s("\u259D\u259C\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u259B\u2598")} ${i("*")} ${I}${O[1]||""}`),R.push(` ${i("*")} ${s("\u2598\u2598 \u259D\u259D")} ${i("*")} ${I}${O[2]||""}`),O[3]&&R.push(` ${I}${O[3]}`)}return R.join(`
3
+ `)},Ve=(e,t)=>{if(t)return r.muted(" Usage: ")+Wt()+r.dim(" Loading...");if(!e)return r.muted(" Usage: ")+r.dim("No data");let s=ze()<70,n=q(e.today),i=q(e.week),a=q(e.total);return s?r.muted(" Usage: ")+r.text("Today ")+r.primary(b(n))+r.dim(" | ")+r.text("Week ")+r.primary(b(i))+r.dim(" | ")+r.text("Total ")+r.primary(b(a)):r.muted(" Usage: ")+r.text("Today ")+r.primary(b(n).padStart(6))+r.dim(` (${ne(e.today.cost)})`)+r.dim(" | ")+r.text("Week ")+r.primary(b(i).padStart(6))+r.dim(` (${ne(e.week.cost)})`)+r.dim(" | ")+r.text("Total ")+r.primary(b(a).padStart(6))+r.dim(` (${ne(e.total.cost)})`)},Xe=()=>{let e=process.stdout.columns||80;return r.dim("\u2500".repeat(e))};var Qe=e=>{let t="Start Claude Code";return e&&w[e]&&(t=`Start Claude Code ${r.muted(`(${w[e].name})`)}`),[{name:r.success(t),value:"start",short:"Start"},{name:r.primary("Switch Environment"),value:"switch",short:"Switch"},{name:r.primary("Permission Mode"),value:"perm",short:"Permission"},{name:r.accent("View Usage"),value:"usage",short:"Usage"},{name:r.text("Set Default Mode"),value:"setDefault",short:"Default"},{name:r.muted("Exit"),value:"exit",short:"Exit"}]},Jt={yolo:r.danger,dev:r.success,readonly:r.primary,safe:r.warning,ci:r.accent,audit:r.primary},Le=(e,t=!1)=>{let s=["yolo","dev","readonly","safe","ci","audit"].map(n=>{let i=w[n],a=Jt[n],c=t&&n===e?r.success(" *"):"";return{name:a(i.name.padEnd(12))+r.muted(i.description)+c,value:n,short:i.name}});return t&&s.push({name:r.muted("Clear default"),value:"clear",short:"Clear"}),s.push({name:r.muted("Back"),value:"back",short:"Back"}),s};var v={success:e=>console.log(r.success("\u2713 ")+r.text(e)),error:e=>console.log(r.danger("\u2717 ")+r.text(e)),warning:e=>console.log(r.warning("! ")+r.text(e)),info:e=>console.log(r.primary("\u203A ")+r.text(e))},Ze=()=>r.muted("Starting Claude Code...");var zt=(e,t=6)=>{let o=[],s=new Date,n=new Date(s);n.setMonth(n.getMonth()-t);let i=n.getDay(),a=n.getDate()-i+(i===0?-6:1);n.setDate(a),n.setHours(0,0,0,0);let l=[],c=new Date(n);for(;(c<=s||c.getDay()!==1)&&(l.push(c.toISOString().split("T")[0]),c.setDate(c.getDate()+1),!(c>s&&c.getDay()===1)););let p=0;for(let A of l){let C=e.dailyHistory[A];if(C){let T=q(C);T>p&&(p=T)}}let d=" ",_=-1,m=Math.ceil(l.length/7);for(let A=0;A<m;A++){let C=A*7;if(C<l.length){let T=new Date(l[C]),O=T.getMonth();if(O!==_&&A<m-1){let R=T.toLocaleString("default",{month:"short"});d+=r.muted(R),_=O}}}d=" ";let g=-1;for(let A=0;A<m;A++){let C=A*7;if(C>=l.length)break;let T=new Date(l[C]),O=T.getMonth();if(O!==g){let R=T.toLocaleString("default",{month:"short"});d+=r.muted(R.padEnd(4)),A++,g=O}else d+=" "}o.push(d);let h=["Mon","","Wed","","Fri","","Sun"],y=[" ","\u2591","\u2592","\u2593","\u2588"];for(let A=0;A<7;A++){let C=r.muted((h[A]||"").padEnd(4)+" ");for(let T=0;T<m;T++){let O=T*7+A;if(O<l.length){let R=l[O];if(new Date(R)>s)C+=" ";else{let I=e.dailyHistory[R],K=I?q(I):0,j=0;K>0&&(p===0?j=0:j=Math.ceil(K/p*4)),C+=(j===0?r.dim("\xB7"):r.primary(y[j]))+" "}}}o.push(C)}return o.push(""),o.push(" "+r.dim("Less ")+r.dim("\xB7")+" "+r.primary(y[1])+" "+r.primary(y[2])+" "+r.primary(y[3])+" "+r.primary(y[4])+" "+r.dim(" More")),o.join(`
4
+ `)},et=e=>{let t=[];t.push(""),t.push(r.primary(" Token Usage Statistics")),t.push(r.dim("\u2500".repeat(60))),t.push(""),t.push(zt(e)),t.push(""),t.push(r.dim("\u2500".repeat(60)));let o=new Ge({head:[r.muted("Period"),r.muted("Input"),r.muted("Output"),r.muted("Cache Read"),r.muted("Cost")],style:{head:[],border:[]},chars:{top:"","top-mid":"","top-left":"","top-right":"",bottom:"","bottom-mid":"","bottom-left":"","bottom-right":"",left:" ","left-mid":"",mid:"","mid-mid":"",right:"","right-mid":"",middle:" "}}),s=(i,a)=>[r.text(i),r.primary(b(a.inputTokens)),r.primary(b(a.outputTokens)),r.primary(b(a.cacheReadTokens)),r.success(ne(a.cost))];o.push(s("Today",e.today)),o.push(s("This Week",e.week)),o.push(s("All Time",e.total)),t.push(o.toString());let n=Object.entries(e.byModel).sort((i,a)=>a[1].cost-i[1].cost);if(n.length>0){t.push(""),t.push(r.dim("\u2500".repeat(60))),t.push(r.muted(" By Model")),t.push("");let i=new Ge({head:[r.muted("Model"),r.muted("Tokens"),r.muted("Cost")],style:{head:[],border:[]},chars:{top:"","top-mid":"","top-left":"","top-right":"",bottom:"","bottom-mid":"","bottom-left":"","bottom-right":"",left:" ","left-mid":"",mid:"","mid-mid":"",right:"","right-mid":"",middle:" "}});for(let[a,l]of n){let c=q(l);i.push([r.text(a),r.primary(b(c)),r.success(ne(l.cost))])}t.push(i.toString())}return t.push(""),t.push(r.dim("\u2500".repeat(60))),t.push(r.muted(` Last updated: ${new Date(e.lastUpdated).toLocaleString()}`)),t.join(`
5
+ `)},tt=(e,t)=>new Promise(o=>{let s=Object.keys(e),n=s.indexOf(t);n===-1&&(n=0);let i=process.stdin,a=i.isRaw;i.setRawMode(!0),i.resume();let l=1+s.length,c=!0,p=()=>{process.stdout.write("\x1B[?25l"),c||(process.stdout.write(`\x1B[${l}A`),process.stdout.write("\x1B[J")),c=!1,console.log(r.muted("?")+" "+r.text("Select environment")+" "+r.dim("(\u2191\u2193 navigate, Enter select, e edit, r rename, c copy, d delete)")),s.forEach((m,g)=>{let h=m===t,y=g===n,A=y?r.primary("\u276F "):" ",C=h?r.success(" *"):"",T=y||h?r.primary(m):r.text(m);console.log(A+T+C)})};p();let d=()=>{i.setRawMode(a??!1),i.removeListener("data",_),process.stdout.write("\x1B[?25h")},_=m=>{let g=m.toString();if(g===""&&(d(),process.exit(0)),g==="\x1B"&&m.length===1){d(),o({action:"cancel"});return}if(g==="\x1B[A"||g==="k"){n=Math.max(0,n-1),p();return}if(g==="\x1B[B"||g==="j"){n=Math.min(s.length-1,n+1),p();return}if(g==="\r"||g===`
6
+ `){d(),o({action:"select",name:s[n]});return}if(g==="e"||g==="E"){d(),o({action:"edit",name:s[n]});return}if(g==="r"||g==="R"){d(),o({action:"rename",name:s[n]});return}if(g==="c"||g==="C"){d(),o({action:"copy",name:s[n]});return}if(g==="d"||g==="D"){d(),o({action:"delete",name:s[n]});return}};i.on("data",_)});import V from"fs";import S from"chalk";import ot from"cli-table3";import{spawn as qt}from"child_process";var Me=e=>{if(V.existsSync(e))try{let t=V.readFileSync(e,"utf-8");return JSON.parse(t)}catch{console.warn(S.yellow(`\u8B66\u544A: \u65E0\u6CD5\u89E3\u6790 ${e}\uFF0C\u5C06\u521B\u5EFA\u5907\u4EFD`));let t=e+".error."+Date.now();return V.copyFileSync(e,t),console.log(S.gray(`\u5907\u4EFD\u5DF2\u4FDD\u5B58\u5230: ${t}`)),{}}return{}},nt=(e,t)=>{$e(),V.writeFileSync(e,JSON.stringify(t,null,2)+`
7
+ `)},Vt=(e,t)=>{let o=e.permissions?.allow||[],s=e.permissions?.deny||[],n=[...new Set([...t.allow,...o])],i=[...new Set([...t.deny,...s])];return{...e,permissions:{allow:n,deny:i}}},st=e=>{let t=w[e];t||(console.error(S.red(`\u672A\u77E5\u7684\u6743\u9650\u6A21\u5F0F: ${e}`)),console.log(S.yellow("\u53EF\u7528\u6A21\u5F0F: "+Ee().join(", "))),process.exit(1));let o=de(!0),s=Me(o),n=Vt(s,t.permissions);nt(o,n),console.log(S.green(`\u5DF2\u5E94\u7528 ${t.name}`)),console.log(S.gray(`\u914D\u7F6E\u5DF2\u5199\u5165: ${o}`)),console.log(S.gray(`\u8BF4\u660E: ${t.description}`))},rt=()=>{let e=de(!0);if(!V.existsSync(e)){console.log(S.yellow("\u6CA1\u6709\u81EA\u5B9A\u4E49\u6743\u9650\u914D\u7F6E\u9700\u8981\u91CD\u7F6E"));return}let t=Me(e);delete t.permissions,Object.keys(t).length===0?(V.unlinkSync(e),console.log(S.green("\u5DF2\u5220\u9664\u914D\u7F6E\u6587\u4EF6\uFF08\u6587\u4EF6\u4E3A\u7A7A\uFF09"))):(nt(e,t),console.log(S.green("\u6743\u9650\u914D\u7F6E\u5DF2\u91CD\u7F6E"))),console.log(S.gray(`\u6587\u4EF6: ${e}`))},it=()=>{let e=de(!0);if(!V.existsSync(e)){console.log(S.yellow("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49\u6743\u9650")),console.log(S.gray(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${e}`));return}let t=Me(e);if(!t.permissions){console.log(S.yellow("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49\u6743\u9650"));return}let o=Object.entries(w).find(([a,l])=>{let c=new Set(t.permissions?.allow||[]),p=new Set(t.permissions?.deny||[]),d=new Set(l.permissions.allow),_=new Set(l.permissions.deny),m=l.permissions.allow.every(h=>c.has(h)),g=l.permissions.deny.every(h=>p.has(h));return m&&g});console.log(o?S.green(`\u5F53\u524D\u6A21\u5F0F: ${o[0]} (${o[1].name})`):S.yellow("\u5F53\u524D\u6A21\u5F0F: \u81EA\u5B9A\u4E49")),console.log(S.gray(`\u914D\u7F6E\u6587\u4EF6: ${e}`));let s=new ot({head:["\u7C7B\u578B","\u89C4\u5219"],style:{head:["cyan"]},colWidths:[10,70]}),n=t.permissions.allow||[],i=t.permissions.deny||[];s.push(["Allow",n.length>0?n.join(`
8
+ `):"(\u65E0)"]),s.push(["Deny",i.length>0?i.join(`
9
+ `):"(\u65E0)"]),console.log(s.toString())},at=()=>{let e=new ot({head:["\u6A21\u5F0F","\u6807\u5FD7","\u8BF4\u660E"],style:{head:["cyan"]},colWidths:[15,15,50]});Object.entries(w).forEach(([t,o])=>{e.push([o.name,`--${t}`,o.description])}),console.log(S.bold(`\u53EF\u7528\u6743\u9650\u6A21\u5F0F:
10
+ `)),console.log(e.toString()),console.log(S.gray(`
11
+ \u4E34\u65F6\u6A21\u5F0F: ccem <mode>`)),console.log(S.gray("\u6C38\u4E45\u6A21\u5F0F: ccem setup perms --<mode>"))},ge=async(e,t)=>{let o=w[e];o||(console.error(S.red(`\u672A\u77E5\u7684\u6743\u9650\u6A21\u5F0F: ${e}`)),console.log(S.yellow("\u53EF\u7528\u6A21\u5F0F: "+Ee().join(", "))),process.exit(1));let s=[];if(s.push("--permission-mode",o.permissionMode),o.permissions.allow.length>0){let i=o.permissions.allow.map(a=>`"${a}"`).join(" ");s.push("--allowedTools",i)}if(o.permissions.deny.length>0){let i=o.permissions.deny.map(a=>`"${a}"`).join(" ");s.push("--disallowedTools",i)}console.log(S.green(`\u5DF2\u5E94\u7528 ${o.name}\uFF08\u4E34\u65F6\uFF09`)),console.log(S.gray(`\u8BF4\u660E: ${o.description}`)),console.log("");let n={...process.env};return t&&(t.ANTHROPIC_BASE_URL&&(n.ANTHROPIC_BASE_URL=t.ANTHROPIC_BASE_URL),t.ANTHROPIC_API_KEY&&(n.ANTHROPIC_API_KEY=Y(t.ANTHROPIC_API_KEY)),t.ANTHROPIC_MODEL&&(n.ANTHROPIC_MODEL=t.ANTHROPIC_MODEL),t.ANTHROPIC_SMALL_FAST_MODEL&&(n.ANTHROPIC_SMALL_FAST_MODEL=t.ANTHROPIC_SMALL_FAST_MODEL)),new Promise(i=>{let a=qt("claude",s,{stdio:"inherit",shell:!0,env:n});a.on("exit",l=>{process.exit(l??0)}),a.on("error",l=>{console.error(S.red(`\u542F\u52A8 Claude Code \u5931\u8D25: ${l.message}`)),process.exit(1)})})};import ke from"fs";import P from"chalk";import{spawn as Xt}from"child_process";var ct=e=>{if(ke.existsSync(e))try{let t=ke.readFileSync(e,"utf-8");return JSON.parse(t)}catch{return console.warn(P.yellow(`\u8B66\u544A: \u65E0\u6CD5\u89E3\u6790 ${e}`)),{}}return{}},lt=(e,t)=>{ke.writeFileSync(e,JSON.stringify(t,null,2)+`
12
+ `)},Qt=()=>{let e=Pe();try{let t=ct(e);return t.hasCompletedOnboarding===!0?(console.log(P.gray(" \u2713 hasCompletedOnboarding \u5DF2\u8BBE\u7F6E")),!0):(t.hasCompletedOnboarding=!0,lt(e,t),console.log(P.green(" \u2713 \u5DF2\u8BBE\u7F6E hasCompletedOnboarding: true")),!0)}catch(t){return console.error(P.red(` \u2717 \u8BBE\u7F6E hasCompletedOnboarding \u5931\u8D25: ${t}`)),!1}},Zt=()=>{let e=Se();try{Ue();let t=ct(e);(!t.env||typeof t.env!="object")&&(t.env={});let o=t.env,s={DISABLE_BUG_COMMAND:"1",DISABLE_ERROR_REPORTING:"1",DISABLE_TELEMETRY:"1"},n=!1;for(let[i,a]of Object.entries(s))o[i]!==a&&(o[i]=a,n=!0);return n?(lt(e,t),console.log(P.green(" \u2713 \u5DF2\u914D\u7F6E\u73AF\u5883\u53D8\u91CF:")),console.log(P.gray(" DISABLE_BUG_COMMAND=1")),console.log(P.gray(" DISABLE_ERROR_REPORTING=1")),console.log(P.gray(" DISABLE_TELEMETRY=1")),!0):(console.log(P.gray(" \u2713 \u73AF\u5883\u53D8\u91CF\u5DF2\u914D\u7F6E")),!0)}catch(t){return console.error(P.red(` \u2717 \u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF\u5931\u8D25: ${t}`)),!1}},eo=()=>new Promise(e=>{console.log(P.cyan(" \u2192 \u6B63\u5728\u6DFB\u52A0 chrome-devtools MCP \u5DE5\u5177..."));let t=Xt("claude",["mcp","add","chrome-devtools","npx","chrome-devtools-mcp@latest","--scope","user"],{stdio:"pipe",shell:!0}),o="",s="";t.stdout?.on("data",n=>{o+=n.toString()}),t.stderr?.on("data",n=>{s+=n.toString()}),t.on("exit",n=>{n===0?(console.log(P.green(" \u2713 \u5DF2\u6DFB\u52A0 chrome-devtools MCP \u5DE5\u5177")),e(!0)):s.includes("already exists")||o.includes("already exists")?(console.log(P.gray(" \u2713 chrome-devtools MCP \u5DE5\u5177\u5DF2\u5B58\u5728")),e(!0)):(console.error(P.red(` \u2717 \u6DFB\u52A0 MCP \u5DE5\u5177\u5931\u8D25 (code: ${n})`)),s&&console.error(P.gray(` ${s.trim()}`)),e(!1))}),t.on("error",n=>{console.error(P.red(` \u2717 \u6267\u884C claude \u547D\u4EE4\u5931\u8D25: ${n.message}`)),console.log(P.yellow(" \u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5 Claude Code CLI")),e(!1)})}),dt=async()=>{console.log(P.bold(`
12
13
  \u{1F527} Claude Code \u521D\u59CB\u5316\u8BBE\u7F6E
13
- `)),console.log(P.cyan("1. \u8BBE\u7F6E onboarding \u72B6\u6001"));let e=Vt();console.log(P.cyan(`
14
- 2. \u914D\u7F6E\u9690\u79C1\u8BBE\u7F6E`));let t=qt();console.log(P.cyan(`
15
- 3. \u5B89\u88C5 MCP \u5DE5\u5177`));let o=await Xt();console.log(""),console.log(e&&t&&o?P.green.bold("\u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01"):P.yellow.bold("\u26A0\uFE0F \u90E8\u5206\u6B65\u9AA4\u672A\u5B8C\u6210\uFF0C\u8BF7\u68C0\u67E5\u4E0A\u8FF0\u9519\u8BEF")),console.log(P.gray(`
16
- \u914D\u7F6E\u6587\u4EF6\u4F4D\u7F6E:`)),console.log(P.gray(` - ${Se()}`)),console.log(P.gray(` - ${Pe()}`)),console.log("")};import{execSync as te}from"child_process";import*as T from"fs";import*as x from"path";import M from"chalk";var mt={official:{label:"\u5B98\u65B9",icon:"\u{1F3E2}"},featured:{label:"\u7CBE\u9009",icon:"\u2B50"},others:{label:"\u5176\u4ED6",icon:"\u{1F4E6}"}},gt=[{name:"frontend-design",description:"\u521B\u5EFA\u9AD8\u8D28\u91CF\u524D\u7AEF\u754C\u9762\u8BBE\u8BA1",group:"official",install:{type:"preset",name:"frontend-design"}},{name:"skill-creator",description:"\u521B\u5EFA\u65B0\u7684 Claude Code skills",group:"official",install:{type:"preset",name:"skill-creator"}},{name:"web-artifacts-builder",description:"\u6784\u5EFA\u53EF\u4EA4\u4E92\u7684 Web \u7EC4\u4EF6",group:"official",install:{type:"preset",name:"web-artifacts-builder"}},{name:"canvas-design",description:"Canvas \u7ED8\u56FE\u8BBE\u8BA1",group:"official",install:{type:"preset",name:"canvas-design"}},{name:"algorithmic-art",description:"\u7B97\u6CD5\u827A\u672F\u751F\u6210",group:"official",install:{type:"preset",name:"algorithmic-art"}},{name:"theme-factory",description:"\u4E3B\u9898\u5DE5\u5382 - \u521B\u5EFA UI \u4E3B\u9898",group:"official",install:{type:"preset",name:"theme-factory"}},{name:"mcp-builder",description:"\u6784\u5EFA MCP \u670D\u52A1\u5668",group:"official",install:{type:"preset",name:"mcp-builder"}},{name:"webapp-testing",description:"Web \u5E94\u7528\u6D4B\u8BD5",group:"official",install:{type:"preset",name:"webapp-testing"}},{name:"pdf",description:"PDF \u6587\u6863\u5904\u7406",group:"official",install:{type:"preset",name:"pdf"}},{name:"docx",description:"Word \u6587\u6863\u5904\u7406",group:"official",install:{type:"preset",name:"docx"}},{name:"pptx",description:"PowerPoint \u6F14\u793A\u6587\u7A3F\u5904\u7406",group:"official",install:{type:"preset",name:"pptx"}},{name:"xlsx",description:"Excel \u8868\u683C\u5904\u7406",group:"official",install:{type:"preset",name:"xlsx"}},{name:"brand-guidelines",description:"\u54C1\u724C\u6307\u5357\u751F\u6210",group:"official",install:{type:"preset",name:"brand-guidelines"}},{name:"doc-coauthoring",description:"\u6587\u6863\u534F\u4F5C\u7F16\u5199",group:"official",install:{type:"preset",name:"doc-coauthoring"}},{name:"internal-comms",description:"\u5185\u90E8\u901A\u4FE1\u6587\u6863",group:"official",install:{type:"preset",name:"internal-comms"}},{name:"slack-gif-creator",description:"Slack GIF \u521B\u5EFA\u5668",group:"official",install:{type:"preset",name:"slack-gif-creator"}},{name:"superpowers",description:"Claude Code Plan\u6A21\u5F0F\u5347\u7EA7\u7248\uFF0C\u8FDE\u7EED\u8FFD\u95EE\u8BA8\u8BBA\u786E\u5B9A\u5F00\u53D1\u65B9\u6848",group:"featured",install:{type:"plugin",marketplace:"obra/superpowers-marketplace",package:"superpowers@superpowers-marketplace"}},{name:"ui-ux-pro-max",description:"\u4E13\u4E1A UI/UX \u8BBE\u8BA1",group:"featured",install:{type:"github",url:"https://github.com/nextlevelbuilder/ui-ux-pro-max-skill/tree/main/.claude/skills/ui-ux-pro-max"}},{name:"Humanizer-zh",description:"\u53BB\u9664\u6587\u672C\u4E2D AI \u751F\u6210\u75D5\u8FF9\uFF0C\u6539\u5199\u5F97\u66F4\u81EA\u7136\u3001\u66F4\u50CF\u4EBA\u7C7B\u4E66\u5199",group:"featured",install:{type:"github",url:"https://github.com/op7418/Humanizer-zh"}},{name:"skill-writer",description:"\u6307\u5BFC\u7528\u6237\u4E3A Claude Code \u521B\u5EFA\u4EE3\u7406\u6280\u80FD",group:"others",install:{type:"github",url:"https://github.com/pytorch/pytorch/tree/main/.claude/skills/skill-writer"}}];function ht(e){return gt.filter(t=>t.group===e)}function ft(){return["official","featured","others"]}function ut(e){if(/^[\w-]+\/[\w-]+$/.test(e)){let[a,c]=e.split("/");return{owner:a,repo:c,branch:"main",path:""}}let t=e.match(/github\.com\/([^/]+)\/([^/]+)(?:\/tree\/([^/]+)(?:\/(.*))?)?/);if(!t)return null;let[,o,n,s="main",i=""]=t;return{owner:o,repo:n.replace(/\.git$/,""),branch:s,path:i}}function Le(){return x.join(process.cwd(),".claude","skills")}function Qt(){let e=Le();return T.existsSync(e)?Zt(e):T.mkdirSync(e,{recursive:!0}),e}function Zt(e){try{let t=T.readdirSync(e,{withFileTypes:!0});for(let o of t)if(o.isDirectory()&&o.name.startsWith(".tmp-")){let n=x.join(e,o.name);T.rmSync(n,{recursive:!0})}}catch{}}function me(e,t,o,n,s){let i=Qt(),a=x.join(i,s);T.existsSync(a)&&(console.log(M.yellow(`Skill "${s}" already exists. Updating...`)),T.rmSync(a,{recursive:!0}));let c=`https://github.com/${e}/${t}.git`,l=x.join(i,`.tmp-${Date.now()}`);try{T.mkdirSync(l,{recursive:!0}),te("git init",{cwd:l,stdio:"pipe"}),te(`git remote add origin ${c}`,{cwd:l,stdio:"pipe"}),te("git config core.sparseCheckout true",{cwd:l,stdio:"pipe"});let m=x.join(l,".git","info","sparse-checkout");T.writeFileSync(m,n?`${n}/
14
+ `)),console.log(P.cyan("1. \u8BBE\u7F6E onboarding \u72B6\u6001"));let e=Qt();console.log(P.cyan(`
15
+ 2. \u914D\u7F6E\u9690\u79C1\u8BBE\u7F6E`));let t=Zt();console.log(P.cyan(`
16
+ 3. \u5B89\u88C5 MCP \u5DE5\u5177`));let o=await eo();console.log(""),console.log(e&&t&&o?P.green.bold("\u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01"):P.yellow.bold("\u26A0\uFE0F \u90E8\u5206\u6B65\u9AA4\u672A\u5B8C\u6210\uFF0C\u8BF7\u68C0\u67E5\u4E0A\u8FF0\u9519\u8BEF")),console.log(P.gray(`
17
+ \u914D\u7F6E\u6587\u4EF6\u4F4D\u7F6E:`)),console.log(P.gray(` - ${Pe()}`)),console.log(P.gray(` - ${Se()}`)),console.log("")};import{execSync as se}from"child_process";import*as E from"fs";import*as H from"path";import L from"chalk";var mt={official:{label:"\u5B98\u65B9",icon:"\u{1F3E2}"},featured:{label:"\u7CBE\u9009",icon:"\u2B50"},others:{label:"\u5176\u4ED6",icon:"\u{1F4E6}"}},ut=[{name:"frontend-design",description:"\u521B\u5EFA\u9AD8\u8D28\u91CF\u524D\u7AEF\u754C\u9762\u8BBE\u8BA1",group:"official",install:{type:"preset",name:"frontend-design"}},{name:"skill-creator",description:"\u521B\u5EFA\u65B0\u7684 Claude Code skills",group:"official",install:{type:"preset",name:"skill-creator"}},{name:"web-artifacts-builder",description:"\u6784\u5EFA\u53EF\u4EA4\u4E92\u7684 Web \u7EC4\u4EF6",group:"official",install:{type:"preset",name:"web-artifacts-builder"}},{name:"canvas-design",description:"Canvas \u7ED8\u56FE\u8BBE\u8BA1",group:"official",install:{type:"preset",name:"canvas-design"}},{name:"algorithmic-art",description:"\u7B97\u6CD5\u827A\u672F\u751F\u6210",group:"official",install:{type:"preset",name:"algorithmic-art"}},{name:"theme-factory",description:"\u4E3B\u9898\u5DE5\u5382 - \u521B\u5EFA UI \u4E3B\u9898",group:"official",install:{type:"preset",name:"theme-factory"}},{name:"mcp-builder",description:"\u6784\u5EFA MCP \u670D\u52A1\u5668",group:"official",install:{type:"preset",name:"mcp-builder"}},{name:"webapp-testing",description:"Web \u5E94\u7528\u6D4B\u8BD5",group:"official",install:{type:"preset",name:"webapp-testing"}},{name:"pdf",description:"PDF \u6587\u6863\u5904\u7406",group:"official",install:{type:"preset",name:"pdf"}},{name:"docx",description:"Word \u6587\u6863\u5904\u7406",group:"official",install:{type:"preset",name:"docx"}},{name:"pptx",description:"PowerPoint \u6F14\u793A\u6587\u7A3F\u5904\u7406",group:"official",install:{type:"preset",name:"pptx"}},{name:"xlsx",description:"Excel \u8868\u683C\u5904\u7406",group:"official",install:{type:"preset",name:"xlsx"}},{name:"brand-guidelines",description:"\u54C1\u724C\u6307\u5357\u751F\u6210",group:"official",install:{type:"preset",name:"brand-guidelines"}},{name:"doc-coauthoring",description:"\u6587\u6863\u534F\u4F5C\u7F16\u5199",group:"official",install:{type:"preset",name:"doc-coauthoring"}},{name:"internal-comms",description:"\u5185\u90E8\u901A\u4FE1\u6587\u6863",group:"official",install:{type:"preset",name:"internal-comms"}},{name:"slack-gif-creator",description:"Slack GIF \u521B\u5EFA\u5668",group:"official",install:{type:"preset",name:"slack-gif-creator"}},{name:"superpowers",description:"Claude Code Plan\u6A21\u5F0F\u5347\u7EA7\u7248\uFF0C\u8FDE\u7EED\u8FFD\u95EE\u8BA8\u8BBA\u786E\u5B9A\u5F00\u53D1\u65B9\u6848",group:"featured",install:{type:"plugin",marketplace:"obra/superpowers-marketplace",package:"superpowers@superpowers-marketplace"}},{name:"ui-ux-pro-max",description:"\u4E13\u4E1A UI/UX \u8BBE\u8BA1",group:"featured",install:{type:"github",url:"https://github.com/nextlevelbuilder/ui-ux-pro-max-skill/tree/main/.claude/skills/ui-ux-pro-max"}},{name:"Humanizer-zh",description:"\u53BB\u9664\u6587\u672C\u4E2D AI \u751F\u6210\u75D5\u8FF9\uFF0C\u6539\u5199\u5F97\u66F4\u81EA\u7136\u3001\u66F4\u50CF\u4EBA\u7C7B\u4E66\u5199",group:"featured",install:{type:"github",url:"https://github.com/op7418/Humanizer-zh"}},{name:"skill-writer",description:"\u6307\u5BFC\u7528\u6237\u4E3A Claude Code \u521B\u5EFA\u4EE3\u7406\u6280\u80FD",group:"others",install:{type:"github",url:"https://github.com/pytorch/pytorch/tree/main/.claude/skills/skill-writer"}}];function gt(e){return ut.filter(t=>t.group===e)}function ft(){return["official","featured","others"]}function pt(e){if(/^[\w-]+\/[\w-]+$/.test(e)){let[a,l]=e.split("/");return{owner:a,repo:l,branch:"main",path:""}}let t=e.match(/github\.com\/([^/]+)\/([^/]+)(?:\/tree\/([^/]+)(?:\/(.*))?)?/);if(!t)return null;let[,o,s,n="main",i=""]=t;return{owner:o,repo:s.replace(/\.git$/,""),branch:n,path:i}}function Ne(){return H.join(process.cwd(),".claude","skills")}function to(){let e=Ne();return E.existsSync(e)?oo(e):E.mkdirSync(e,{recursive:!0}),e}function oo(e){try{let t=E.readdirSync(e,{withFileTypes:!0});for(let o of t)if(o.isDirectory()&&o.name.startsWith(".tmp-")){let s=H.join(e,o.name);E.rmSync(s,{recursive:!0})}}catch{}}function fe(e,t,o,s,n){let i=to(),a=H.join(i,n);E.existsSync(a)&&(console.log(L.yellow(`Skill "${n}" already exists. Updating...`)),E.rmSync(a,{recursive:!0}));let l=`https://github.com/${e}/${t}.git`,c=H.join(i,`.tmp-${Date.now()}`);try{E.mkdirSync(c,{recursive:!0}),se("git init",{cwd:c,stdio:"pipe"}),se(`git remote add origin ${l}`,{cwd:c,stdio:"pipe"}),se("git config core.sparseCheckout true",{cwd:c,stdio:"pipe"});let p=H.join(c,".git","info","sparse-checkout");E.writeFileSync(p,s?`${s}/
17
18
  `:`*
18
- `),te(`git pull --depth=1 origin ${o}`,{cwd:l,stdio:"pipe"});let f=n?x.join(l,n):l;if(!T.existsSync(f))throw new Error(`Path "${n}" not found in repository`);return yt(f,a),console.log(M.green(`Successfully installed skill "${s}"`)),!0}catch(m){let f=m instanceof Error?m.message:String(m);return console.error(M.red(`Failed to download skill: ${f}`)),!1}finally{T.existsSync(l)&&T.rmSync(l,{recursive:!0})}}function yt(e,t){T.mkdirSync(t,{recursive:!0});let o=T.readdirSync(e,{withFileTypes:!0});for(let n of o){if(n.name===".git")continue;let s=x.join(e,n.name),i=x.join(t,n.name);n.isDirectory()?yt(s,i):T.copyFileSync(s,i)}}function ge(e){let t=gt.find(s=>s.name===e);if(t){if(t.install.type==="preset")return me("anthropics","skills","main",`skills/${t.install.name}`,t.name);if(t.install.type==="github"){let s=ut(t.install.url);return s?me(s.owner,s.repo,s.branch,s.path,t.name):(console.error(M.red(`Invalid GitHub URL in preset: ${t.install.url}`)),!1)}else if(t.install.type==="plugin")return console.error(M.yellow(`Plugin installation not yet supported for "${t.name}"`)),console.log(M.gray(`Marketplace: ${t.install.marketplace}`)),console.log(M.gray(`Package: ${t.install.package}`)),!1}let o=ut(e);if(!o)return console.error(M.red("Invalid GitHub URL or preset name")),console.log(M.gray("Examples:")),console.log(M.gray(" ccem skill add frontend-design")),console.log(M.gray(" ccem skill add https://github.com/owner/repo")),console.log(M.gray(" ccem skill add https://github.com/owner/repo/tree/main/path")),!1;let n;return o.path?n=x.basename(o.path):n=o.repo,me(o.owner,o.repo,o.branch,o.path,n)}function _t(){let e=Le();return T.existsSync(e)?T.readdirSync(e,{withFileTypes:!0}).filter(o=>o.isDirectory()&&!o.name.startsWith(".")).map(o=>({name:o.name,path:x.join(e,o.name)})):[]}function St(e){let t=Le(),o=x.join(t,e);return T.existsSync(o)?(T.rmSync(o,{recursive:!0}),console.log(M.green(`Removed skill "${e}"`)),!0):(console.error(M.red(`Skill "${e}" not found`)),!1)}function eo(e,t){try{return console.log(M.cyan(`Adding marketplace: ${e}...`)),te(`claude plugin marketplace add ${e}`,{stdio:"inherit"}),console.log(M.cyan(`Installing package: ${t}...`)),te(`claude plugin install ${t}`,{stdio:"inherit"}),console.log(M.green(`Successfully installed ${t}`)),!0}catch(o){let n=o instanceof Error?o.message:String(o);return console.error(M.red(`Failed to install from marketplace: ${n}`)),!1}}function Pt(e){switch(console.log(M.cyan(`Installing ${e.name}...`)),e.install.type){case"preset":let t={repo:"anthropics/skills",path:`skills/${e.install.name}`,branch:"main"},[o,n]=t.repo.split("/");return me(o,n,t.branch,t.path,e.name);case"github":return ge(e.install.url);case"plugin":return eo(e.install.marketplace,e.install.package)}}import{render as no}from"ink";import{useState as At,useEffect as to}from"react";import{Box as K,Text as V,useInput as oo,useApp as so}from"ink";import{jsx as H,jsxs as re}from"react/jsx-runtime";function Ct({onSelect:e,onCancel:t}){let{exit:o}=so(),n=ft(),[s,i]=At(0),[a,c]=At(0),l=n[s],f=[...ht(l),null],y=f.length-1;return to(()=>{c(0)},[s]),oo((p,_)=>{if(_.tab&&!_.shift){i(u=>(u+1)%n.length);return}if(_.tab&&_.shift){i(u=>(u-1+n.length)%n.length);return}if(_.upArrow){c(u=>Math.max(0,u-1));return}if(_.downArrow){c(u=>Math.min(y,u+1));return}if(_.return){let u=f[a];e(u===null?"custom":u);return}if(_.escape||p==="q"){t(),o();return}}),re(K,{flexDirection:"column",children:[H(K,{marginBottom:1,children:n.map((p,_)=>{let u=mt[p],g=_===s;return H(K,{marginRight:2,children:re(V,{bold:g,color:g?"cyan":"gray",inverse:g,children:[" ",u.icon," ",u.label," "]})},p)})}),H(K,{marginBottom:1,children:H(V,{color:"gray",children:"\u2500".repeat(50)})}),H(K,{flexDirection:"column",children:f.map((p,_)=>{let u=_===a,g=u?"\u276F ":" ";return p===null?H(K,{children:re(V,{color:u?"yellow":"gray",children:[g,"\u8F93\u5165\u81EA\u5B9A\u4E49 GitHub URL"]})},"custom"):H(K,{children:re(V,{color:u?"cyan":void 0,children:[g,H(V,{bold:u,children:p.name}),re(V,{color:"gray",children:[" - ",p.description]})]})},p.name)})}),H(K,{marginTop:1,children:H(V,{color:"gray",children:"Tab \u5207\u6362\u5206\u7EC4 | \u2191\u2193 \u9009\u62E9 | Enter \u786E\u8BA4 | Esc \u53D6\u6D88"})})]})}import{jsx as ro}from"react/jsx-runtime";async function Tt(){return new Promise(e=>{let t=!1,{unmount:o,waitUntilExit:n}=no(ro(Ct,{onSelect:s=>{t||(t=!0,o(),e(s==="custom"?{type:"custom"}:{type:"skill",skill:s}))},onCancel:()=>{t||(t=!0,o(),e({type:"cancelled"}))}}));n().then(()=>{t||e({type:"cancelled"})})})}var lo=co(import.meta.url),po=fe.dirname(lo),uo=fe.resolve(po,"..","package.json"),mo=JSON.parse(Rt.readFileSync(uo,"utf-8")),L=new io,h=new ao({projectName:"claude-code-env-manager",defaults:{registries:{official:{ANTHROPIC_BASE_URL:"https://api.anthropic.com",ANTHROPIC_MODEL:"claude-sonnet-4-5-20250929",ANTHROPIC_SMALL_FAST_MODEL:"claude-haiku-4-5-20251001"}},current:"official",defaultMode:null}}),ie=["yolo","dev","readonly","safe","ci","audit"],W=null,oe=!0;var q=null,go=e=>{let t=We();t?(W=t,oe=!1):e&&Ve(e),q&&q.abort(),q=new AbortController;let o=q.signal;Ye(o).then(n=>{if(o.aborted)return;let s=oe||W&&n&&W.lastUpdated!==n.lastUpdated;W=n,oe=!1,pe(),s&&e&&e()}).catch(n=>{n.message!=="Aborted"&&(oe=!1,pe())})};L.name("ccem").description("Claude Code Environment Manager - \u7BA1\u7406 Claude Code \u73AF\u5883\u53D8\u91CF\u548C\u6743\u9650").version(mo.version).option("--mode","\u67E5\u770B\u5F53\u524D\u6743\u9650\u6A21\u5F0F").option("--list-modes","\u5217\u51FA\u6240\u6709\u53EF\u7528\u6743\u9650\u6A21\u5F0F");ie.forEach(e=>{let t=O[e];L.command(e).description(`\u4E34\u65F6\u5E94\u7528 ${t.name}\uFF0C\u9000\u51FA\u540E\u8FD8\u539F`).action(async()=>{let o=h.get("registries"),n=h.get("current"),s=o[n];await ue(e,s)})});var be=(e,t)=>{if(!process.stdout.isTTY)return;let o=h.get("current"),s=h.get("registries")[o],i=h.get("defaultMode");s&&(console.log(Xe(o,{ANTHROPIC_BASE_URL:s.ANTHROPIC_BASE_URL,ANTHROPIC_API_KEY:s.ANTHROPIC_API_KEY?j(s.ANTHROPIC_API_KEY):void 0,ANTHROPIC_MODEL:s.ANTHROPIC_MODEL,ANTHROPIC_SMALL_FAST_MODEL:s.ANTHROPIC_SMALL_FAST_MODEL},i)),console.log(""),console.log(Qe(e,t)),console.log(Ze()),console.log(""))},ho=async e=>{let t=h.get("registries");if(!t[e]){console.error(d.red(`Environment '${e}' not found.`));return}h.set("current",e),process.stdout.isTTY?console.log(d.green(`Switched to environment '${e}'`)):console.error(d.green(`Switched to environment '${e}'`)),be(null,!1);let o=t[e],n=[];o.ANTHROPIC_BASE_URL&&n.push(`export ANTHROPIC_BASE_URL="${o.ANTHROPIC_BASE_URL}"`),o.ANTHROPIC_API_KEY&&n.push(`export ANTHROPIC_API_KEY="${j(o.ANTHROPIC_API_KEY)}"`),o.ANTHROPIC_MODEL&&n.push(`export ANTHROPIC_MODEL="${o.ANTHROPIC_MODEL}"`),o.ANTHROPIC_SMALL_FAST_MODEL&&n.push(`export ANTHROPIC_SMALL_FAST_MODEL="${o.ANTHROPIC_SMALL_FAST_MODEL}"`),process.stdout.isTTY?(console.log(d.yellow(`
19
- To apply to current shell immediately, run:`)),console.log(d.cyan("eval $(ccem env)")),console.log(d.yellow(`
20
- Or manually export:`)),n.forEach(s=>console.log(s))):n.forEach(s=>console.log(s))};L.command("ls").description("List all configured environments").action(()=>{let e=h.get("registries"),t=h.get("current"),o=new kt({head:["Name","Base URL","Model"],style:{head:["cyan"]}});Object.keys(e).forEach(n=>{let s=e[n],i=n===t?d.green("* "):" ";o.push([i+n,s.ANTHROPIC_BASE_URL||"-",s.ANTHROPIC_MODEL||"-"])}),console.log(o.toString())});L.command("use <name>").description("Switch to a specific environment").action(async e=>{await ho(e)});L.command("add <name>").description("Add a new environment configuration").action(async e=>{let t=h.get("registries");if(t[e]){console.log(d.red(`Environment '${e}' already exists.`));return}let{usePreset:o}=await U.prompt([{type:"confirm",name:"usePreset",message:"Do you want to use a preset configuration?",default:!0}]),n={};if(o){let{presetName:i}=await U.prompt([{type:"list",name:"presetName",message:"Select a preset:",choices:Object.keys(Ae)}]);n=Ae[i]}let s=await U.prompt([{type:"input",name:"ANTHROPIC_BASE_URL",message:"Enter ANTHROPIC_BASE_URL:",default:n.ANTHROPIC_BASE_URL||"https://api.anthropic.com"},{type:"password",name:"ANTHROPIC_API_KEY",message:"Enter ANTHROPIC_API_KEY:"},{type:"input",name:"ANTHROPIC_MODEL",message:"Enter ANTHROPIC_MODEL:",default:n.ANTHROPIC_MODEL||"claude-sonnet-4-5-20250929"},{type:"input",name:"ANTHROPIC_SMALL_FAST_MODEL",message:"Enter ANTHROPIC_SMALL_FAST_MODEL:",default:n.ANTHROPIC_SMALL_FAST_MODEL||"claude-haiku-4-5-20251001"}]);s.ANTHROPIC_API_KEY&&(s.ANTHROPIC_API_KEY=$e(s.ANTHROPIC_API_KEY)),t[e]=s,h.set("registries",t),console.log(d.green(`Environment '${e}' added successfully.`))});L.command("del <name>").description("Delete an environment configuration").action(e=>{let t=h.get("registries");if(!t[e]){console.log(d.red(`Environment '${e}' not found.`));return}if(e==="official"){console.log(d.red("Cannot delete default 'official' environment."));return}delete t[e],h.set("registries",t),h.get("current")===e&&(h.set("current","official"),console.log(d.yellow("Deleted current environment. Switched back to 'official'."))),console.log(d.green(`Environment '${e}' deleted.`))});L.command("current").description("Show current environment name").action(()=>{let e=h.get("current");console.log(d.green(e))});L.command("env").description("Output environment variables for shell eval").option("--json","Output as JSON").action(e=>{let t=h.get("registries"),o=h.get("current"),n=t[o];if(!n)return;let s={...n};s.ANTHROPIC_API_KEY&&(s.ANTHROPIC_API_KEY=j(s.ANTHROPIC_API_KEY)),e.json?console.log(JSON.stringify(s,null,2)):(s.ANTHROPIC_BASE_URL&&console.log(`export ANTHROPIC_BASE_URL="${s.ANTHROPIC_BASE_URL}"`),s.ANTHROPIC_API_KEY&&console.log(`export ANTHROPIC_API_KEY="${s.ANTHROPIC_API_KEY}"`),s.ANTHROPIC_MODEL&&console.log(`export ANTHROPIC_MODEL="${s.ANTHROPIC_MODEL}"`),s.ANTHROPIC_SMALL_FAST_MODEL&&console.log(`export ANTHROPIC_SMALL_FAST_MODEL="${s.ANTHROPIC_SMALL_FAST_MODEL}"`))});L.command("run <command...>").description("Run a command with the current environment variables").action(e=>{let t=h.get("registries"),o=h.get("current"),n=t[o];n||(console.error(d.red("No environment configuration found.")),process.exit(1));let s={...process.env};n.ANTHROPIC_BASE_URL&&(s.ANTHROPIC_BASE_URL=n.ANTHROPIC_BASE_URL),n.ANTHROPIC_API_KEY&&(s.ANTHROPIC_API_KEY=j(n.ANTHROPIC_API_KEY||"")),n.ANTHROPIC_MODEL&&(s.ANTHROPIC_MODEL=n.ANTHROPIC_MODEL),n.ANTHROPIC_SMALL_FAST_MODEL&&(s.ANTHROPIC_SMALL_FAST_MODEL=n.ANTHROPIC_SMALL_FAST_MODEL);let[i,...a]=e;Et(i,a,{env:s,stdio:"inherit",shell:!0}).on("exit",l=>{process.exit(l??0)})});var Ne=L.command("setup").description("Setup commands for permanent configurations");Ne.command("perms").description("\u6C38\u4E45\u914D\u7F6E\u6743\u9650\u6A21\u5F0F").option("--yolo","\u5E94\u7528 YOLO \u6A21\u5F0F\uFF08\u5168\u90E8\u653E\u5F00\uFF09").option("--dev","\u5E94\u7528\u5F00\u53D1\u6A21\u5F0F").option("--readonly","\u5E94\u7528\u53EA\u8BFB\u6A21\u5F0F").option("--safe","\u5E94\u7528\u5B89\u5168\u6A21\u5F0F").option("--ci","\u5E94\u7528 CI/CD \u6A21\u5F0F").option("--audit","\u5E94\u7528\u5BA1\u8BA1\u6A21\u5F0F").option("--reset","\u91CD\u7F6E\u6743\u9650\u914D\u7F6E").action(function(){let e=this.opts();if(e.reset){it();return}for(let t of ie)if(e[t]){rt(t);return}console.log(d.yellow("\u8BF7\u6307\u5B9A\u4E00\u4E2A\u6743\u9650\u6A21\u5F0F\uFF0C\u4F8B\u5982: ccem setup perms --dev")),console.log(d.gray("\u53EF\u7528\u6A21\u5F0F: "+ie.join(", "))),console.log(d.gray("\u91CD\u7F6E\u6743\u9650: ccem setup perms --reset"))});Ne.command("default-mode").description("\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F").option("--yolo","YOLO \u6A21\u5F0F").option("--dev","\u5F00\u53D1\u6A21\u5F0F").option("--readonly","\u53EA\u8BFB\u6A21\u5F0F").option("--safe","\u5B89\u5168\u6A21\u5F0F").option("--ci","CI/CD \u6A21\u5F0F").option("--audit","\u5BA1\u8BA1\u6A21\u5F0F").option("--reset","\u6E05\u9664\u9ED8\u8BA4\u6A21\u5F0F").action(function(){let e=this.opts();if(e.reset){h.set("defaultMode",null),console.log(d.green("\u5DF2\u6E05\u9664\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F"));return}for(let o of ie)if(e[o]){h.set("defaultMode",o),console.log(d.green(`\u5DF2\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F: ${O[o].name}`)),console.log(d.gray("\u4E0B\u6B21\u542F\u52A8 ccem \u65F6\u5C06\u9ED8\u8BA4\u4F7F\u7528\u6B64\u6A21\u5F0F"));return}let t=h.get("defaultMode");t&&O[t]?console.log(d.green(`\u5F53\u524D\u9ED8\u8BA4\u6A21\u5F0F: ${O[t].name}`)):console.log(d.yellow("\u672A\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F")),console.log(d.gray(`
21
- \u8BBE\u7F6E\u9ED8\u8BA4\u6A21\u5F0F: ccem setup default-mode --dev`)),console.log(d.gray("\u6E05\u9664\u9ED8\u8BA4\u6A21\u5F0F: ccem setup default-mode --reset")),console.log(d.gray("\u53EF\u7528\u6A21\u5F0F: "+ie.join(", ")))});Ne.command("init").description("\u521D\u59CB\u5316 Claude Code \u5168\u5C40\u914D\u7F6E\uFF08\u8DF3\u8FC7 onboarding\u3001\u7981\u7528\u9065\u6D4B\u3001\u5B89\u88C5 MCP \u5DE5\u5177\uFF09").action(async()=>{await pt()});var Be=L.command("skill").description("\u7BA1\u7406 Claude Code skills");Be.command("add [url]").description("\u6DFB\u52A0 skill\uFF08\u4ECE\u5B98\u65B9\u9884\u8BBE\u6216 GitHub URL\uFF09").action(async e=>{if(e)ge(e);else{let t=await Tt();if(t.type==="cancelled"){console.log(d.yellow("\u5DF2\u53D6\u6D88"));return}if(t.type==="custom"){let{customUrl:o}=await U.prompt([{type:"input",name:"customUrl",message:"\u8F93\u5165 GitHub URL:",validate:n=>n.trim()?!n.includes("github.com")&&!/^[\w-]+\/[\w-]+$/.test(n)?"\u8BF7\u8F93\u5165\u6709\u6548\u7684 GitHub URL \u6216 owner/repo \u683C\u5F0F":!0:"\u8BF7\u8F93\u5165\u6709\u6548\u7684 URL"}]);ge(o)}else t.skill&&Pt(t.skill)}});Be.command("ls").description("\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 skills").action(()=>{let e=_t();if(e.length===0){console.log(d.yellow("\u5F53\u524D\u76EE\u5F55\u6CA1\u6709\u5B89\u88C5\u4EFB\u4F55 skill")),console.log(d.gray("\u4F7F\u7528 ccem skill add \u6DFB\u52A0 skills"));return}let t=new kt({head:["Name","Path"],style:{head:["cyan"]}});e.forEach(o=>{t.push([d.green(o.name),d.gray(o.path)])}),console.log(t.toString())});Be.command("rm <name>").description("\u5220\u9664\u5DF2\u5B89\u88C5\u7684 skill").action(e=>{St(e)});L.action(async e=>{if(e.mode){at();return}if(e.listModes){ct();return}for(go(()=>{he.cursorTo(process.stdout,0,0),he.clearScreenDown(process.stdout),be(W,oe),console.log("");let o=h.get("defaultMode");console.log(d.gray("?")+" "+d.gray("Select action")+" "+d.cyan("(Use arrow keys)")),Oe(o).forEach((s,i)=>{let a=i===0?d.cyan("\u276F"):" ";console.log(a+" "+s.name)})});;){console.clear(),be(W,oe),console.log("");let o=h.get("defaultMode"),n=h.get("registries"),s=h.get("current"),i=n[s],{action:a}=await U.prompt([{type:"list",name:"action",message:d.gray("Select action"),choices:Oe(o),prefix:d.gray("?")}]);if(a==="start"){if(q&&(q.abort(),q=null),pe(),i||(ne.error("No environment configuration found."),process.exit(1)),o&&O[o])await ue(o,i);else{let c={...process.env};i.ANTHROPIC_BASE_URL&&(c.ANTHROPIC_BASE_URL=i.ANTHROPIC_BASE_URL),i.ANTHROPIC_API_KEY&&(c.ANTHROPIC_API_KEY=j(i.ANTHROPIC_API_KEY||"")),i.ANTHROPIC_MODEL&&(c.ANTHROPIC_MODEL=i.ANTHROPIC_MODEL),i.ANTHROPIC_SMALL_FAST_MODEL&&(c.ANTHROPIC_SMALL_FAST_MODEL=i.ANTHROPIC_SMALL_FAST_MODEL),console.log(tt()),Et("claude",[],{env:c,stdio:"inherit",shell:!0}).on("exit",m=>{process.exit(m??0)})}return}else if(a==="usage")console.clear(),W?console.log(ot(W)):ne.warning("No usage data available"),await U.prompt([{type:"input",name:"continue",message:d.gray("Press Enter to continue..."),prefix:""}]);else if(a==="switch"){let{selected:c}=await U.prompt([{type:"list",name:"selected",message:d.gray("Select environment"),choices:et(n,s),prefix:d.gray("?"),default:s}]);h.set("current",c)}else if(a==="perm"){let{permMode:c}=await U.prompt([{type:"list",name:"permMode",message:d.gray("Select permission mode"),choices:Me(null,!1),prefix:d.gray("?")}]);if(c!=="back"){await ue(c,i);return}}else if(a==="setDefault"){let c=h.get("defaultMode"),{selectedMode:l}=await U.prompt([{type:"list",name:"selectedMode",message:d.gray("Set default permission mode"),choices:Me(c,!0),prefix:d.gray("?")}]);l==="clear"?(h.set("defaultMode",null),ne.success("Default mode cleared"),await new Promise(m=>setTimeout(m,800))):l!=="back"&&(h.set("defaultMode",l),ne.success(`Default mode set: ${O[l].name}`),await new Promise(m=>setTimeout(m,800)))}else process.exit(0)}});L.parse(process.argv);
19
+ `),se(`git pull --depth=1 origin ${o}`,{cwd:c,stdio:"pipe"});let d=s?H.join(c,s):c;if(!E.existsSync(d))throw new Error(`Path "${s}" not found in repository`);return ht(d,a),console.log(L.green(`Successfully installed skill "${n}"`)),!0}catch(p){let d=p instanceof Error?p.message:String(p);return console.error(L.red(`Failed to download skill: ${d}`)),!1}finally{E.existsSync(c)&&E.rmSync(c,{recursive:!0})}}function ht(e,t){E.mkdirSync(t,{recursive:!0});let o=E.readdirSync(e,{withFileTypes:!0});for(let s of o){if(s.name===".git")continue;let n=H.join(e,s.name),i=H.join(t,s.name);s.isDirectory()?ht(n,i):E.copyFileSync(n,i)}}function he(e){let t=ut.find(n=>n.name===e);if(t){if(t.install.type==="preset")return fe("anthropics","skills","main",`skills/${t.install.name}`,t.name);if(t.install.type==="github"){let n=pt(t.install.url);return n?fe(n.owner,n.repo,n.branch,n.path,t.name):(console.error(L.red(`Invalid GitHub URL in preset: ${t.install.url}`)),!1)}else if(t.install.type==="plugin")return console.error(L.yellow(`Plugin installation not yet supported for "${t.name}"`)),console.log(L.gray(`Marketplace: ${t.install.marketplace}`)),console.log(L.gray(`Package: ${t.install.package}`)),!1}let o=pt(e);if(!o)return console.error(L.red("Invalid GitHub URL or preset name")),console.log(L.gray("Examples:")),console.log(L.gray(" ccem skill add frontend-design")),console.log(L.gray(" ccem skill add https://github.com/owner/repo")),console.log(L.gray(" ccem skill add https://github.com/owner/repo/tree/main/path")),!1;let s;return o.path?s=H.basename(o.path):s=o.repo,fe(o.owner,o.repo,o.branch,o.path,s)}function yt(){let e=Ne();return E.existsSync(e)?E.readdirSync(e,{withFileTypes:!0}).filter(o=>o.isDirectory()&&!o.name.startsWith(".")).map(o=>({name:o.name,path:H.join(e,o.name)})):[]}function _t(e){let t=Ne(),o=H.join(t,e);return E.existsSync(o)?(E.rmSync(o,{recursive:!0}),console.log(L.green(`Removed skill "${e}"`)),!0):(console.error(L.red(`Skill "${e}" not found`)),!1)}function no(e,t){try{return console.log(L.cyan(`Adding marketplace: ${e}...`)),se(`claude plugin marketplace add ${e}`,{stdio:"inherit"}),console.log(L.cyan(`Installing package: ${t}...`)),se(`claude plugin install ${t}`,{stdio:"inherit"}),console.log(L.green(`Successfully installed ${t}`)),!0}catch(o){let s=o instanceof Error?o.message:String(o);return console.error(L.red(`Failed to install from marketplace: ${s}`)),!1}}function At(e){switch(console.log(L.cyan(`Installing ${e.name}...`)),e.install.type){case"preset":let t={repo:"anthropics/skills",path:`skills/${e.install.name}`,branch:"main"},[o,s]=t.repo.split("/");return fe(o,s,t.branch,t.path,e.name);case"github":return he(e.install.url);case"plugin":return no(e.install.marketplace,e.install.package)}}import{render as ao}from"ink";import{useState as Pt,useEffect as so}from"react";import{Box as W,Text as X,useInput as ro,useApp as io}from"ink";import{jsx as F,jsxs as ie}from"react/jsx-runtime";function St({onSelect:e,onCancel:t}){let{exit:o}=io(),s=ft(),[n,i]=Pt(0),[a,l]=Pt(0),c=s[n],d=[...gt(c),null],_=d.length-1;return so(()=>{l(0)},[n]),ro((m,g)=>{if(g.tab&&!g.shift){i(h=>(h+1)%s.length);return}if(g.tab&&g.shift){i(h=>(h-1+s.length)%s.length);return}if(g.upArrow){l(h=>Math.max(0,h-1));return}if(g.downArrow){l(h=>Math.min(_,h+1));return}if(g.return){let h=d[a];e(h===null?"custom":h);return}if(g.escape||m==="q"){t(),o();return}}),ie(W,{flexDirection:"column",children:[F(W,{marginBottom:1,children:s.map((m,g)=>{let h=mt[m],y=g===n;return F(W,{marginRight:2,children:ie(X,{bold:y,color:y?"cyan":"gray",inverse:y,children:[" ",h.icon," ",h.label," "]})},m)})}),F(W,{marginBottom:1,children:F(X,{color:"gray",children:"\u2500".repeat(50)})}),F(W,{flexDirection:"column",children:d.map((m,g)=>{let h=g===a,y=h?"\u276F ":" ";return m===null?F(W,{children:ie(X,{color:h?"yellow":"gray",children:[y,"\u8F93\u5165\u81EA\u5B9A\u4E49 GitHub URL"]})},"custom"):F(W,{children:ie(X,{color:h?"cyan":void 0,children:[y,F(X,{bold:h,children:m.name}),ie(X,{color:"gray",children:[" - ",m.description]})]})},m.name)})}),F(W,{marginTop:1,children:F(X,{color:"gray",children:"Tab \u5207\u6362\u5206\u7EC4 | \u2191\u2193 \u9009\u62E9 | Enter \u786E\u8BA4 | Esc \u53D6\u6D88"})})]})}import{jsx as co}from"react/jsx-runtime";async function Rt(){return new Promise(e=>{let t=!1,{unmount:o,waitUntilExit:s}=ao(co(St,{onSelect:n=>{t||(t=!0,o(),e(n==="custom"?{type:"custom"}:{type:"skill",skill:n}))},onCancel:()=>{t||(t=!0,o(),e({type:"cancelled"}))}}));s().then(()=>{t||e({type:"cancelled"})})})}import Et from"crypto";import x from"chalk";import lo from"conf";var Tt=new lo({projectName:"claude-code-env-manager"}),po=(e,t)=>{let o=Et.scryptSync(t,"ccem-salt",32),s=Buffer.from(e,"base64"),n=s.subarray(0,16),i=s.subarray(16).toString("hex"),a=Et.createDecipheriv("aes-256-cbc",o,n),l=a.update(i,"hex","utf8");return l+=a.final("utf8"),l},mo=(e,t)=>{if(!t.has(e))return e;let o=1,s=`${e}-remote`;for(;t.has(s);)o++,s=`${e}-remote-${o}`;return s},Ct=async(e,t)=>{console.log(x.gray("Fetching from remote..."));let o;try{o=await fetch(e)}catch(c){console.error(x.red("Error: Failed to connect to server")),console.error(x.gray(c.message)),process.exit(1)}o.status===401&&(console.error(x.red("Error: Invalid key (HTTP 401)")),process.exit(1)),o.status===429&&(console.error(x.red("Error: Too many requests, please try again later")),process.exit(1)),o.ok||(console.error(x.red(`Error: Server returned HTTP ${o.status}`)),process.exit(1));let s;try{s=await o.json()}catch{console.error(x.red("Error: Invalid response format from server")),process.exit(1)}s.encrypted||(console.error(x.red("Error: Invalid response format from server")),process.exit(1));let n;try{let c=po(s.encrypted,t);n=JSON.parse(c)}catch{console.error(x.red("Error: Decryption failed, check your --secret")),process.exit(1)}(!n.environments||typeof n.environments!="object")&&(console.error(x.red("Error: Invalid response format from server")),process.exit(1));let i=Tt.get("registries"),a=new Set(Object.keys(i)),l=[];for(let[c,p]of Object.entries(n.environments)){let d=mo(c,a),_=d!==c,m={...p};m.ANTHROPIC_API_KEY&&(m.ANTHROPIC_API_KEY=J(m.ANTHROPIC_API_KEY)),i[d]=m,a.add(d),l.push({name:d,originalName:c,renamed:_})}Tt.set("registries",i),console.log(x.green(`
20
+ Loaded ${l.length} environment(s) from remote:`));for(let c of l)c.renamed?console.log(x.yellow(` + ${c.originalName} \u2192 ${c.name} (renamed, local exists)`)):console.log(x.green(` + ${c.name} (new)`));console.log(x.gray(`
21
+ Run 'ccem ls' to see all environments.`))};var ho=fo(import.meta.url),yo=ye.dirname(ho),_o=ye.resolve(yo,"..","package.json"),Ao=JSON.parse(wt.readFileSync(_o,"utf-8")),N=new uo,f=new go({projectName:"claude-code-env-manager",defaults:{registries:{official:{ANTHROPIC_BASE_URL:"https://api.anthropic.com",ANTHROPIC_MODEL:"claude-sonnet-4-5-20250929",ANTHROPIC_SMALL_FAST_MODEL:"claude-haiku-4-5-20251001"}},current:"official",defaultMode:null}}),ce=["yolo","dev","readonly","safe","ci","audit"],Q=null,ae=!0;var Z=null,Po=e=>{let t=Ke();t?(Q=t,ae=!1):e&&Je(e),Z&&Z.abort(),Z=new AbortController;let o=Z.signal;Ye(o).then(s=>{if(o.aborted)return;let n=ae||Q&&s&&Q.lastUpdated!==s.lastUpdated;Q=s,ae=!1,ue(),n&&e&&e()}).catch(s=>{s.message!=="Aborted"&&(ae=!1,ue())})};N.name("ccem").description("Claude Code Environment Manager - \u7BA1\u7406 Claude Code \u73AF\u5883\u53D8\u91CF\u548C\u6743\u9650").version(Ao.version).option("--mode","\u67E5\u770B\u5F53\u524D\u6743\u9650\u6A21\u5F0F").option("--list-modes","\u5217\u51FA\u6240\u6709\u53EF\u7528\u6743\u9650\u6A21\u5F0F");ce.forEach(e=>{let t=w[e];N.command(e).description(`\u4E34\u65F6\u5E94\u7528 ${t.name}\uFF0C\u9000\u51FA\u540E\u8FD8\u539F`).action(async()=>{let o=f.get("registries"),s=f.get("current"),n=o[s];await ge(e,n)})});var Lt=(e,t)=>{if(!process.stdout.isTTY)return;let o=f.get("current"),n=f.get("registries")[o],i=f.get("defaultMode");n&&(console.log(qe(o,{ANTHROPIC_BASE_URL:n.ANTHROPIC_BASE_URL,ANTHROPIC_API_KEY:n.ANTHROPIC_API_KEY?Y(n.ANTHROPIC_API_KEY):void 0,ANTHROPIC_MODEL:n.ANTHROPIC_MODEL,ANTHROPIC_SMALL_FAST_MODEL:n.ANTHROPIC_SMALL_FAST_MODEL},i)),console.log(""),console.log(Ve(e,t)),console.log(Xe()),console.log(""))},So=async e=>{let t=f.get("registries");if(!t[e]){console.error(u.red(`Environment '${e}' not found.`));return}f.set("current",e),process.stdout.isTTY?console.log(u.green(`Switched to environment '${e}'`)):console.error(u.green(`Switched to environment '${e}'`)),Lt(null,!1);let o=t[e],s=[];o.ANTHROPIC_BASE_URL&&s.push(`export ANTHROPIC_BASE_URL="${o.ANTHROPIC_BASE_URL}"`),o.ANTHROPIC_API_KEY&&s.push(`export ANTHROPIC_API_KEY="${Y(o.ANTHROPIC_API_KEY)}"`),o.ANTHROPIC_MODEL&&s.push(`export ANTHROPIC_MODEL="${o.ANTHROPIC_MODEL}"`),o.ANTHROPIC_SMALL_FAST_MODEL&&s.push(`export ANTHROPIC_SMALL_FAST_MODEL="${o.ANTHROPIC_SMALL_FAST_MODEL}"`),process.stdout.isTTY?(console.log(u.yellow(`
22
+ To apply to current shell immediately, run:`)),console.log(u.cyan("eval $(ccem env)")),console.log(u.yellow(`
23
+ Or manually export:`)),s.forEach(n=>console.log(n))):s.forEach(n=>console.log(n))};N.command("ls").description("List all configured environments").action(()=>{let e=f.get("registries"),t=f.get("current"),o=new Ot({head:["Name","Base URL","Model"],style:{head:["cyan"]}});Object.keys(e).forEach(s=>{let n=e[s],i=s===t?u.green("* "):" ";o.push([i+s,n.ANTHROPIC_BASE_URL||"-",n.ANTHROPIC_MODEL||"-"])}),console.log(o.toString())});N.command("use <name>").description("Switch to a specific environment").action(async e=>{await So(e)});N.command("add <name>").description("Add a new environment configuration").action(async e=>{let t=f.get("registries");if(t[e]){console.log(u.red(`Environment '${e}' already exists.`));return}let{usePreset:o}=await k.prompt([{type:"confirm",name:"usePreset",message:"Do you want to use a preset configuration?",default:!0}]),s={};if(o){let{presetName:i}=await k.prompt([{type:"list",name:"presetName",message:"Select a preset:",choices:Object.keys(Re)}]);s=Re[i]}let n=await k.prompt([{type:"input",name:"ANTHROPIC_BASE_URL",message:"Enter ANTHROPIC_BASE_URL:",default:s.ANTHROPIC_BASE_URL||"https://api.anthropic.com"},{type:"password",name:"ANTHROPIC_API_KEY",message:"Enter ANTHROPIC_API_KEY:"},{type:"input",name:"ANTHROPIC_MODEL",message:"Enter ANTHROPIC_MODEL:",default:s.ANTHROPIC_MODEL||"claude-sonnet-4-5-20250929"},{type:"input",name:"ANTHROPIC_SMALL_FAST_MODEL",message:"Enter ANTHROPIC_SMALL_FAST_MODEL:",default:s.ANTHROPIC_SMALL_FAST_MODEL||"claude-haiku-4-5-20251001"}]);n.ANTHROPIC_API_KEY&&(n.ANTHROPIC_API_KEY=J(n.ANTHROPIC_API_KEY)),t[e]=n,f.set("registries",t),console.log(u.green(`Environment '${e}' added successfully.`))});N.command("del <name>").description("Delete an environment configuration").action(e=>{let t=f.get("registries");if(!t[e]){console.log(u.red(`Environment '${e}' not found.`));return}if(e==="official"){console.log(u.red("Cannot delete default 'official' environment."));return}delete t[e],f.set("registries",t),f.get("current")===e&&(f.set("current","official"),console.log(u.yellow("Deleted current environment. Switched back to 'official'."))),console.log(u.green(`Environment '${e}' deleted.`))});N.command("rename <old> <new>").description("Rename an environment configuration").action((e,t)=>{let o=f.get("registries");if(!o[e]){console.log(u.red(`Environment '${e}' not found.`));return}if(o[t]){console.log(u.red(`Environment '${t}' already exists.`));return}if(e==="official"){console.log(u.red("Cannot rename default 'official' environment."));return}o[t]=o[e],delete o[e],f.set("registries",o),f.get("current")===e&&f.set("current",t),console.log(u.green(`Environment '${e}' renamed to '${t}'.`))});N.command("cp <source> <target>").description("Copy an environment configuration").action(async(e,t)=>{let o=f.get("registries");if(!o[e]){console.log(u.red(`Environment '${e}' not found.`));return}if(o[t]){console.log(u.red(`Environment '${t}' already exists.`));return}o[t]={...o[e]},f.set("registries",o),console.log(u.green(`Environment '${e}' copied to '${t}'.`));let{modify:s}=await k.prompt([{type:"confirm",name:"modify",message:"Do you want to modify the configuration?",default:!1}]);if(s){let n=o[t],i=await k.prompt([{type:"input",name:"ANTHROPIC_BASE_URL",message:"ANTHROPIC_BASE_URL:",default:n.ANTHROPIC_BASE_URL},{type:"password",name:"ANTHROPIC_API_KEY",message:"ANTHROPIC_API_KEY (leave empty to keep current):"},{type:"input",name:"ANTHROPIC_MODEL",message:"ANTHROPIC_MODEL:",default:n.ANTHROPIC_MODEL},{type:"input",name:"ANTHROPIC_SMALL_FAST_MODEL",message:"ANTHROPIC_SMALL_FAST_MODEL:",default:n.ANTHROPIC_SMALL_FAST_MODEL}]);i.ANTHROPIC_BASE_URL&&(n.ANTHROPIC_BASE_URL=i.ANTHROPIC_BASE_URL),i.ANTHROPIC_API_KEY&&(n.ANTHROPIC_API_KEY=J(i.ANTHROPIC_API_KEY)),i.ANTHROPIC_MODEL&&(n.ANTHROPIC_MODEL=i.ANTHROPIC_MODEL),i.ANTHROPIC_SMALL_FAST_MODEL&&(n.ANTHROPIC_SMALL_FAST_MODEL=i.ANTHROPIC_SMALL_FAST_MODEL),o[t]=n,f.set("registries",o),console.log(u.green(`Environment '${t}' updated.`))}});N.command("current").description("Show current environment name").action(()=>{let e=f.get("current");console.log(u.green(e))});N.command("env").description("Output environment variables for shell eval").option("--json","Output as JSON").action(e=>{let t=f.get("registries"),o=f.get("current"),s=t[o];if(!s)return;let n={...s};n.ANTHROPIC_API_KEY&&(n.ANTHROPIC_API_KEY=Y(n.ANTHROPIC_API_KEY)),e.json?console.log(JSON.stringify(n,null,2)):(n.ANTHROPIC_BASE_URL&&console.log(`export ANTHROPIC_BASE_URL="${n.ANTHROPIC_BASE_URL}"`),n.ANTHROPIC_API_KEY&&console.log(`export ANTHROPIC_API_KEY="${n.ANTHROPIC_API_KEY}"`),n.ANTHROPIC_MODEL&&console.log(`export ANTHROPIC_MODEL="${n.ANTHROPIC_MODEL}"`),n.ANTHROPIC_SMALL_FAST_MODEL&&console.log(`export ANTHROPIC_SMALL_FAST_MODEL="${n.ANTHROPIC_SMALL_FAST_MODEL}"`))});N.command("run <command...>").description("Run a command with the current environment variables").action(e=>{let t=f.get("registries"),o=f.get("current"),s=t[o];s||(console.error(u.red("No environment configuration found.")),process.exit(1));let n={...process.env};s.ANTHROPIC_BASE_URL&&(n.ANTHROPIC_BASE_URL=s.ANTHROPIC_BASE_URL),s.ANTHROPIC_API_KEY&&(n.ANTHROPIC_API_KEY=Y(s.ANTHROPIC_API_KEY||"")),s.ANTHROPIC_MODEL&&(n.ANTHROPIC_MODEL=s.ANTHROPIC_MODEL),s.ANTHROPIC_SMALL_FAST_MODEL&&(n.ANTHROPIC_SMALL_FAST_MODEL=s.ANTHROPIC_SMALL_FAST_MODEL);let[i,...a]=e;It(i,a,{env:n,stdio:"inherit",shell:!0}).on("exit",c=>{process.exit(c??0)})});var xe=N.command("setup").description("Setup commands for permanent configurations");xe.command("perms").description("\u6C38\u4E45\u914D\u7F6E\u6743\u9650\u6A21\u5F0F").option("--yolo","\u5E94\u7528 YOLO \u6A21\u5F0F\uFF08\u5168\u90E8\u653E\u5F00\uFF09").option("--dev","\u5E94\u7528\u5F00\u53D1\u6A21\u5F0F").option("--readonly","\u5E94\u7528\u53EA\u8BFB\u6A21\u5F0F").option("--safe","\u5E94\u7528\u5B89\u5168\u6A21\u5F0F").option("--ci","\u5E94\u7528 CI/CD \u6A21\u5F0F").option("--audit","\u5E94\u7528\u5BA1\u8BA1\u6A21\u5F0F").option("--reset","\u91CD\u7F6E\u6743\u9650\u914D\u7F6E").action(function(){let e=this.opts();if(e.reset){rt();return}for(let t of ce)if(e[t]){st(t);return}console.log(u.yellow("\u8BF7\u6307\u5B9A\u4E00\u4E2A\u6743\u9650\u6A21\u5F0F\uFF0C\u4F8B\u5982: ccem setup perms --dev")),console.log(u.gray("\u53EF\u7528\u6A21\u5F0F: "+ce.join(", "))),console.log(u.gray("\u91CD\u7F6E\u6743\u9650: ccem setup perms --reset"))});xe.command("default-mode").description("\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F").option("--yolo","YOLO \u6A21\u5F0F").option("--dev","\u5F00\u53D1\u6A21\u5F0F").option("--readonly","\u53EA\u8BFB\u6A21\u5F0F").option("--safe","\u5B89\u5168\u6A21\u5F0F").option("--ci","CI/CD \u6A21\u5F0F").option("--audit","\u5BA1\u8BA1\u6A21\u5F0F").option("--reset","\u6E05\u9664\u9ED8\u8BA4\u6A21\u5F0F").action(function(){let e=this.opts();if(e.reset){f.set("defaultMode",null),console.log(u.green("\u5DF2\u6E05\u9664\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F"));return}for(let o of ce)if(e[o]){f.set("defaultMode",o),console.log(u.green(`\u5DF2\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F: ${w[o].name}`)),console.log(u.gray("\u4E0B\u6B21\u542F\u52A8 ccem \u65F6\u5C06\u9ED8\u8BA4\u4F7F\u7528\u6B64\u6A21\u5F0F"));return}let t=f.get("defaultMode");t&&w[t]?console.log(u.green(`\u5F53\u524D\u9ED8\u8BA4\u6A21\u5F0F: ${w[t].name}`)):console.log(u.yellow("\u672A\u8BBE\u7F6E\u9ED8\u8BA4\u6743\u9650\u6A21\u5F0F")),console.log(u.gray(`
24
+ \u8BBE\u7F6E\u9ED8\u8BA4\u6A21\u5F0F: ccem setup default-mode --dev`)),console.log(u.gray("\u6E05\u9664\u9ED8\u8BA4\u6A21\u5F0F: ccem setup default-mode --reset")),console.log(u.gray("\u53EF\u7528\u6A21\u5F0F: "+ce.join(", ")))});xe.command("init").description("\u521D\u59CB\u5316 Claude Code \u5168\u5C40\u914D\u7F6E\uFF08\u8DF3\u8FC7 onboarding\u3001\u7981\u7528\u9065\u6D4B\u3001\u5B89\u88C5 MCP \u5DE5\u5177\uFF09").action(async()=>{await dt()});var ve=N.command("skill").description("\u7BA1\u7406 Claude Code skills");ve.command("add [url]").description("\u6DFB\u52A0 skill\uFF08\u4ECE\u5B98\u65B9\u9884\u8BBE\u6216 GitHub URL\uFF09").action(async e=>{if(e)he(e);else{let t=await Rt();if(t.type==="cancelled"){console.log(u.yellow("\u5DF2\u53D6\u6D88"));return}if(t.type==="custom"){let{customUrl:o}=await k.prompt([{type:"input",name:"customUrl",message:"\u8F93\u5165 GitHub URL:",validate:s=>s.trim()?!s.includes("github.com")&&!/^[\w-]+\/[\w-]+$/.test(s)?"\u8BF7\u8F93\u5165\u6709\u6548\u7684 GitHub URL \u6216 owner/repo \u683C\u5F0F":!0:"\u8BF7\u8F93\u5165\u6709\u6548\u7684 URL"}]);he(o)}else t.skill&&At(t.skill)}});ve.command("ls").description("\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 skills").action(()=>{let e=yt();if(e.length===0){console.log(u.yellow("\u5F53\u524D\u76EE\u5F55\u6CA1\u6709\u5B89\u88C5\u4EFB\u4F55 skill")),console.log(u.gray("\u4F7F\u7528 ccem skill add \u6DFB\u52A0 skills"));return}let t=new Ot({head:["Name","Path"],style:{head:["cyan"]}});e.forEach(o=>{t.push([u.green(o.name),u.gray(o.path)])}),console.log(t.toString())});ve.command("rm <name>").description("\u5220\u9664\u5DF2\u5B89\u88C5\u7684 skill").action(e=>{_t(e)});N.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(e,t)=>{await Ct(e,t.secret)});N.action(async e=>{if(e.mode){it();return}if(e.listModes){at();return}for(Po();;){console.clear(),Lt(Q,ae),console.log("");let t=f.get("defaultMode"),o=f.get("registries"),s=f.get("current"),n=o[s],{action:i}=await k.prompt([{type:"list",name:"action",message:u.gray("Select action"),choices:Qe(t),prefix:u.gray("?")}]);if(i==="start"){if(Z&&(Z.abort(),Z=null),ue(),n||(v.error("No environment configuration found."),process.exit(1)),t&&w[t])await ge(t,n);else{let a={...process.env};n.ANTHROPIC_BASE_URL&&(a.ANTHROPIC_BASE_URL=n.ANTHROPIC_BASE_URL),n.ANTHROPIC_API_KEY&&(a.ANTHROPIC_API_KEY=Y(n.ANTHROPIC_API_KEY||"")),n.ANTHROPIC_MODEL&&(a.ANTHROPIC_MODEL=n.ANTHROPIC_MODEL),n.ANTHROPIC_SMALL_FAST_MODEL&&(a.ANTHROPIC_SMALL_FAST_MODEL=n.ANTHROPIC_SMALL_FAST_MODEL),console.log(Ze()),It("claude",[],{env:a,stdio:"inherit",shell:!0}).on("exit",c=>{process.exit(c??0)})}return}else if(i==="usage")console.clear(),Q?console.log(et(Q)):v.warning("No usage data available"),await k.prompt([{type:"input",name:"continue",message:u.gray("Press Enter to continue..."),prefix:""}]);else if(i==="switch"){let a=await tt(o,s);if(a.action==="select")f.set("current",a.name);else if(a.action==="edit"){let l=o[a.name];console.log(u.yellow(`
25
+ Editing environment '${a.name}'`));let c=await k.prompt([{type:"input",name:"ANTHROPIC_BASE_URL",message:"ANTHROPIC_BASE_URL:",default:l.ANTHROPIC_BASE_URL},{type:"password",name:"ANTHROPIC_API_KEY",message:"ANTHROPIC_API_KEY (leave empty to keep current):"},{type:"input",name:"ANTHROPIC_MODEL",message:"ANTHROPIC_MODEL:",default:l.ANTHROPIC_MODEL},{type:"input",name:"ANTHROPIC_SMALL_FAST_MODEL",message:"ANTHROPIC_SMALL_FAST_MODEL:",default:l.ANTHROPIC_SMALL_FAST_MODEL}]);c.ANTHROPIC_BASE_URL&&(l.ANTHROPIC_BASE_URL=c.ANTHROPIC_BASE_URL),c.ANTHROPIC_API_KEY&&(l.ANTHROPIC_API_KEY=J(c.ANTHROPIC_API_KEY)),c.ANTHROPIC_MODEL&&(l.ANTHROPIC_MODEL=c.ANTHROPIC_MODEL),c.ANTHROPIC_SMALL_FAST_MODEL&&(l.ANTHROPIC_SMALL_FAST_MODEL=c.ANTHROPIC_SMALL_FAST_MODEL),o[a.name]=l,f.set("registries",o),v.success(`Environment '${a.name}' updated.`),await new Promise(p=>setTimeout(p,800))}else if(a.action==="rename")if(a.name==="official")v.error("Cannot rename default 'official' environment."),await new Promise(l=>setTimeout(l,800));else{let{newName:l}=await k.prompt([{type:"input",name:"newName",message:`Rename '${a.name}' to:`,validate:c=>c.trim()?o[c]?`Environment '${c}' already exists`:!0:"Name cannot be empty"}]);o[l]=o[a.name],delete o[a.name],f.set("registries",o),s===a.name&&f.set("current",l),v.success(`Environment '${a.name}' renamed to '${l}'.`),await new Promise(c=>setTimeout(c,800))}else if(a.action==="copy"){let{targetName:l}=await k.prompt([{type:"input",name:"targetName",message:`Copy '${a.name}' to:`,validate:p=>p.trim()?o[p]?`Environment '${p}' already exists`:!0:"Name cannot be empty"}]);o[l]={...o[a.name]},f.set("registries",o),v.success(`Environment '${a.name}' copied to '${l}'.`);let{modify:c}=await k.prompt([{type:"confirm",name:"modify",message:"Do you want to modify the configuration?",default:!1}]);if(c){let p=o[l],d=await k.prompt([{type:"input",name:"ANTHROPIC_BASE_URL",message:"ANTHROPIC_BASE_URL:",default:p.ANTHROPIC_BASE_URL},{type:"password",name:"ANTHROPIC_API_KEY",message:"ANTHROPIC_API_KEY (leave empty to keep current):"},{type:"input",name:"ANTHROPIC_MODEL",message:"ANTHROPIC_MODEL:",default:p.ANTHROPIC_MODEL},{type:"input",name:"ANTHROPIC_SMALL_FAST_MODEL",message:"ANTHROPIC_SMALL_FAST_MODEL:",default:p.ANTHROPIC_SMALL_FAST_MODEL}]);d.ANTHROPIC_BASE_URL&&(p.ANTHROPIC_BASE_URL=d.ANTHROPIC_BASE_URL),d.ANTHROPIC_API_KEY&&(p.ANTHROPIC_API_KEY=J(d.ANTHROPIC_API_KEY)),d.ANTHROPIC_MODEL&&(p.ANTHROPIC_MODEL=d.ANTHROPIC_MODEL),d.ANTHROPIC_SMALL_FAST_MODEL&&(p.ANTHROPIC_SMALL_FAST_MODEL=d.ANTHROPIC_SMALL_FAST_MODEL),o[l]=p,f.set("registries",o),v.success(`Environment '${l}' updated.`)}await new Promise(p=>setTimeout(p,800))}else if(a.action==="delete")if(a.name==="official")v.error("Cannot delete default 'official' environment."),await new Promise(l=>setTimeout(l,800));else{let{confirm:l}=await k.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete '${a.name}'?`,default:!1}]);l&&(delete o[a.name],f.set("registries",o),s===a.name?(f.set("current","official"),v.warning("Deleted current environment. Switched back to 'official'.")):v.success(`Environment '${a.name}' deleted.`)),await new Promise(c=>setTimeout(c,800))}}else if(i==="perm"){let{permMode:a}=await k.prompt([{type:"list",name:"permMode",message:u.gray("Select permission mode"),choices:Le(null,!1),prefix:u.gray("?")}]);if(a!=="back"){await ge(a,n);return}}else if(i==="setDefault"){let a=f.get("defaultMode"),{selectedMode:l}=await k.prompt([{type:"list",name:"selectedMode",message:u.gray("Set default permission mode"),choices:Le(a,!0),prefix:u.gray("?")}]);l==="clear"?(f.set("defaultMode",null),v.success("Default mode cleared"),await new Promise(c=>setTimeout(c,800))):l!=="back"&&(f.set("defaultMode",l),v.success(`Default mode set: ${w[l].name}`),await new Promise(c=>setTimeout(c,800)))}else process.exit(0)}});N.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccem",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "type": "module",
5
5
  "description": "Claude Code Environment Manager",
6
6
  "author": {
@@ -24,6 +24,9 @@
24
24
  "@types/inquirer": "^9.0.7",
25
25
  "@types/node": "^20.11.24",
26
26
  "@types/react": "^19.2.9",
27
+ "asciify-image": "^0.1.10",
28
+ "sharp": "^0.34.5",
29
+ "terminal-image": "^4.2.0",
27
30
  "tsup": "^8.0.2",
28
31
  "typescript": "^5.3.3"
29
32
  },