@chenpu17/cc-gw 0.2.1 → 0.2.2

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.md CHANGED
@@ -13,7 +13,7 @@ cc-gw 是一个面向 Claude Code 与同类客户端的本地多模型网关,
13
13
 
14
14
  | 模块 | 说明 |
15
15
  | ---- | ---- |
16
- | `@cc-gw/server` | Fastify 服务,实现协议转换、模型路由、Provider 适配与日志存储 |
16
+ | `@cc-gw/server` | Fastify 服务,实现协议转换、模型路由、Provider 适配与日志存储(支持 Anthropic 原生 payload/headers 透传与缓存统计) |
17
17
  | `@cc-gw/web` | React + Vite Web UI,包含仪表盘、日志面板、模型管理、系统设置 |
18
18
  | `@cc-gw/cli` | CLI 守护工具,封装 start/stop/restart/status 并托管 PID/日志 |
19
19
 
@@ -28,6 +28,8 @@ cc-gw start --daemon --port 4100
28
28
 
29
29
  首启会在 `~/.cc-gw/config.json` 生成配置模板,推荐直接通过 Web UI (`http://127.0.0.1:4100/ui`) 完成所有后续配置与调整。`cc-gw status`、`cc-gw stop`、`cc-gw restart` 可用于日常运维。
30
30
 
31
+ > ⚠️ **Linux 安装提示**:如果未命中 sqlite3 的预编译二进制,需要系统具备 `build-essential`、`python3`、`python3-gyp` 等编译依赖。可执行 `sudo apt install build-essential python3 python3-gyp` 后,再运行 `npm install -g @chenpu17/cc-gw --unsafe-perm --build-from-source`。
32
+
31
33
  ### 从源码构建(开发者)
32
34
 
33
35
  前置:Node.js 18.18+(推荐 20 LTS)、pnpm 8+
@@ -89,7 +91,9 @@ pnpm --filter @cc-gw/cli exec tsx index.ts start --daemon --port 4100
89
91
  "claude-opus-4-1-20250805": "anthropic:claude-3-5-sonnet-latest"
90
92
  },
91
93
  "logRetentionDays": 30,
92
- "storePayloads": true
94
+ "storePayloads": true,
95
+ "logLevel": "info",
96
+ "requestLogging": true
93
97
  }
94
98
  ```
95
99
 
@@ -99,8 +103,16 @@ pnpm --filter @cc-gw/cli exec tsx index.ts start --daemon --port 4100
99
103
  - 模型标识使用 `providerId:modelId` 形式供路由引用。
100
104
  - `modelRoutes`:将 Claude 发起的模型名映射到上游模型;未命中时使用 `defaults`。
101
105
  - `storePayloads`:是否在 SQLite 中压缩保存原始请求/响应(Brotli),关闭后仅保留元信息。
106
+ - `logLevel`:控制 Fastify/Pino 控制台日志级别(`fatal`/`error`/`warn`/`info`/`debug`/`trace`)。
107
+ - `requestLogging`:是否输出每个 HTTP 请求的访问日志,关闭后终端更加安静。
102
108
  - 推荐通过 Web UI 的“模型管理 / 系统设置”在线编辑并热加载,无需手工修改文件。
103
109
 
110
+ #### Anthropic Provider 额外说明
111
+
112
+ - 当 Provider `type` 设置为 `anthropic` 时,网关会保留 Claude Code 发来的完整 payload,并将其原样转发到 `<baseUrl>/v1/messages`,无需转换工具调用或 metadata 字段。
113
+ - 所有自定义 Header(如 `x-stainless-*`、`anthropic-beta`、`anthropic-dangerous-direct-browser-access`)会自动透传到下游,确保 Claude Code 的诊断与调试能力不受影响。
114
+ - usage 统计会解析 `cache_read_input_tokens` / `cache_creation_input_tokens`,从而在日志与 Web UI 的 Token 指标中显示缓存命中或写入量;Moonshot / Anthropic 若未返回上述字段,则 `cached` 会继续显示为空。
115
+
104
116
  ### 环境变量
105
117
 
106
118
  | 变量 | 说明 |
@@ -116,7 +128,7 @@ pnpm --filter @cc-gw/cli exec tsx index.ts start --daemon --port 4100
116
128
  - **Dashboard**:展示请求量、Token 使用、缓存命中、各模型 TTFT(Time To First Token)/TPOT(Total Processing Time)、SQLite 数据库占用。
117
129
  - **请求日志**:多条件筛选(时间、Provider、模型、状态),查看压缩日志详情,支持分页导出与清理。
118
130
  - **模型管理**:维护 Provider 列表、预置模型、路由策略;一键测试连通性(发送诊断 PROMPT)。
119
- - **系统设置**:端口、日志保留策略、是否存储请求 payload、日志清理工具。
131
+ - **系统设置**:端口、日志保留策略、是否存储请求 payload、日志级别与访问日志开关、日志清理工具。
120
132
 
121
133
  UI 支持中英文、深色/浅色主题以及移动端响应式布局,提供键盘可达性(Skip Link、焦点管理)。
122
134
 
@@ -134,7 +146,7 @@ pnpm --filter @cc-gw/cli exec tsx index.ts status
134
146
 
135
147
  ## 数据与日志
136
148
 
137
- - 数据库:`~/.cc-gw/data/gateway.db`(`better-sqlite3`)。
149
+ - 数据库:`~/.cc-gw/data/gateway.db`(`sqlite3`)。
138
150
  - `request_logs`:请求摘要、路由结果、耗时、TTFT/TPOT。
139
151
  - `request_payloads`:压缩的请求/响应正文(Brotli)。
140
152
  - `daily_metrics`:按日聚合的调用次数与 Token 统计。
@@ -171,6 +183,8 @@ cc-gw start --daemon --port 4100
171
183
 
172
184
  The first launch writes `~/.cc-gw/config.json`. Manage everything through the Web UI at `http://127.0.0.1:4100/ui`. Use `cc-gw status`, `cc-gw stop`, and `cc-gw restart` to control the daemon.
