@wangxiaoerqqq/ccs 2.0.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 (64) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +21 -0
  3. package/README.md +287 -0
  4. package/dist/commands/current.d.ts +2 -0
  5. package/dist/commands/current.d.ts.map +1 -0
  6. package/dist/commands/current.js +29 -0
  7. package/dist/commands/current.js.map +1 -0
  8. package/dist/commands/edit.d.ts +2 -0
  9. package/dist/commands/edit.d.ts.map +1 -0
  10. package/dist/commands/edit.js +21 -0
  11. package/dist/commands/edit.js.map +1 -0
  12. package/dist/commands/init.d.ts +2 -0
  13. package/dist/commands/init.d.ts.map +1 -0
  14. package/dist/commands/init.js +47 -0
  15. package/dist/commands/init.js.map +1 -0
  16. package/dist/commands/list.d.ts +2 -0
  17. package/dist/commands/list.d.ts.map +1 -0
  18. package/dist/commands/list.js +31 -0
  19. package/dist/commands/list.js.map +1 -0
  20. package/dist/commands/models.d.ts +2 -0
  21. package/dist/commands/models.d.ts.map +1 -0
  22. package/dist/commands/models.js +44 -0
  23. package/dist/commands/models.js.map +1 -0
  24. package/dist/commands/set-key.d.ts +2 -0
  25. package/dist/commands/set-key.d.ts.map +1 -0
  26. package/dist/commands/set-key.js +51 -0
  27. package/dist/commands/set-key.js.map +1 -0
  28. package/dist/commands/switch.d.ts +3 -0
  29. package/dist/commands/switch.d.ts.map +1 -0
  30. package/dist/commands/switch.js +83 -0
  31. package/dist/commands/switch.js.map +1 -0
  32. package/dist/config/crypto.d.ts +5 -0
  33. package/dist/config/crypto.d.ts.map +1 -0
  34. package/dist/config/crypto.js +89 -0
  35. package/dist/config/crypto.js.map +1 -0
  36. package/dist/config/manager.d.ts +28 -0
  37. package/dist/config/manager.d.ts.map +1 -0
  38. package/dist/config/manager.js +188 -0
  39. package/dist/config/manager.js.map +1 -0
  40. package/dist/index.d.ts +3 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +99 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/providers/defaults.d.ts +22 -0
  45. package/dist/providers/defaults.d.ts.map +1 -0
  46. package/dist/providers/defaults.js +160 -0
  47. package/dist/providers/defaults.js.map +1 -0
  48. package/dist/providers/registry.d.ts +20 -0
  49. package/dist/providers/registry.d.ts.map +1 -0
  50. package/dist/providers/registry.js +81 -0
  51. package/dist/providers/registry.js.map +1 -0
  52. package/dist/utils/logger.d.ts +13 -0
  53. package/dist/utils/logger.d.ts.map +1 -0
  54. package/dist/utils/logger.js +51 -0
  55. package/dist/utils/logger.js.map +1 -0
  56. package/dist/utils/platform.d.ts +11 -0
  57. package/dist/utils/platform.d.ts.map +1 -0
  58. package/dist/utils/platform.js +50 -0
  59. package/dist/utils/platform.js.map +1 -0
  60. package/dist/utils/reload.d.ts +4 -0
  61. package/dist/utils/reload.d.ts.map +1 -0
  62. package/dist/utils/reload.js +51 -0
  63. package/dist/utils/reload.js.map +1 -0
  64. package/package.json +64 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2024-03-25
