@sifwenf/cc-proxy 0.1.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.
- package/README.ja.md +337 -0
- package/README.md +284 -0
- package/README.zh-CN.md +337 -0
- package/TASKS.md +102 -0
- package/config.example.json +29 -0
- package/package.json +21 -0
- package/scripts/ccp +126 -0
- package/scripts/status.js +32 -0
- package/src/config.ts +86 -0
- package/src/format-converter.ts +168 -0
- package/src/logger.ts +213 -0
- package/src/proxy.ts +83 -0
- package/src/scripts/init.ts +161 -0
- package/src/server.ts +338 -0
- package/src/types.ts +78 -0
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# cc-proxy
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md) | [日本語](README.ja.md)
|
|
4
|
+
|
|
5
|
+
轻量级 LLM 代理服务器,用于 Claude Code - 将 Anthropic API 请求路由到任意 LLM 提供商。
|
|
6
|
+
|
|
7
|
+
## 功能特性
|
|
8
|
+
|
|
9
|
+
- **模型路由**:将 Claude 模型(haiku、sonnet、opus)映射到任意提供商的模型
|
|
10
|
+
- **多提供商**:同时支持多个 LLM 提供商
|
|
11
|
+
- **格式转换**:自动在 Anthropic 和 OpenAI 格式之间转换
|
|
12
|
+
- **热重载**:配置更改自动应用,无需重启
|
|
13
|
+
- **性能优化**:异步批量日志记录,最小化开销
|
|
14
|
+
- **自动启动**:Shell 集成,静默后台启动
|
|
15
|
+
|
|
16
|
+
## 安装方式
|
|
17
|
+
|
|
18
|
+
### 方式 1:Bun 全局安装(推荐)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# 从 npm 安装
|
|
22
|
+
bun install -g cc-proxy
|
|
23
|
+
|
|
24
|
+
# 或从本地源码安装
|
|
25
|
+
cd cc-proxy
|
|
26
|
+
bun link
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
这将全局安装 `ccp` 命令:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
ccp start # 启动代理服务器
|
|
33
|
+
ccp status # 检查状态
|
|
34
|
+
ccp config # 在编辑器中打开配置文件
|
|
35
|
+
ccp logs # 查看日志
|
|
36
|
+
ccp help # 显示所有命令
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
添加到 `~/.zshrc` 或 `~/.bashrc` 以实现 shell 打开时自动启动:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
eval "$(ccp activate)"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 方式 2:手动安装
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 克隆仓库
|
|
49
|
+
git clone https://github.com/your-username/cc-proxy.git
|
|
50
|
+
cd cc-proxy
|
|
51
|
+
|
|
52
|
+
# 安装依赖
|
|
53
|
+
bun install
|
|
54
|
+
|
|
55
|
+
# 初始化配置
|
|
56
|
+
bun run init
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 快速开始
|
|
60
|
+
|
|
61
|
+
### 1. 初始化配置
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
bun run init
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
这将创建:
|
|
68
|
+
- `~/.claude-code-proxy/` 目录结构
|
|
69
|
+
- 默认配置文件
|
|
70
|
+
- 日志目录
|
|
71
|
+
|
|
72
|
+
### 2. 配置提供商
|
|
73
|
+
|
|
74
|
+
编辑配置文件:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
~/.claude-code-proxy/config.json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3. 启动服务器
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# 使用 ccp 命令(如果已全局安装)
|
|
84
|
+
ccp start
|
|
85
|
+
|
|
86
|
+
# 或使用 bun
|
|
87
|
+
bun start
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## 配置参考
|
|
92
|
+
|
|
93
|
+
### 完整配置结构
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"server": {
|
|
98
|
+
"port": 3457,
|
|
99
|
+
"host": "127.0.0.1"
|
|
100
|
+
},
|
|
101
|
+
"logging": {
|
|
102
|
+
"enabled": true,
|
|
103
|
+
"level": "verbose",
|
|
104
|
+
"dir": "~/.claude-code-proxy/logs"
|
|
105
|
+
},
|
|
106
|
+
"providers": [
|
|
107
|
+
{
|
|
108
|
+
"name": "zp",
|
|
109
|
+
"baseUrl": "https://api.z.ai/api/anthropic/v1/messages",
|
|
110
|
+
"apiKey": "your-api-key",
|
|
111
|
+
"format": "anthropic"
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"router": {
|
|
115
|
+
"haiku": "zp,glm-4.7",
|
|
116
|
+
"sonnet": "zp,glm-4.7",
|
|
117
|
+
"opus": "zp,glm-4.7",
|
|
118
|
+
"image": "zp,glm-4.7"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 参数说明
|
|
124
|
+
|
|
125
|
+
#### `server`
|
|
126
|
+
|
|
127
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
128
|
+
|------|------|---------|------|
|
|
129
|
+
| `port` | number | `3457` | 代理服务器端口号 |
|
|
130
|
+
| `host` | string | `"127.0.0.1"` | 绑定的主机地址 |
|
|
131
|
+
|
|
132
|
+
#### `logging`
|
|
133
|
+
|
|
134
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
135
|
+
|------|------|---------|------|
|
|
136
|
+
| `enabled` | boolean | `true` | 启用/禁用日志 |
|
|
137
|
+
| `level` | string | `"verbose"` | 日志级别:`"basic"`、`"standard"` 或 `"verbose"` |
|
|
138
|
+
| `dir` | string | `"~/.claude-code-proxy/logs"` | 日志文件存储目录 |
|
|
139
|
+
|
|
140
|
+
#### `providers`
|
|
141
|
+
|
|
142
|
+
提供商配置数组。每个提供商对象:
|
|
143
|
+
|
|
144
|
+
| 参数 | 类型 | 必需 | 说明 |
|
|
145
|
+
|------|------|--------|------|
|
|
146
|
+
| `name` | string | ✅ 是 | 提供商唯一标识符(用于路由) |
|
|
147
|
+
| `baseUrl` | string | ✅ 是 | API 端点 URL |
|
|
148
|
+
| `apiKey` | string | ✅ 是 | API 认证密钥 |
|
|
149
|
+
| `format` | string | 否 | API 格式:`"anthropic"`、`"openai"` 或省略(透传模式) |
|
|
150
|
+
|
|
151
|
+
**格式类型:**
|
|
152
|
+
- `"anthropic"`:使用 Anthropic 兼容头(x-api-key, anthropic-version)
|
|
153
|
+
- `"openai"`:转换为 OpenAI 格式(Authorization: Bearer)
|
|
154
|
+
- 省略:透传模式(仅替换 API 密钥,转发原始头)
|
|
155
|
+
|
|
156
|
+
#### `router`
|
|
157
|
+
|
|
158
|
+
将 Claude 模型名映射到提供商端点。
|
|
159
|
+
|
|
160
|
+
格式:`"<claude-model>": "<provider-name>,<actual-model-name>"`
|
|
161
|
+
|
|
162
|
+
| 参数 | 说明 | 示例 |
|
|
163
|
+
|------|------|------|
|
|
164
|
+
| `haiku` | 快速/经济模型路由 | `"zp,glm-4.7"` |
|
|
165
|
+
| `sonnet` | 均衡性能模型路由 | `"zp,glm-4.7"` |
|
|
166
|
+
| `opus` | 高性能模型路由 | `"openrouter,anthropic/claude-opus-4.5"` |
|
|
167
|
+
| `image` | 图像生成模型路由 | `"zp,glm-4.7"` |
|
|
168
|
+
|
|
169
|
+
### 路由语法
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
"router": {
|
|
173
|
+
"haiku": "provider-name,model-name"
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**组成部分:**
|
|
178
|
+
- **提供商名称**:必须匹配提供商的 `name` 字段
|
|
179
|
+
- **模型名称**:向提供商请求的实际模型
|
|
180
|
+
|
|
181
|
+
**示例:**
|
|
182
|
+
- `"zp,glm-4.7"`:使用 `zp` 提供商,请求 `glm-4.7` 模型
|
|
183
|
+
- `"openrouter,anthropic/claude-opus-4.5"`:使用 OpenRouter,请求 Claude Opus 4.5
|
|
184
|
+
|
|
185
|
+
### 环境变量覆盖
|
|
186
|
+
|
|
187
|
+
代理可以从 `ANTHROPIC_BASE_URL` 检测端口:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
export ANTHROPIC_BASE_URL="http://127.0.0.1:3456"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
这将覆盖 `server.port` 配置并使用端口 `3456`。
|
|
194
|
+
|
|
195
|
+
服务器将:
|
|
196
|
+
- 从 `~/.claude-code-proxy/` 加载配置
|
|
197
|
+
- 在 `~/.claude-code-proxy/logs/` 存储日志
|
|
198
|
+
- 监听配置文件更改并热重载
|
|
199
|
+
|
|
200
|
+
## 配置示例
|
|
201
|
+
|
|
202
|
+
### 智谱 AI(Anthropic 格式)
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"name": "zp",
|
|
207
|
+
"baseUrl": "https://api.z.ai/api/anthropic/v1/messages",
|
|
208
|
+
"apiKey": "your-key",
|
|
209
|
+
"format": "anthropic"
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### OpenRouter(OpenAI 格式)
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"name": "openrouter",
|
|
218
|
+
"baseUrl": "https://openrouter.ai/api/v1/chat/completions",
|
|
219
|
+
"apiKey": "sk-or-...",
|
|
220
|
+
"format": "openai"
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 多提供商配置
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"providers": [
|
|
229
|
+
{
|
|
230
|
+
"name": "zp",
|
|
231
|
+
"baseUrl": "https://api.z.ai/api/anthropic/v1/messages",
|
|
232
|
+
"apiKey": "your-zpai-key"
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"name": "openrouter",
|
|
236
|
+
"baseUrl": "https://openrouter.ai/api/v1/chat/completions",
|
|
237
|
+
"apiKey": "sk-or-..."
|
|
238
|
+
}
|
|
239
|
+
],
|
|
240
|
+
"router": {
|
|
241
|
+
"haiku": "zp,glm-4.7",
|
|
242
|
+
"sonnet": "zp,glm-4.7",
|
|
243
|
+
"opus": "openrouter,anthropic/claude-opus-4.5"
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## CLI 命令
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
ccp activate # 静默自动启动(用于 shell 配置)
|
|
252
|
+
ccp start # 强制重启并启动
|
|
253
|
+
ccp stop # 停止代理服务器
|
|
254
|
+
ccp restart # 重启代理服务器
|
|
255
|
+
ccp status # 显示运行状态
|
|
256
|
+
ccp config # 在编辑器中打开配置文件(zed > vscode > vi)
|
|
257
|
+
ccp logs # 实时查看服务器日志
|
|
258
|
+
ccp help # 显示帮助信息
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Claude Code 集成
|
|
262
|
+
|
|
263
|
+
设置环境变量以在 Claude Code 中使用 cc-proxy:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
export ANTHROPIC_BASE_URL="http://127.0.0.1:3456"
|
|
267
|
+
export ANTHROPIC_API_KEY="routing-key"
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
如需在 shell 打开时自动启动,添加到 `~/.zshrc`:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
eval "$(ccp activate)"
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## 日志管理
|
|
277
|
+
|
|
278
|
+
### 查看最新日志
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# 服务器日志
|
|
282
|
+
ccp logs
|
|
283
|
+
|
|
284
|
+
# 请求日志(JSONL 格式)
|
|
285
|
+
tail -f ~/.claude-code-proxy/logs/requests.jsonl | jq '.'
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 过滤日志
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# 按提供商过滤
|
|
292
|
+
cat ~/.claude-code-proxy/logs/requests.jsonl | jq 'select(.provider == "zp")'
|
|
293
|
+
|
|
294
|
+
# 按类型过滤
|
|
295
|
+
cat ~/.claude-code-proxy/logs/requests.jsonl | jq 'select(.type == "forward")'
|
|
296
|
+
cat ~/.claude-code-proxy/logs/requests.jsonl | jq 'select(.type == "response")'
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## 性能
|
|
300
|
+
|
|
301
|
+
代理针对高并发场景进行了优化:
|
|
302
|
+
|
|
303
|
+
- **异步批量日志**:100ms 刷新间隔,最小化 I/O 阻塞
|
|
304
|
+
- **无 per-chunk 日志**:流式响应绕过 per-chunk 开销
|
|
305
|
+
- **高效内存使用**:约 100KB 缓冲区限制
|
|
306
|
+
- **优雅关闭**:退出前刷新日志
|
|
307
|
+
|
|
308
|
+
可处理来自 agent-swarm 场景的 100+ 并发请求。
|
|
309
|
+
|
|
310
|
+
## 故障排除
|
|
311
|
+
|
|
312
|
+
### 服务器无法启动
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
# 检查是否已运行
|
|
316
|
+
ccp status
|
|
317
|
+
|
|
318
|
+
# 查看日志
|
|
319
|
+
ccp logs
|
|
320
|
+
|
|
321
|
+
# 尝试强制重启
|
|
322
|
+
ccp restart
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### 配置未加载
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# 验证配置文件存在
|
|
329
|
+
cat ~/.claude-code-proxy/config.json
|
|
330
|
+
|
|
331
|
+
# 重新初始化
|
|
332
|
+
bun run init
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## 许可证
|
|
336
|
+
|
|
337
|
+
MIT
|
package/TASKS.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# CC-Proxy 遗留任务
|
|
2
|
+
|
|
3
|
+
## 功能完善
|
|
4
|
+
|
|
5
|
+
### 1. Image 路由功能
|
|
6
|
+
**优先级:** 中
|
|
7
|
+
|
|
8
|
+
**描述:** 当请求用于图像识别时,使用 `router.image` 配置的provider和模型。
|
|
9
|
+
|
|
10
|
+
**实现方案:** 参考liteLLM,检测请求内容是否包含图像(`content` 类型为 `image`),如果是则使用 `image` 路由配置。
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
// 当前配置
|
|
14
|
+
"router": {
|
|
15
|
+
"image": "zp,glm-4.7" // 图像识别请求路由到此
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
### 2. WebSearch 路由功能
|
|
22
|
+
**优先级:** 中
|
|
23
|
+
|
|
24
|
+
**描述:** 当Claude Code调用web search tool时,使用 `router.webSearch` 配置的provider和模型。
|
|
25
|
+
|
|
26
|
+
**实现方案:** 检测请求中的 `tools` 字段,判断是否包含web search相关的tool(如 `web_search`、`browser` 等),如果是则使用 `webSearch` 路由配置。
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
// 当前配置
|
|
30
|
+
"router": {
|
|
31
|
+
"webSearch": "op,google/gemini-2.5-flash" // web search请求路由到此
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
### 3. OpenAI格式Provider支持
|
|
38
|
+
**优先级:** 低
|
|
39
|
+
|
|
40
|
+
**描述:** 当前代码只支持Anthropic格式的provider。需要支持OpenAI兼容格式的provider(如OpenRouter)。
|
|
41
|
+
|
|
42
|
+
**实现方案:**
|
|
43
|
+
1. 在 `ProviderConfig` 中添加 `format` 字段:`"anthropic"` 或 `"openai"`
|
|
44
|
+
2. 根据provider格式选择不同的请求/响应处理逻辑
|
|
45
|
+
3. OpenAI格式需要:
|
|
46
|
+
- 请求头: `Authorization: Bearer ${apiKey}`
|
|
47
|
+
- 请求体转换:Anthropic → OpenAI格式
|
|
48
|
+
- 响应体转换:OpenAI → Anthropic格式
|
|
49
|
+
- 流式响应转换
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
// 预期配置
|
|
53
|
+
"providers": [
|
|
54
|
+
{
|
|
55
|
+
"name": "openrouter",
|
|
56
|
+
"baseUrl": "https://openrouter.ai/api/v1/chat/completions",
|
|
57
|
+
"apiKey": "...",
|
|
58
|
+
"format": "openai" // 新增字段
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "zp",
|
|
62
|
+
"baseUrl": "https://api.z.ai/api/anthropic/v1/messages",
|
|
63
|
+
"apiKey": "...",
|
|
64
|
+
"format": "anthropic"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 优化改进
|
|
72
|
+
|
|
73
|
+
### 4. 配置热重载
|
|
74
|
+
**优先级:** 低
|
|
75
|
+
|
|
76
|
+
**描述:** 修改config.json后无需重启服务,自动加载新配置。
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### 5. 健康检查增强
|
|
81
|
+
**优先级:** 低
|
|
82
|
+
|
|
83
|
+
**描述:** `/status` 端点增加provider连通性检测。
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### 6. 日志查询工具
|
|
88
|
+
**优先级:** 低
|
|
89
|
+
|
|
90
|
+
**描述:** 提供 `ccp logs --filter` 等命令,方便查询特定请求的日志。
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 文档
|
|
95
|
+
|
|
96
|
+
### 7. README更新
|
|
97
|
+
**优先级:** 中
|
|
98
|
+
|
|
99
|
+
**描述:** 更新README.md文档,包含:
|
|
100
|
+
- 新的配置格式说明
|
|
101
|
+
- 路由配置示例
|
|
102
|
+
- CCP命令使用说明
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"server": {
|
|
3
|
+
"port": 3457,
|
|
4
|
+
"host": "127.0.0.1"
|
|
5
|
+
},
|
|
6
|
+
"logging": {
|
|
7
|
+
"enabled": true,
|
|
8
|
+
"level": "verbose",
|
|
9
|
+
"dir": "./logs"
|
|
10
|
+
},
|
|
11
|
+
"providers": [
|
|
12
|
+
{
|
|
13
|
+
"name": "openrouter",
|
|
14
|
+
"baseUrl": "https://openrouter.ai/api/v1/chat/completions",
|
|
15
|
+
"apiKey": ""
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "zp",
|
|
19
|
+
"baseUrl": "https://api.z.ai/api/anthropic/v1/messages",
|
|
20
|
+
"apiKey": "your-zpai-key-here"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"router": {
|
|
24
|
+
"haiku": "zp,glm-4.7",
|
|
25
|
+
"sonnet": "zp,glm-4.7",
|
|
26
|
+
"opus": "zp,glm-4.7",
|
|
27
|
+
"image": "zp,glm-4.7"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sifwenf/cc-proxy",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight LLM proxy server for Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ccp": "./scripts/ccp"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "bun run src/server.ts",
|
|
11
|
+
"dev": "bun run --watch src/server.ts",
|
|
12
|
+
"init": "bun run src/scripts/init.ts"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"chokidar": "^5.0.0",
|
|
16
|
+
"hono": "^4.0.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/bun": "^1.0.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/scripts/ccp
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# cc-proxy manager script (bun global install wrapper)
|
|
3
|
+
|
|
4
|
+
# Resolve symlink to get real script path
|
|
5
|
+
SCRIPT_SOURCE="${BASH_SOURCE[0]}"
|
|
6
|
+
while [ -h "$SCRIPT_SOURCE" ]; do
|
|
7
|
+
SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_SOURCE")" && pwd)"
|
|
8
|
+
SCRIPT_SOURCE="$(readlink "$SCRIPT_SOURCE")"
|
|
9
|
+
[[ $SCRIPT_SOURCE != /* ]] && SCRIPT_SOURCE="$SCRIPT_DIR/$SCRIPT_SOURCE"
|
|
10
|
+
done
|
|
11
|
+
SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_SOURCE")" && pwd)"
|
|
12
|
+
CCP_DIR="$SCRIPT_DIR"
|
|
13
|
+
|
|
14
|
+
# Check if we're in the scripts directory
|
|
15
|
+
if [ "$(basename "$CCP_DIR")" = "scripts" ]; then
|
|
16
|
+
CCP_DIR="$(dirname "$CCP_DIR")"
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
CCP_DATA="$HOME/.claude-code-proxy"
|
|
20
|
+
CCP_LOG="$CCP_DATA/logs/server.log"
|
|
21
|
+
CCP_PID="$CCP_DATA/cc-proxy.pid"
|
|
22
|
+
|
|
23
|
+
activate() {
|
|
24
|
+
if pgrep -f "bun.*server.ts" > /dev/null 2>&1; then return; fi
|
|
25
|
+
mkdir -p "$CCP_DATA/logs" 2>/dev/null
|
|
26
|
+
(cd "$CCP_DIR" && nohup bun run src/server.ts > "$CCP_LOG" 2>&1 &)
|
|
27
|
+
echo $! > "$CCP_PID"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
stop() {
|
|
31
|
+
[ -f "$CCP_PID" ] && kill $(cat "$CCP_PID") 2>/dev/null
|
|
32
|
+
rm -f "$CCP_PID"
|
|
33
|
+
pkill -f "bun.*server.ts" 2>/dev/null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
status() {
|
|
37
|
+
if pgrep -f "bun.*server.ts" > /dev/null 2>&1; then
|
|
38
|
+
echo "✅ cc-proxy is running"
|
|
39
|
+
echo ""
|
|
40
|
+
|
|
41
|
+
# Try common ports for status endpoint
|
|
42
|
+
STATUS_JSON=""
|
|
43
|
+
for PORT in 3456 3457; do
|
|
44
|
+
STATUS_JSON=$(curl -s "http://127.0.0.1:$PORT/status" 2>/dev/null)
|
|
45
|
+
# Validate JSON before accepting (check for "server" key)
|
|
46
|
+
if [ -n "$STATUS_JSON" ] && [ "$STATUS_JSON" != "" ]; then
|
|
47
|
+
if echo "$STATUS_JSON" | grep -q '"server"'; then
|
|
48
|
+
break
|
|
49
|
+
fi
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
if [ -n "$STATUS_JSON" ]; then
|
|
54
|
+
# Use status.js script from fixed location
|
|
55
|
+
TEMP_JSON=$(mktemp)
|
|
56
|
+
# Use heredoc to write JSON (handles special characters)
|
|
57
|
+
cat > "$TEMP_JSON" << EOF
|
|
58
|
+
$STATUS_JSON
|
|
59
|
+
EOF
|
|
60
|
+
bun run "$CCP_DATA/status.js" "$TEMP_JSON"
|
|
61
|
+
rm -f "$TEMP_JSON"
|
|
62
|
+
else
|
|
63
|
+
echo "⚠️ Status endpoint unavailable"
|
|
64
|
+
fi
|
|
65
|
+
else
|
|
66
|
+
echo "❌ cc-proxy is not running"
|
|
67
|
+
fi
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
logs() { tail -f "$CCP_LOG" 2>/dev/null || echo "No logs"; }
|
|
71
|
+
|
|
72
|
+
config() {
|
|
73
|
+
CCP_CONFIG="$CCP_DATA/config.json"
|
|
74
|
+
if [ ! -f "$CCP_CONFIG" ]; then
|
|
75
|
+
echo "❌ Config not found: $CCP_CONFIG"
|
|
76
|
+
echo "Run 'bun run init' first to create config"
|
|
77
|
+
exit 1
|
|
78
|
+
fi
|
|
79
|
+
# Try editors in order: zed > vscode > vi
|
|
80
|
+
if command -v zed >/dev/null 2>&1; then
|
|
81
|
+
zed "$CCP_CONFIG"
|
|
82
|
+
elif command -v code >/dev/null 2>&1; then
|
|
83
|
+
code "$CCP_CONFIG"
|
|
84
|
+
else
|
|
85
|
+
vi "$CCP_CONFIG"
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
help() {
|
|
90
|
+
cat << 'HELP'
|
|
91
|
+
cc-proxy - Claude Code LLM Proxy Manager
|
|
92
|
+
|
|
93
|
+
USAGE: ccp <command>
|
|
94
|
+
|
|
95
|
+
COMMANDS:
|
|
96
|
+
activate Silent auto-start (for .zshrc)
|
|
97
|
+
start Force restart and start
|
|
98
|
+
stop Stop server
|
|
99
|
+
restart Restart server
|
|
100
|
+
status Show status
|
|
101
|
+
logs Tail logs
|
|
102
|
+
config Open config file in editor
|
|
103
|
+
help Show this help
|
|
104
|
+
|
|
105
|
+
CONFIG AUTO-RELOAD:
|
|
106
|
+
Edit ~/.claude-code-proxy/config.json to automatically reload configuration
|
|
107
|
+
|
|
108
|
+
GLOBAL INSTALL:
|
|
109
|
+
bun install -g cc-proxy # From npm
|
|
110
|
+
bun link # From local source
|
|
111
|
+
|
|
112
|
+
CONFIG: ~/.claude-code-proxy/config.json
|
|
113
|
+
HELP
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
case "$1" in
|
|
117
|
+
activate) activate ;;
|
|
118
|
+
start) stop; sleep 1; activate; echo "✅ started" ;;
|
|
119
|
+
stop) stop; echo "🛑 stopped" ;;
|
|
120
|
+
restart) stop; sleep 1; activate; echo "🔄 restarted" ;;
|
|
121
|
+
status) status ;;
|
|
122
|
+
logs) logs ;;
|
|
123
|
+
config) config ;;
|
|
124
|
+
help|--help|-h) help ;;
|
|
125
|
+
*) echo "❌ Unknown: $1"; help; exit 1 ;;
|
|
126
|
+
esac
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
|
|
4
|
+
async function main() {
|
|
5
|
+
const chunks = [];
|
|
6
|
+
for await (const chunk of Bun.stdin.stream()) {
|
|
7
|
+
chunks.push(chunk);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const data = JSON.parse(Buffer.concat(chunks).toString());
|
|
11
|
+
|
|
12
|
+
console.log('📊 Model Routing:');
|
|
13
|
+
console.log('');
|
|
14
|
+
|
|
15
|
+
const models = ['haiku', 'sonnet', 'opus', 'image'];
|
|
16
|
+
for (const key of models) {
|
|
17
|
+
if (data.router[key]) {
|
|
18
|
+
console.log(` ${key.toUpperCase()} → ${data.router[key]}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log('📡 Providers:');
|
|
24
|
+
for (const p of data.providers) {
|
|
25
|
+
console.log(` • ${p.name} - ${p.baseUrl}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log('');
|
|
29
|
+
console.log(`🔗 Endpoint: http://${data.server.host}:${data.server.port}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
main().catch(console.error);
|