173
185
 
186
+ > ⚠️ **Linux build note**: `sqlite3` may fall back to building from source. Install toolchain packages such as `build-essential`, `python3`, `python3-gyp`, then rerun `npm install -g @chenpu17/cc-gw --unsafe-perm --build-from-source` if needed.
187
+
174
188
  ### From Source (contributors)
175
189
 
176
190
  ```bash
@@ -190,14 +204,17 @@ claude "help me review this file"
190
204
  ### Configuration Snapshot
191
205
 
192
206
  - Providers include `type`, `baseUrl`, `apiKey`, and `models` descriptions.
207
+ - When `type` is `anthropic`, cc-gw forwards the original Claude payload and all headers to `<baseUrl>/v1/messages`, so tool calls/metadata remain intact.
193
208
  - Model routes use `providerId:modelId` syntax to remap Claude requests.
194
209
  - `storePayloads` toggles compressed body retention; disable to keep only metadata.
210
+ - `logLevel` adjusts Fastify/Pino verbosity (`fatal` → `trace`).
211
+ - `requestLogging` controls whether per-request access logs are emitted to the console.
195
212
  - Web UI allows editing without restarting; CLI restart will pick up bundle changes after rebuilds.
196
213
 
197
214
  ### Observability & Storage
198
215
 
199
216
  - SQLite file under `~/.cc-gw/data/gateway.db` tracks logs and aggregated metrics.
200
- - Dashboard surfaces per-model TTFT/TPOT, cache hits, and DB size.
217
+ - Dashboard surfaces per-model TTFT/TPOT, cache hits(including Anthropic `cache_read_input_tokens` / `cache_creation_input_tokens`), and DB size.
201
218
  - Logs can be filtered/exported/cleaned directly from the UI.
202
219
 
203
220
  ### CLI Reference
package/package.json CHANGED
@@ -1,23 +1,8 @@
1
1
  {
2
2
  "name": "@chenpu17/cc-gw",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "private": false,
5
5
  "type": "module",
6
- "scripts": {
7
- "dev": "pnpm --filter server dev",
8
- "build": "pnpm run build:server && pnpm run build:web",
9
- "build:server": "pnpm --filter @cc-gw/server build",
10
- "build:cli": "pnpm --filter @cc-gw/cli build",
11
- "build:web": "pnpm --filter @cc-gw/web build",
12
- "build:all": "pnpm run build:server && pnpm run build:cli && pnpm run build:web",
13
- "release:bundle": "pnpm run build:all && node scripts/build-release.mjs",
14
- "prepack": "pnpm run build:all",
15
- "lint": "pnpm exec eslint .",
16
- "format": "pnpm exec prettier --check .",
17
- "format:write": "pnpm exec prettier --write .",
18
- "typecheck": "pnpm -r exec tsc --noEmit",
19
- "test": "pnpm exec vitest run"
20
- },
21
6
  "bin": {
22
7
  "cc-gw": "src/cli/dist/index.js"
23
8
  },
@@ -28,15 +13,6 @@
28
13
  "README.md",
29
14
  "LICENSE"
30
15
  ],
31
- "pnpm": {
32
- "peerDependencyRules": {
33
- "ignoreMissing": [
34
- "react",
35
- "react-dom"
36
- ]
37
- }
38
- },
39
- "packageManager": "pnpm@9.0.0",
40
16
  "engines": {
41
17
  "node": ">=18.18.0"
42
18
  },
@@ -55,7 +31,7 @@
55
31
  "dependencies": {
56
32
  "@fastify/cors": "^9.0.1",
57
33
  "@fastify/static": "^7.0.4",
58
- "better-sqlite3": "^9.0.0",
34
+ "sqlite3": "^5.1.7",
59
35
  "commander": "^12.0.0",
60
36
  "colorette": "^2.0.20",
61
37
  "fastify": "^4.26.2",
@@ -71,6 +47,21 @@
71
47
  "prettier": "^3.2.5",
72
48
  "typescript": "^5.4.3",
73
49
  "typescript-eslint": "^7.5.0",
74
- "vitest": "^1.6.0"
50
+ "vitest": "^1.6.0",
51
+ "@types/sqlite3": "^3.1.11"
52
+ },
53
+ "scripts": {
54
+ "dev": "pnpm --filter server dev",
55
+ "build": "pnpm run build:server && pnpm run build:web",
56
+ "build:server": "pnpm --filter @cc-gw/server build",
57
+ "build:cli": "pnpm --filter @cc-gw/cli build",
58
+ "build:web": "pnpm --filter @cc-gw/web build",
59
+ "build:all": "pnpm run build:server && pnpm run build:cli && pnpm run build:web",
60
+ "release:bundle": "pnpm run build:all && node scripts/build-release.mjs",
61
+ "lint": "pnpm exec eslint .",
62
+ "format": "pnpm exec prettier --check .",
63
+ "format:write": "pnpm exec prettier --write .",
64
+ "typecheck": "pnpm -r exec tsc --noEmit",
65
+ "test": "pnpm exec vitest run"
75
66
  }
76
- }
67
+ }
@@ -69,7 +69,9 @@ async function ensureConfigTemplate(port) {
69
69
  },
70
70
  logRetentionDays: 30,
71
71
  modelRoutes: {},
72
- storePayloads: true
72
+ storePayloads: true,
73
+ logLevel: "info",
74
+ requestLogging: true
73
75
  };
74
76
  await fsp.mkdir(path.dirname(CONFIG_FILE), { recursive: true });
75
77
  await fsp.writeFile(CONFIG_FILE, JSON.stringify(template, null, 2), "utf-8");
@@ -156,6 +158,28 @@ async function handleStart(options) {
156
158
  console.log(green(`\u5DF2\u5728 ${CONFIG_FILE} \u751F\u6210\u9ED8\u8BA4\u914D\u7F6E`));
157
159
  console.log(yellow(`\u9996\u6B21\u542F\u52A8\uFF1A\u5F85\u670D\u52A1\u5C31\u7EEA\u540E\uFF0C\u8BF7\u5728\u6D4F\u89C8\u5668\u8BBF\u95EE http://127.0.0.1:${effectivePort}/ui \u8FDB\u884C\u914D\u7F6E\u3002`));
158
160
  }
161
+ if (!options.daemon) {
162
+ const forwardSignal = (signal) => {
163
+ if (!child.killed) {
164
+ try {
165
+ child.kill(signal);
166
+ } catch {
167
+ }
168
+ }
169
+ };
170
+ process.on("SIGINT", forwardSignal);
171
+ process.on("SIGTERM", forwardSignal);
172
+ await new Promise((resolve) => {
173
+ child.on("exit", () => resolve());
174
+ child.on("close", () => resolve());
175
+ });
176
+ process.off("SIGINT", forwardSignal);
177
+ process.off("SIGTERM", forwardSignal);
178
+ await removePid();
179
+ if (child.exitCode && child.exitCode !== 0) {
180
+ process.exitCode = child.exitCode;
181
+ }
182
+ }
159
183
  }
160
184
  async function handleStop() {
161
185
  const pid = await readPid();