9
+
10
+ ### Added
11
+
12
+ - Initial release
13
+ - CLI commands:
14
+ - `ccs init` - Initialize configuration
15
+ - `ccs <provider> [model]` - Switch provider and model
16
+ - `ccs model <model>` - Switch model only
17
+ - `ccs set-key <provider> [api-key]` - Set API key
18
+ - `ccs list` / `ccs ls` - List all providers and models
19
+ - `ccs current` - Show current configuration
20
+ - `ccs models [provider]` - List models for a provider
21
+ - `ccs edit` - Open config file for editing
22
+ - `ccs reload` - Send reload signal to Claude Code
23
+ - Supported providers:
24
+ - 阿里百炼 (Aliyun) - Qwen series models
25
+ - 智谱 GLM (Zhipu) - GLM-4/5 series models
26
+ - 火山引擎豆包 (Volc) - Doubao series models
27
+ - DeepSeek - Chat and Reasoner models
28
+ - Moonshot Kimi - Kimi series models
29
+ - MiniMax - abab series models
30
+ - Anthropic - Claude series models
31
+ - Features:
32
+ - Encrypted API key storage using AES-256-CBC
33
+ - Cross-platform support (macOS, Linux, Windows)
34
+ - Hot reload via SIGHUP signal
35
+ - Dynamic provider commands (e.g., `ccs aliyun`, `ccs zhipu`)
36
+ - Machine-specific encryption keys
37
+
38
+ ### Security
39
+
40
+ - API keys are encrypted with AES-256-CBC before storage
41
+ - Encryption keys are derived from machine-specific identifiers
42
+ - Secrets file has restricted permissions (0600)
43
+
44
+ ---
45
+
46
+ ## Future Plans
47
+
48
+ - [ ] Auto-detect rate limit status
49
+ - [ ] Support for more providers via community contributions
50
+ - [ ] API for programmatic access
51
+ - [ ] VS Code extension integration
52
+ - [ ] Configuration sync across devices
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 genzhen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,287 @@
1
+ # CCS - Claude Code Switcher
2
+
3
+ 一个极简风格的 CLI 工具,用于在 Claude Code 中即时切换 AI 提供商和模型。
4
+
5
+ ## 功能特点
6
+
7
+ - **快速切换**: 一条命令即可切换提供商和模型
8
+ - **多提供商支持**: 支持阿里百炼、智谱 GLM、DeepSeek、火山引擎、MiniMax、美团 LongCat 等主流 AI 平台
9
+ - **灵活配置**: 支持提供商和模型两级 env 配置,模型代号与真实模型名分离
10
+ - **安全存储**: API 密钥加密存储在本地
11
+ - **热加载**: 自动发送重载信号,无需重启 Claude Code
12
+ - **跨平台**: 支持 macOS、Linux、Windows
13
+
14
+ ## 安装
15
+ ZFfbvTh3Yu
16
+ ```bash
17
+ # npm
18
+ npm install -g ccs
19
+
20
+ # 或使用 pnpm
21
+ pnpm add -g ccs
22
+
23
+ # 或使用 yarn
24
+ yarn global add ccs
25
+ ```
26
+
27
+ ## 快速开始
28
+
29
+ ### 1. 初始化配置
30
+
31
+ ```bash
32
+ ccs init
33
+ ```
34
+
35
+ 这将引导你设置各个平台的 API 密钥。
36
+
37
+ ### 2. 切换提供商
38
+
39
+ ```bash
40
+ # 切换到阿里百炼(使用默认模型)
41
+ ccs aliyun
42
+
43
+ # 切换到智谱 GLM 并指定模型
44
+ ccs zhipu glm-5.1
45
+
46
+ # 切换到 DeepSeek
47
+ ccs deepseek
48
+
49
+ # 仅切换模型(保持当前提供商)
50
+ ccs model qwen-max
51
+ ```
52
+
53
+ ### 3. 查看状态
54
+
55
+ ```bash
56
+ # 列出所有提供商和模型
57
+ ccs list
58
+
59
+ # 查看当前配置
60
+ ccs current
61
+
62
+ # 查看特定提供商的模型列表
63
+ ccs models zhipu
64
+ ```
65
+
66
+ ## 支持的提供商
67
+
68
+ | 提供商 | 命令 | 默认模型 |
69
+ |--------|------|----------|
70
+ | 阿里百炼 | `ccs aliyun` | qwen-turbo |
71
+ | 智谱 GLM | `ccs zhipu` | glm-5.1 |
72
+ | 火山引擎豆包 | `ccs volc` | doubao-pro-32k |
73
+ | DeepSeek | `ccs deepseek` | v4pro |
74
+ | Moonshot Kimi | `ccs moonshot` | kimi-k2.6 |
75
+ | MiniMax | `ccs minimax` | m3 |
76
+ | Anthropic 官方 | `ccs anthropic` | claude-sonnet-4-6 |
77
+ | 美团官方 | `ccs longcat` | longcat-2-preview |
78
+
79
+ ## 命令参考
80
+
81
+ ### `ccs init`
82
+
83
+ 初始化 CCS 配置,交互式引导设置 API 密钥。
84
+
85
+ ### `ccs <provider> [model]`
86
+
87
+ 切换到指定提供商和模型。
88
+
89
+ ```bash
90
+ ccs aliyun # 切换到阿里百炼(默认模型)
91
+ ccs zhipu glm-5.1 # 切换到智谱 GLM 的 glm-5.1 模型
92
+ ccs minimax m3 # 切换到 MiniMax-M3
93
+ ```
94
+
95
+ ### `ccs model <model>`
96
+
97
+ 仅切换模型,保持当前提供商不变。
98
+
99
+ ```bash
100
+ ccs model qwen-max # 切换到 qwen-max 模型
101
+ ```
102
+
103
+ ### `ccs set-key <provider> [api-key]`
104
+
105
+ 设置提供商的 API 密钥。
106
+
107
+ ```bash
108
+ ccs set-key zhipu # 交互式输入
109
+ ccs set-key aliyun sk-xxx # 直接设置
110
+ ```
111
+
112
+ ### `ccs list` / `ccs ls`
113
+
114
+ 列出所有可用的提供商和模型,含模型代号和真实 API 模型名。
115
+
116
+ ### `ccs current`
117
+
118
+ 显示当前的提供商和模型配置。当代号与真实模型名不同时,额外显示 Real model 行。
119
+
120
+ ### `ccs models [provider]`
121
+
122
+ 列出提供商的所有可用模型。
123
+
124
+ ```bash
125
+ ccs models # 当前提供商的模型
126
+ ccs models zhipu # 智谱 GLM 的所有模型
127
+ ```
128
+
129
+ ### `ccs edit`
130
+
131
+ 打开提供商配置文件进行编辑。
132
+
133
+ ### `ccs reload`
134
+
135
+ 发送重载信号到 Claude Code 进程。
136
+
137
+ ## 配置文件
138
+
139
+ 配置文件存储位置:
140
+
141
+ | 平台 | 配置目录 |
142
+ |------|----------|
143
+ | macOS/Linux | `~/.config/ccs/` |
144
+ | Windows | `%APPDATA%\ccs\` |
145
+
146
+ ### 文件说明
147
+
148
+ - `providers.json` - 提供商和模型配置
149
+ - `current.json` - 当前选择的提供商和模型
150
+ - `secrets.enc` - 加密存储的 API 密钥
151
+ - `.key` - 本地加密密钥(请勿分享)
152
+
153
+ ### providers.json 结构
154
+
155
+ 每个提供商可以配置两级 `env`:
156
+
157
+ - **provider 级 env**:所有模型共享的基础环境变量(如 `ANTHROPIC_BASE_URL`)
158
+ - **model 级 env**:覆盖或追加模型专属的环境变量(如 `ENDPOINT_ID`)
159
+
160
+ 模型的 `model` 字段为真实 API 模型名,而 key 为用户使用的友好代号:
161
+
162
+ ```json
163
+ {
164
+ "moonshot": {
165
+ "name": "Moonshot Kimi",
166
+ "env": {
167
+ "ANTHROPIC_BASE_URL": "https://api.moonshot.cn/v1"
168
+ },
169
+ "models": {
170
+ "kimi-8k": {
171
+ "name": "Kimi 8K",
172
+ "model": "moonshot-v1-8k",
173
+ "default": true
174
+ }
175
+ }
176
+ }
177
+ }
178
+ ```
179
+
180
+ 上例中用户使用 `ccs moonshot kimi-8k`,实际写入 `ANTHROPIC_MODEL` 的值为 `moonshot-v1-8k`。
181
+
182
+ 模型也可配置 `env` 字段覆盖 provider 级的同名变量(`undefined` 值会被跳过不覆盖):
183
+
184
+ ```json
185
+ {
186
+ "deepseek": {
187
+ "name": "DeepSeek",
188
+ "env": {
189
+ "ANTHROPIC_BASE_URL": "https://api.deepseek.com/anthropic",
190
+ "ANTHROPIC_DEFAULT_OPUS_MODEL": "deepseek-v4-pro"
191
+ },
192
+ "models": {
193
+ "deepseek-v4-flash": {
194
+ "name": "DeepSeek V4 Flash",
195
+ "model": "deepseek-v4-flash",
196
+ "env": {
197
+ "ANTHROPIC_DEFAULT_OPUS_MODEL": "deepseek-v4-flash"
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }
203
+ ```
204
+
205
+ 切换 `deepseek-v4-flash` 时,`ANTHROPIC_DEFAULT_OPUS_MODEL` 会被覆盖为 `deepseek-v4-flash`。
206
+
207
+ ### 添加自定义提供商
208
+
209
+ 编辑 `~/.config/ccs/providers.json`:
210
+
211
+ ```json
212
+ {
213
+ "my-provider": {
214
+ "name": "我的提供商",
215
+ "env": {
216
+ "ANTHROPIC_BASE_URL": "https://api.example.com/anthropic"
217
+ },
218
+ "models": {
219
+ "model-1": {
220
+ "name": "Model 1",
221
+ "model": "real-model-name-1",
222
+ "default": true
223
+ },
224
+ "model-2": {
225
+ "name": "Model 2",
226
+ "model": "real-model-name-2",
227
+ "env": {
228
+ "CUSTOM_VAR": "model-specific-value"
229
+ }
230
+ }
231
+ }
232
+ }
233
+ }
234
+ ```
235
+
236
+ ## 热加载机制
237
+
238
+ CCS 支持自动重载 Claude Code 配置:
239
+
240
+ 1. 切换提供商后,自动检测 Claude Code 进程
241
+ 2. 发送 SIGHUP 信号触发重载
242
+ 3. 如使用 Shell wrapper,会话自动继续
243
+
244
+ ### Shell Wrapper(推荐)
245
+
246
+ 创建 `~/bin/claude-wrapper.sh`:
247
+
248
+ ```bash
249
+ #!/bin/bash
250
+ while claude "$@"; [ $? -eq 129 ]; do
251
+ set -- -c
252
+ done
253
+ ```
254
+
255
+ 然后在终端中使用此脚本启动 Claude Code。
256
+
257
+ ## 开发
258
+
259
+ ```bash
260
+ # 克隆仓库
261
+ git clone https://gitee.com/xiaoerlangqqq/ccs.git
262
+ cd ccs
263
+
264
+ # 安装依赖
265
+ npm install
266
+
267
+ # 构建
268
+ npm run build
269
+
270
+ # 测试
271
+ npm test
272
+
273
+ # 开发模式(监听文件变化)
274
+ npm run dev
275
+ ```
276
+
277
+ ## 许可证
278
+
279
+ MIT License
280
+
281
+ ## 贡献
282
+
283
+ 欢迎提交 Issue 和 Pull Request!
284
+
285
+ ## 相关项目
286
+
287
+ - [Claude Code](https://github.com/anthropics/claude-code) - Anthropic 官方 CLI 工具
@@ -0,0 +1,2 @@
1
+ export declare function currentCommand(): void;
2
+ //# sourceMappingURL=current.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current.d.ts","sourceRoot":"","sources":["../../src/commands/current.ts"],"names":[],"mappings":"AAOA,wBAAgB,cAAc,IAAI,IAAI,CA4BrC"}
@@ -0,0 +1,29 @@
1
+ // Current command - show current selection
2
+ import { loadCurrent, initConfig } from '../config/manager.js';
3
+ import { getProviderDisplayName, getModelDisplayName, getRealModelName, hasApiKey } from '../providers/registry.js';
4
+ import { logger } from '../utils/logger.js';
5
+ import chalk from 'chalk';
6
+ export function currentCommand() {
7
+ initConfig();
8
+ const current = loadCurrent();
9
+ logger.title('Current Configuration');
10
+ if (!current.provider) {
11
+ logger.warning('No provider selected');
12
+ logger.info('Run "ccs <provider>" to select a provider');
13
+ return;
14
+ }
15
+ const providerName = getProviderDisplayName(current.provider);
16
+ const modelName = getModelDisplayName(current.provider, current.model);
17
+ const realModel = getRealModelName(current.provider, current.model);
18
+ const keyStatus = hasApiKey(current.provider)
19
+ ? chalk.green('✓ API key set')
20
+ : chalk.red('✗ No API key');
21
+ logger.item('Provider', `${providerName} ${chalk.dim(`(${current.provider})`)}`);
22
+ logger.item('Model', `${modelName} ${chalk.dim(`(${current.model})`)}`);
23
+ if (realModel && realModel !== current.model) {
24
+ logger.item('Real model', realModel);
25
+ }
26
+ logger.item('Status', keyStatus);
27
+ console.log();
28
+ }
29
+ //# sourceMappingURL=current.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current.js","sourceRoot":"","sources":["../../src/commands/current.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAE3C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACpH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,cAAc;IAC5B,UAAU,EAAE,CAAC;IAEb,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAE9B,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAEtC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACtB,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QACzD,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,sBAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACpE,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC3C,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC;QAC9B,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAE9B,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,YAAY,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC;IACjF,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,SAAS,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;IACxE,IAAI,SAAS,IAAI,SAAS,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAEjC,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function editCommand(): Promise<void>;
2
+ //# sourceMappingURL=edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/commands/edit.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBjD"}
@@ -0,0 +1,21 @@
1
+ // Edit command - open config file for editing
2
+ import { getProvidersPath, getConfigDir } from '../utils/platform.js';
3
+ import { logger } from '../utils/logger.js';
4
+ import open from 'open';
5
+ export async function editCommand() {
6
+ const providersPath = getProvidersPath();
7
+ const configDir = getConfigDir();
8
+ logger.info(`Config directory: ${configDir}`);
9
+ logger.info(`Providers file: ${providersPath}`);
10
+ // Try to open with default editor
11
+ try {
12
+ await open(providersPath);
13
+ logger.success('Opened providers.json in default editor');
14
+ }
15
+ catch {
16
+ // Fallback: show instructions
17
+ logger.info('Could not open editor automatically');
18
+ logger.info(`Please edit: ${providersPath}`);
19
+ }
20
+ }
21
+ //# sourceMappingURL=edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/commands/edit.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAG9C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IAEjC,MAAM,CAAC,IAAI,CAAC,qBAAqB,SAAS,EAAE,CAAC,CAAC;IAC9C,MAAM,CAAC,IAAI,CAAC,mBAAmB,aAAa,EAAE,CAAC,CAAC;IAEhD,kCAAkC;IAClC,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,aAAa,CAAC,CAAC;QAC1B,MAAM,CAAC,OAAO,CAAC,yCAAyC,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;QAC9B,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,gBAAgB,aAAa,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function initCommand(): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA+CjD"}
@@ -0,0 +1,47 @@
1
+ // Init command - initialize CCS configuration
2
+ import inquirer from 'inquirer';
3
+ import { initConfig, setApiKey, loadSecrets } from '../config/manager.js';
4
+ import { getAvailableProviders } from '../providers/registry.js';
5
+ import { logger } from '../utils/logger.js';
6
+ export async function initCommand() {
7
+ logger.title('CCS Configuration');
8
+ // Initialize config files
9
+ initConfig();
10
+ const providers = getAvailableProviders();
11
+ const secrets = loadSecrets();
12
+ logger.info('Configuration directory created');
13
+ logger.info('Please enter API keys for the providers you want to use:');
14
+ logger.separator();
15
+ for (const [providerId, config] of Object.entries(providers)) {
16
+ const existingKey = secrets[providerId];
17
+ const { setKey } = await inquirer.prompt([
18
+ {
19
+ type: 'confirm',
20
+ name: 'setKey',
21
+ message: `Set API key for ${config.name}?`,
22
+ default: !existingKey
23
+ }
24
+ ]);
25
+ if (setKey) {
26
+ const { apiKey } = await inquirer.prompt([
27
+ {
28
+ type: 'password',
29
+ name: 'apiKey',
30
+ message: `Enter API key for ${config.name}:`,
31
+ mask: '*',
32
+ validate: (input) => input.length > 0 || 'API key cannot be empty'
33
+ }
34
+ ]);
35
+ setApiKey(providerId, apiKey);
36
+ logger.success(`API key saved for ${config.name}`);
37
+ }
38
+ else if (existingKey) {
39
+ logger.info(`Using existing API key for ${config.name}`);
40
+ }
41
+ }
42
+ logger.separator();
43
+ logger.success('CCS initialization complete!');
44
+ logger.info('Run "ccs list" to see available providers');
45
+ logger.info('Run "ccs <provider>" to switch to a provider');
46
+ }
47
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAE9C,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAa,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAElC,0BAA0B;IAC1B,UAAU,EAAE,CAAC;IAEb,MAAM,SAAS,GAAG,qBAAqB,EAAE,CAAC;IAC1C,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAE9B,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;IACxE,MAAM,CAAC,SAAS,EAAE,CAAC;IAEnB,KAAK,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7D,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QAExC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YACvC;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,mBAAmB,MAAM,CAAC,IAAI,GAAG;gBAC1C,OAAO,EAAE,CAAC,WAAW;aACtB;SACF,CAAC,CAAC;QAEH,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;gBACvC;oBACE,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,qBAAqB,MAAM,CAAC,IAAI,GAAG;oBAC5C,IAAI,EAAE,GAAG;oBACT,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,yBAAyB;iBAC3E;aACF,CAAC,CAAC;YAEH,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,OAAO,CAAC,qBAAqB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;aAAM,IAAI,WAAW,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC,8BAA8B,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,MAAM,CAAC,SAAS,EAAE,CAAC;IACnB,MAAM,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IACzD,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function listCommand(): void;
2
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAOA,wBAAgB,WAAW,IAAI,IAAI,CA+BlC"}
@@ -0,0 +1,31 @@
1
+ // List command - list all providers and models
2
+ import { loadProviders, loadCurrent, initConfig } from '../config/manager.js';
3
+ import { hasApiKey } from '../providers/registry.js';
4
+ import { logger } from '../utils/logger.js';
5
+ import chalk from 'chalk';
6
+ export function listCommand() {
7
+ initConfig();
8
+ const providers = loadProviders();
9
+ const current = loadCurrent();
10
+ logger.title('Available Providers');
11
+ for (const [providerId, config] of Object.entries(providers)) {
12
+ const hasKey = hasApiKey(providerId);
13
+ const isCurrent = providerId === current.provider;
14
+ // Provider header
15
+ const status = hasKey ? chalk.green('✓') : chalk.dim('○');
16
+ const currentMarker = isCurrent ? chalk.yellow(' (current)') : '';
17
+ console.log(`${status} ${chalk.bold(config.name)} ${chalk.dim(`(${providerId})`)}${currentMarker}`);
18
+ // Models
19
+ for (const [modelId, modelConfig] of Object.entries(config.models)) {
20
+ const defaultMarker = modelConfig.default ? chalk.dim(' [default]') : '';
21
+ const currentModelMarker = isCurrent && modelId === current.model ? chalk.yellow(' ←') : '';
22
+ const realModel = modelConfig.model !== modelId ? chalk.dim(` → ${modelConfig.model}`) : '';
23
+ console.log(` ${chalk.dim('•')} ${modelConfig.name} ${chalk.dim(`(${modelId})`)}${realModel}${defaultMarker}${currentModelMarker}`);
24
+ }
25
+ console.log();
26
+ }
27
+ logger.separator();
28
+ logger.info('Usage: ccs <provider> [model]');
29
+ logger.info('Example: ccs zhipu glm-5-turbo');
30
+ }
31
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,WAAW;IACzB,UAAU,EAAE,CAAC;IAEb,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAE9B,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAEpC,KAAK,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7D,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC;QAElD,kBAAkB;QAClB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1D,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,GAAG,aAAa,EAAE,CAAC,CAAC;QAEpG,SAAS;QACT,KAAK,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,MAAM,kBAAkB,GAAG,SAAS,IAAI,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5F,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5F,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,GAAG,SAAS,GAAG,aAAa,GAAG,kBAAkB,EAAE,CAAC,CAAC;QACzI,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,SAAS,EAAE,CAAC;IACnB,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;IAC7C,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function modelsCommand(provider?: string): void;
2
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/commands/models.ts"],"names":[],"mappings":"AAeA,wBAAgB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CA6CrD"}
@@ -0,0 +1,44 @@
1
+ // Models command - list models for a provider
2
+ import { initConfig, loadProviders } from '../config/manager.js';
3
+ import { providerExists, getProviderModels, getProviderDisplayName, getModelDisplayName, getProviderDefaultModel, getRealModelName } from '../providers/registry.js';
4
+ import { logger } from '../utils/logger.js';
5
+ import chalk from 'chalk';
6
+ export function modelsCommand(provider) {
7
+ initConfig();
8
+ if (!provider) {
9
+ // Show models for all providers
10
+ const allProviders = loadProviders();
11
+ logger.title('Available Models');
12
+ for (const [providerId, config] of Object.entries(allProviders)) {
13
+ console.log(chalk.bold(config.name));
14
+ for (const [modelId, modelConfig] of Object.entries(config.models)) {
15
+ const defaultMarker = modelConfig.default ? chalk.dim(' [default]') : '';
16
+ const realModel = modelConfig.model !== modelId ? chalk.dim(` → ${modelConfig.model}`) : '';
17
+ console.log(` ${modelConfig.name} ${chalk.dim(`(${modelId})`)}${realModel}${defaultMarker}`);
18
+ }
19
+ console.log();
20
+ }
21
+ return;
22
+ }
23
+ // Validate provider
24
+ if (!providerExists(provider)) {
25
+ logger.error(`Unknown provider: ${provider}`);
26
+ logger.info('Run "ccs list" to see available providers');
27
+ process.exit(1);
28
+ }
29
+ const models = getProviderModels(provider);
30
+ const defaultModel = getProviderDefaultModel(provider);
31
+ const providerName = getProviderDisplayName(provider);
32
+ logger.title(`Models for ${providerName}`);
33
+ for (const modelId of models) {
34
+ const modelName = getModelDisplayName(provider, modelId);
35
+ const realModel = getRealModelName(provider, modelId);
36
+ const isDefault = modelId === defaultModel;
37
+ const defaultMarker = isDefault ? chalk.green(' [default]') : '';
38
+ const realMarker = realModel && realModel !== modelId ? chalk.dim(` → ${realModel}`) : '';
39
+ console.log(` ${modelName} ${chalk.dim(`(${modelId})`)}${realMarker}${defaultMarker}`);
40
+ }
41
+ console.log();
42
+ logger.info(`Usage: ccs ${provider} <model>`);
43
+ }
44
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/commands/models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function setKeyCommand(providerArg?: string, apiKeyArg?: string): Promise<void>;
2
+ //# sourceMappingURL=set-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set-key.d.ts","sourceRoot":"","sources":["../../src/commands/set-key.ts"],"names":[],"mappings":"AAOA,wBAAsB,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD3F"}
@@ -0,0 +1,51 @@
1
+ // Set-key command - set API key for a provider
2
+ import inquirer from 'inquirer';
3
+ import { setApiKey, initConfig, loadProviders } from '../config/manager.js';
4
+ import { providerExists, getProviderDisplayName } from '../providers/registry.js';
5
+ import { logger } from '../utils/logger.js';
6
+ export async function setKeyCommand(providerArg, apiKeyArg) {
7
+ initConfig();
8
+ let provider = providerArg;
9
+ // If provider not specified, show interactive prompt
10
+ if (!provider) {
11
+ const providers = loadProviders();
12
+ const { selectedProvider } = await inquirer.prompt([
13
+ {
14
+ type: 'list',
15
+ name: 'selectedProvider',
16
+ message: 'Select provider to set API key:',
17
+ choices: Object.keys(providers).map(p => ({
18
+ name: `${providers[p].name}`,
19
+ value: p
20
+ }))
21
+ }
22
+ ]);
23
+ provider = selectedProvider;
24
+ }
25
+ // Validate provider
26
+ if (!provider || !providerExists(provider)) {
27
+ logger.error(`Unknown provider: ${provider || 'undefined'}`);
28
+ logger.info('Run "ccs list" to see available providers');
29
+ process.exit(1);
30
+ }
31
+ let apiKey = apiKeyArg;
32
+ // If API key not provided, prompt for it
33
+ if (!apiKey) {
34
+ const response = await inquirer.prompt([
35
+ {
36
+ type: 'password',
37
+ name: 'apiKey',
38
+ message: `Enter API key for ${getProviderDisplayName(provider)}:`,
39
+ mask: '*',
40
+ validate: (input) => input.length > 0 || 'API key cannot be empty'
41
+ }
42
+ ]);
43
+ apiKey = response.apiKey;
44
+ }
45
+ // Save the API key (apiKey is guaranteed to be defined here)
46
+ if (apiKey) {
47
+ setApiKey(provider, apiKey);
48
+ logger.success(`API key saved for ${getProviderDisplayName(provider)}`);
49
+ }
50
+ }
51
+ //# sourceMappingURL=set-key.js.map