@uvl000/claude-trace 3.0.13-workflowexp.1
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 +477 -0
- package/README.zh-CN.md +477 -0
- package/dist/adapt/api-format.d.ts +41 -0
- package/dist/adapt/api-format.d.ts.map +1 -0
- package/dist/adapt/api-format.js +132 -0
- package/dist/adapt/api-format.js.map +1 -0
- package/dist/adapt/openai-adapter.d.ts +123 -0
- package/dist/adapt/openai-adapter.d.ts.map +1 -0
- package/dist/adapt/openai-adapter.js +628 -0
- package/dist/adapt/openai-adapter.js.map +1 -0
- package/dist/cli/cli-common.d.ts +73 -0
- package/dist/cli/cli-common.d.ts.map +1 -0
- package/dist/cli/cli-common.js +189 -0
- package/dist/cli/cli-common.js.map +1 -0
- package/dist/cli/cli.d.ts +23 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +175 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/codex-cli.d.ts +24 -0
- package/dist/cli/codex-cli.d.ts.map +1 -0
- package/dist/cli/codex-cli.js +146 -0
- package/dist/cli/codex-cli.js.map +1 -0
- package/dist/cli/opencode-cli.d.ts +23 -0
- package/dist/cli/opencode-cli.d.ts.map +1 -0
- package/dist/cli/opencode-cli.js +156 -0
- package/dist/cli/opencode-cli.js.map +1 -0
- package/dist/cli/trace-runner.d.ts +21 -0
- package/dist/cli/trace-runner.d.ts.map +1 -0
- package/dist/cli/trace-runner.js +282 -0
- package/dist/cli/trace-runner.js.map +1 -0
- package/dist/cli/validate-trace.d.ts +30 -0
- package/dist/cli/validate-trace.d.ts.map +1 -0
- package/dist/cli/validate-trace.js +230 -0
- package/dist/cli/validate-trace.js.map +1 -0
- package/dist/cli/verify-offline-bundle.d.ts +13 -0
- package/dist/cli/verify-offline-bundle.d.ts.map +1 -0
- package/dist/cli/verify-offline-bundle.js +89 -0
- package/dist/cli/verify-offline-bundle.js.map +1 -0
- package/dist/cli/vibe-coding-proxy-cli.d.ts +12 -0
- package/dist/cli/vibe-coding-proxy-cli.d.ts.map +1 -0
- package/dist/cli/vibe-coding-proxy-cli.js +218 -0
- package/dist/cli/vibe-coding-proxy-cli.js.map +1 -0
- package/dist/config/claude-config-overlay.d.ts +69 -0
- package/dist/config/claude-config-overlay.d.ts.map +1 -0
- package/dist/config/claude-config-overlay.js +229 -0
- package/dist/config/claude-config-overlay.js.map +1 -0
- package/dist/config/codex-config-overlay.d.ts +122 -0
- package/dist/config/codex-config-overlay.d.ts.map +1 -0
- package/dist/config/codex-config-overlay.js +352 -0
- package/dist/config/codex-config-overlay.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/intercept/forward-proxy.d.ts +77 -0
- package/dist/intercept/forward-proxy.d.ts.map +1 -0
- package/dist/intercept/forward-proxy.js +368 -0
- package/dist/intercept/forward-proxy.js.map +1 -0
- package/dist/intercept/header-redaction.d.ts +7 -0
- package/dist/intercept/header-redaction.d.ts.map +1 -0
- package/dist/intercept/header-redaction.js +28 -0
- package/dist/intercept/header-redaction.js.map +1 -0
- package/dist/intercept/interceptor-loader.js +26 -0
- package/dist/intercept/interceptor.d.ts +164 -0
- package/dist/intercept/interceptor.d.ts.map +1 -0
- package/dist/intercept/interceptor.js +496 -0
- package/dist/intercept/interceptor.js.map +1 -0
- package/dist/intercept/mitm-cert.d.ts +53 -0
- package/dist/intercept/mitm-cert.d.ts.map +1 -0
- package/dist/intercept/mitm-cert.js +259 -0
- package/dist/intercept/mitm-cert.js.map +1 -0
- package/dist/intercept/proxy-log-writer.d.ts +77 -0
- package/dist/intercept/proxy-log-writer.d.ts.map +1 -0
- package/dist/intercept/proxy-log-writer.js +323 -0
- package/dist/intercept/proxy-log-writer.js.map +1 -0
- package/dist/intercept/proxy-targets.d.ts +69 -0
- package/dist/intercept/proxy-targets.d.ts.map +1 -0
- package/dist/intercept/proxy-targets.js +129 -0
- package/dist/intercept/proxy-targets.js.map +1 -0
- package/dist/intercept/reverse-proxy.d.ts +191 -0
- package/dist/intercept/reverse-proxy.d.ts.map +1 -0
- package/dist/intercept/reverse-proxy.js +807 -0
- package/dist/intercept/reverse-proxy.js.map +1 -0
- package/dist/intercept/token-extractor.js +28 -0
- package/dist/report/html-generator.d.ts +96 -0
- package/dist/report/html-generator.d.ts.map +1 -0
- package/dist/report/html-generator.js +225 -0
- package/dist/report/html-generator.js.map +1 -0
- package/dist/report/index-generator.d.ts +89 -0
- package/dist/report/index-generator.d.ts.map +1 -0
- package/dist/report/index-generator.js +319 -0
- package/dist/report/index-generator.js.map +1 -0
- package/dist/report/shared-conversation-processor.d.ts +200 -0
- package/dist/report/shared-conversation-processor.d.ts.map +1 -0
- package/dist/report/shared-conversation-processor.js +720 -0
- package/dist/report/shared-conversation-processor.js.map +1 -0
- package/dist/routing/codex-routing.d.ts +40 -0
- package/dist/routing/codex-routing.d.ts.map +1 -0
- package/dist/routing/codex-routing.js +96 -0
- package/dist/routing/codex-routing.js.map +1 -0
- package/dist/routing/proxy-routing.d.ts +48 -0
- package/dist/routing/proxy-routing.d.ts.map +1 -0
- package/dist/routing/proxy-routing.js +113 -0
- package/dist/routing/proxy-routing.js.map +1 -0
- package/dist/tools/binary-utils.d.ts +29 -0
- package/dist/tools/binary-utils.d.ts.map +1 -0
- package/dist/tools/binary-utils.js +134 -0
- package/dist/tools/binary-utils.js.map +1 -0
- package/dist/tools/claude.d.ts +61 -0
- package/dist/tools/claude.d.ts.map +1 -0
- package/dist/tools/claude.js +449 -0
- package/dist/tools/claude.js.map +1 -0
- package/dist/tools/codex.d.ts +70 -0
- package/dist/tools/codex.d.ts.map +1 -0
- package/dist/tools/codex.js +492 -0
- package/dist/tools/codex.js.map +1 -0
- package/dist/tools/opencode.d.ts +85 -0
- package/dist/tools/opencode.d.ts.map +1 -0
- package/dist/tools/opencode.js +401 -0
- package/dist/tools/opencode.js.map +1 -0
- package/dist/tools/types.d.ts +91 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +11 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/types.d.ts +158 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/frontend/dist/index.global.js +1551 -0
- package/frontend/dist/styles.css +1027 -0
- package/frontend/template.html +19 -0
- package/node_modules/agent-base/LICENSE +22 -0
- package/node_modules/agent-base/README.md +69 -0
- package/node_modules/agent-base/dist/helpers.d.ts +15 -0
- package/node_modules/agent-base/dist/helpers.d.ts.map +1 -0
- package/node_modules/agent-base/dist/helpers.js +66 -0
- package/node_modules/agent-base/dist/helpers.js.map +1 -0
- package/node_modules/agent-base/dist/index.d.ts +41 -0
- package/node_modules/agent-base/dist/index.d.ts.map +1 -0
- package/node_modules/agent-base/dist/index.js +178 -0
- package/node_modules/agent-base/dist/index.js.map +1 -0
- package/node_modules/agent-base/package.json +46 -0
- package/node_modules/debug/LICENSE +20 -0
- package/node_modules/debug/README.md +481 -0
- package/node_modules/debug/package.json +64 -0
- package/node_modules/debug/src/browser.js +272 -0
- package/node_modules/debug/src/common.js +292 -0
- package/node_modules/debug/src/index.js +10 -0
- package/node_modules/debug/src/node.js +263 -0
- package/node_modules/http-proxy-agent/LICENSE +22 -0
- package/node_modules/http-proxy-agent/README.md +44 -0
- package/node_modules/http-proxy-agent/dist/index.d.ts +44 -0
- package/node_modules/http-proxy-agent/dist/index.d.ts.map +1 -0
- package/node_modules/http-proxy-agent/dist/index.js +148 -0
- package/node_modules/http-proxy-agent/dist/index.js.map +1 -0
- package/node_modules/http-proxy-agent/package.json +47 -0
- package/node_modules/https-proxy-agent/LICENSE +22 -0
- package/node_modules/https-proxy-agent/README.md +70 -0
- package/node_modules/https-proxy-agent/dist/index.d.ts +47 -0
- package/node_modules/https-proxy-agent/dist/index.d.ts.map +1 -0
- package/node_modules/https-proxy-agent/dist/index.js +180 -0
- package/node_modules/https-proxy-agent/dist/index.js.map +1 -0
- package/node_modules/https-proxy-agent/dist/parse-proxy-response.d.ts +15 -0
- package/node_modules/https-proxy-agent/dist/parse-proxy-response.d.ts.map +1 -0
- package/node_modules/https-proxy-agent/dist/parse-proxy-response.js +101 -0
- package/node_modules/https-proxy-agent/dist/parse-proxy-response.js.map +1 -0
- package/node_modules/https-proxy-agent/package.json +50 -0
- package/node_modules/ms/index.js +162 -0
- package/node_modules/ms/license.md +21 -0
- package/node_modules/ms/package.json +38 -0
- package/node_modules/ms/readme.md +59 -0
- package/node_modules/node-forge/LICENSE +331 -0
- package/node_modules/node-forge/README.md +2071 -0
- package/node_modules/node-forge/dist/forge.all.min.js +2 -0
- package/node_modules/node-forge/dist/forge.all.min.js.map +1 -0
- package/node_modules/node-forge/dist/forge.min.js +2 -0
- package/node_modules/node-forge/dist/forge.min.js.map +1 -0
- package/node_modules/node-forge/dist/prime.worker.min.js +2 -0
- package/node_modules/node-forge/dist/prime.worker.min.js.map +1 -0
- package/node_modules/node-forge/flash/swf/SocketPool.swf +0 -0
- package/node_modules/node-forge/lib/aes.js +1091 -0
- package/node_modules/node-forge/lib/aesCipherSuites.js +282 -0
- package/node_modules/node-forge/lib/asn1-validator.js +91 -0
- package/node_modules/node-forge/lib/asn1.js +1503 -0
- package/node_modules/node-forge/lib/baseN.js +186 -0
- package/node_modules/node-forge/lib/cipher.js +230 -0
- package/node_modules/node-forge/lib/cipherModes.js +999 -0
- package/node_modules/node-forge/lib/des.js +496 -0
- package/node_modules/node-forge/lib/ed25519.js +1091 -0
- package/node_modules/node-forge/lib/forge.js +13 -0
- package/node_modules/node-forge/lib/form.js +149 -0
- package/node_modules/node-forge/lib/hmac.js +146 -0
- package/node_modules/node-forge/lib/http.js +1346 -0
- package/node_modules/node-forge/lib/index.all.js +16 -0
- package/node_modules/node-forge/lib/index.js +33 -0
- package/node_modules/node-forge/lib/jsbn.js +1294 -0
- package/node_modules/node-forge/lib/kem.js +168 -0
- package/node_modules/node-forge/lib/log.js +319 -0
- package/node_modules/node-forge/lib/md.all.js +13 -0
- package/node_modules/node-forge/lib/md.js +11 -0
- package/node_modules/node-forge/lib/md5.js +289 -0
- package/node_modules/node-forge/lib/mgf.js +12 -0
- package/node_modules/node-forge/lib/mgf1.js +57 -0
- package/node_modules/node-forge/lib/oids.js +180 -0
- package/node_modules/node-forge/lib/pbe.js +1023 -0
- package/node_modules/node-forge/lib/pbkdf2.js +211 -0
- package/node_modules/node-forge/lib/pem.js +237 -0
- package/node_modules/node-forge/lib/pkcs1.js +276 -0
- package/node_modules/node-forge/lib/pkcs12.js +1078 -0
- package/node_modules/node-forge/lib/pkcs7.js +1260 -0
- package/node_modules/node-forge/lib/pkcs7asn1.js +410 -0
- package/node_modules/node-forge/lib/pki.js +102 -0
- package/node_modules/node-forge/lib/prime.js +297 -0
- package/node_modules/node-forge/lib/prime.worker.js +168 -0
- package/node_modules/node-forge/lib/prng.js +419 -0
- package/node_modules/node-forge/lib/pss.js +241 -0
- package/node_modules/node-forge/lib/random.js +191 -0
- package/node_modules/node-forge/lib/rc2.js +410 -0
- package/node_modules/node-forge/lib/rsa.js +1968 -0
- package/node_modules/node-forge/lib/sha1.js +319 -0
- package/node_modules/node-forge/lib/sha256.js +327 -0
- package/node_modules/node-forge/lib/sha512.js +561 -0
- package/node_modules/node-forge/lib/socket.js +287 -0
- package/node_modules/node-forge/lib/ssh.js +236 -0
- package/node_modules/node-forge/lib/tls.js +4282 -0
- package/node_modules/node-forge/lib/tlssocket.js +249 -0
- package/node_modules/node-forge/lib/util.js +2652 -0
- package/node_modules/node-forge/lib/x509.js +3251 -0
- package/node_modules/node-forge/lib/xhr.js +738 -0
- package/node_modules/node-forge/package.json +123 -0
- package/node_modules/smol-toml/LICENSE +24 -0
- package/node_modules/smol-toml/README.md +239 -0
- package/node_modules/smol-toml/dist/date.d.ts +41 -0
- package/node_modules/smol-toml/dist/date.js +127 -0
- package/node_modules/smol-toml/dist/error.d.ts +38 -0
- package/node_modules/smol-toml/dist/error.js +63 -0
- package/node_modules/smol-toml/dist/extract.d.ts +30 -0
- package/node_modules/smol-toml/dist/extract.js +100 -0
- package/node_modules/smol-toml/dist/index.cjs +897 -0
- package/node_modules/smol-toml/dist/index.d.ts +43 -0
- package/node_modules/smol-toml/dist/index.js +33 -0
- package/node_modules/smol-toml/dist/parse.d.ts +37 -0
- package/node_modules/smol-toml/dist/parse.js +148 -0
- package/node_modules/smol-toml/dist/primitive.d.ts +31 -0
- package/node_modules/smol-toml/dist/primitive.js +179 -0
- package/node_modules/smol-toml/dist/stringify.d.ts +31 -0
- package/node_modules/smol-toml/dist/stringify.js +167 -0
- package/node_modules/smol-toml/dist/struct.d.ts +32 -0
- package/node_modules/smol-toml/dist/struct.js +184 -0
- package/node_modules/smol-toml/dist/util.d.ts +42 -0
- package/node_modules/smol-toml/dist/util.js +111 -0
- package/node_modules/smol-toml/package.json +54 -0
- package/offline/bin/claude-trace +6 -0
- package/offline/bin/claude-wrapper +13 -0
- package/offline/bin/install-agent +14 -0
- package/offline/bin/validate-trace +6 -0
- package/offline/bin/verify-bundle +7 -0
- package/package.json +103 -0
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
# claude-trace
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
记录 **Claude Code**、**OpenCode**、**Codex CLI** 以及通过独立正向代理接入的指定大模型端点 API 流量。在自包含 HTML 查看器中查看系统提示词、工具输出、思考块以及完整请求/响应数据。
|
|
6
|
+
|
|
7
|
+
**[mariozechner/claude-trace](https://github.com/badlogic/lemmy/tree/main/apps/claude-trace) 的分支版本**,扩展支持 [Claude Code V2+](https://docs.anthropic.com/en/docs/claude-code) 原生二进制、独立的 **[OpenCode](https://opencode.ai)** 命令(多 provider 拦截,Anthropic 与 OpenAI API 格式),以及 **[Codex CLI](https://developers.openai.com/codex/cli) ChatGPT OAuth** 追踪(通过 ChatGPT 账号登录 —— 多数用户的默认 Codex 认证方式)。
|
|
8
|
+
|
|
9
|
+
## 代理模式总览(正向代理 & 反向代理)
|
|
10
|
+
|
|
11
|
+
本项目同时支持 **两种代理模式**:
|
|
12
|
+
|
|
13
|
+
- **反向代理(内置工具封装)**:`claude-trace`、`opencode-trace`、`codex-trace` 会启动本地反向代理,并在启动目标工具时把其上游 base URL 重定向到代理(因此可以自动记录流量)。
|
|
14
|
+
- **正向代理(独立代理)**:`vibe-coding-proxy` 只启动 HTTP/HTTPS 正向代理。你需要在启动要追踪的客户端之前,先在同一个 shell/session 中 **导出 `HTTP_PROXY` / `HTTPS_PROXY` / `ALL_PROXY`**。
|
|
15
|
+
|
|
16
|
+
## 支持的工具
|
|
17
|
+
|
|
18
|
+
| 工具 | CLI 命令 | 日志目录 | 拦截方式 |
|
|
19
|
+
|------|----------|----------|----------|
|
|
20
|
+
| **Claude Code** | `claude-trace` | `.claude-trace/` | V1:`fetch()` 钩子 · V2+:反向代理(`ANTHROPIC_BASE_URL`) |
|
|
21
|
+
| **OpenCode** | `opencode-trace` | `.opencode-trace/` | 反向代理 + 模型路由;支持 Anthropic 与 OpenAI 格式 |
|
|
22
|
+
| **Codex CLI** | `codex-trace` | `.codex-trace/` | 反向代理(`CODEX_HOME` 覆盖);**ChatGPT OAuth** 与 OpenAI API Key(Responses API) |
|
|
23
|
+
| **独立代理** | `vibe-coding-proxy` | `.vibe-coding-proxy/` | 通过 `HTTP_PROXY` / `HTTPS_PROXY` 使用正向代理;仅对 allowlist 目标做 HTTPS MITM |
|
|
24
|
+
|
|
25
|
+
三条命令共用同一套 HTML 报告界面、JSONL/JSON 导出,以及 `--index` 会话摘要功能。
|
|
26
|
+
|
|
27
|
+
## 快速开始
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install -g @uvl000/claude-trace
|
|
31
|
+
|
|
32
|
+
# Claude Code
|
|
33
|
+
claude-trace
|
|
34
|
+
|
|
35
|
+
# OpenCode
|
|
36
|
+
opencode-trace
|
|
37
|
+
|
|
38
|
+
# Codex CLI
|
|
39
|
+
codex-trace
|
|
40
|
+
|
|
41
|
+
# 独立正向代理
|
|
42
|
+
vibe-coding-proxy --target-url https://api.deepseek.com/anthropic
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
会话结束后会自动在浏览器中打开最新 HTML 报告(可用 `--no-open` 关闭)。
|
|
46
|
+
|
|
47
|
+
## 安装
|
|
48
|
+
|
|
49
|
+
### 从 npm 安装
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install -g @uvl000/claude-trace
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 从源码安装
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/hanqunfeng/claude-trace.git
|
|
59
|
+
cd claude-trace
|
|
60
|
+
npm run setup # 安装根目录 + frontend 依赖
|
|
61
|
+
npm run build
|
|
62
|
+
npm link # 可选:全局可用 claude-trace、opencode-trace、codex-trace 与 vibe-coding-proxy
|
|
63
|
+
# 不 link 则用 node dist/cli/cli.js / node dist/cli/opencode-cli.js / node dist/cli/codex-cli.js / node dist/cli/vibe-coding-proxy-cli.js
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Claude Code(`claude-trace`)
|
|
67
|
+
|
|
68
|
+
### 使用
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# 启动 Claude Code 并记录日志(自动识别 V1 JS / V2+ 原生二进制)
|
|
72
|
+
claude-trace
|
|
73
|
+
|
|
74
|
+
# 记录所有 API 请求(代理模式默认只记录 /v1/messages)
|
|
75
|
+
claude-trace --include-all-requests
|
|
76
|
+
|
|
77
|
+
# 记录敏感 header 且不脱敏(请谨慎使用)
|
|
78
|
+
claude-trace --include-sensitive-headers
|
|
79
|
+
|
|
80
|
+
# 向 Claude 传递参数
|
|
81
|
+
claude-trace --run-with chat --model sonnet-3.5
|
|
82
|
+
|
|
83
|
+
# 指定 Claude 二进制路径
|
|
84
|
+
claude-trace --claude-path /usr/local/Caskroom/claude-code/2.1.153/claude
|
|
85
|
+
|
|
86
|
+
# 提取 OAuth token(V1 Node.js 路径)
|
|
87
|
+
claude-trace --extract-token
|
|
88
|
+
|
|
89
|
+
# 从已有 .jsonl 生成 HTML 报告
|
|
90
|
+
claude-trace --generate-html logs.jsonl report.html
|
|
91
|
+
|
|
92
|
+
# 生成会话摘要与可搜索索引
|
|
93
|
+
claude-trace --index
|
|
94
|
+
|
|
95
|
+
claude-trace --help
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
日志路径:当前目录 `.claude-trace/log-YYYY-MM-DD-HH-MM-SS.{jsonl,json,html}`。
|
|
99
|
+
|
|
100
|
+
### CLI 选项
|
|
101
|
+
|
|
102
|
+
| 参数 | 说明 |
|
|
103
|
+
|------|------|
|
|
104
|
+
| `--include-all-requests` | 记录所有 API 流量,不仅限于 `/v1/messages` |
|
|
105
|
+
| `--include-sensitive-headers` | 记录 auth token、cookie 等,不做脱敏 |
|
|
106
|
+
| `--log NAME` | 自定义日志文件名(不含扩展名) |
|
|
107
|
+
| `--claude-path PATH` | Claude 二进制路径(省略则自动检测) |
|
|
108
|
+
| `--no-open` | 生成 HTML 后不自动打开浏览器 |
|
|
109
|
+
| `--run-with ARGS...` | 将后续参数传给 Claude |
|
|
110
|
+
| `--extract-token` | 提取 OAuth token 后退出 |
|
|
111
|
+
| `--generate-html FILE [OUT]` | 从 JSONL 生成 HTML 报告 |
|
|
112
|
+
| `--index` | 生成会话摘要与索引 |
|
|
113
|
+
|
|
114
|
+
### Claude Code V2+(原生二进制)
|
|
115
|
+
|
|
116
|
+
Claude Code V2 以**原生二进制**分发(macOS Mach-O / Linux ELF / Windows PE),不再是 Node.js 脚本。原有 `node --require interceptor claude` 方式已不可用。
|
|
117
|
+
|
|
118
|
+
| Claude Code 版本 | 二进制类型 | 拦截模式 |
|
|
119
|
+
|------------------|------------|----------|
|
|
120
|
+
| V1.x | Node.js 脚本 | 通过 `--require` 注入 `interceptor-loader.js` |
|
|
121
|
+
| **V2+** | 原生二进制 | 本地反向代理;重定向 `ANTHROPIC_BASE_URL` |
|
|
122
|
+
|
|
123
|
+
流程:
|
|
124
|
+
|
|
125
|
+
1. 在 `127.0.0.1` 启动本地 HTTP 反向代理
|
|
126
|
+
2. 通过 `ANTHROPIC_BASE_URL` 将 Claude Code 指向代理
|
|
127
|
+
3. 转发流量到真实上游(`~/.claude/settings.json` 或环境变量)
|
|
128
|
+
4. 实时写入 `.claude-trace/`
|
|
129
|
+
|
|
130
|
+
若 `~/.claude/settings.json` 已设置 `ANTHROPIC_BASE_URL`,会使用持久化配置 overlay(`~/.claude-trace/claude-config-overlay/`):仅重写 `settings.json` 去掉该项,其余条目尽量通过符号链接指向原配置(Windows 目录用 junction,文件 symlink 失败则复制)。**单项链接失败不会阻断启动**,代理仍可用;跳过的条目仅在 `CLAUDE_TRACE_DEBUG=1` 时输出到 stderr。
|
|
131
|
+
|
|
132
|
+
### 第三方模型(CC-Switch 与自定义端点)
|
|
133
|
+
|
|
134
|
+
支持任何通过自定义 `ANTHROPIC_BASE_URL` 路由 Claude Code 的方案——[CC-Switch](https://github.com/farion1231/cc-switch)、LiteLLM、企业网关、自托管代理等。
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Claude Code → claude-trace 代理(记录) → CC-Switch / 自定义端点 → 模型提供商
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
CC-Switch 示例:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# CC-Switch 写入 ~/.claude/settings.json 后:
|
|
144
|
+
claude-trace
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
手动指定上游:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
export ANTHROPIC_BASE_URL="https://your-gateway.example.com"
|
|
151
|
+
claude-trace
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
注意事项:
|
|
155
|
+
|
|
156
|
+
- 上游需支持 **Anthropic Messages API**(`/v1/messages`),或使用能转换为该格式的网关
|
|
157
|
+
- API Key 及 settings 中的其他 `env` 项会保留——仅在本地覆盖 `ANTHROPIC_BASE_URL`
|
|
158
|
+
- HTML 日志会显示实际上游 URL 和每次请求的模型名
|
|
159
|
+
|
|
160
|
+
### 请求过滤(Claude)
|
|
161
|
+
|
|
162
|
+
**代理模式(V2+):** 默认 `/v1/messages`;`--include-all-requests` 记录所有代理流量。
|
|
163
|
+
|
|
164
|
+
**拦截模式(V1,Node.js):** 默认记录上下文中消息数 > 2 的 `/v1/messages`;`--include-all-requests` 记录所有 `api.anthropic.com` 请求。
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## OpenCode(`opencode-trace`)
|
|
169
|
+
|
|
170
|
+
### 使用
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# 启动 OpenCode TUI 并记录日志
|
|
174
|
+
opencode-trace
|
|
175
|
+
|
|
176
|
+
# 单次 prompt
|
|
177
|
+
opencode-trace --run-with run "Explain async/await"
|
|
178
|
+
|
|
179
|
+
# 指定模型
|
|
180
|
+
opencode-trace --run-with run -m my-deepseek/deepseek-v4-flash "Refactor this module"
|
|
181
|
+
|
|
182
|
+
# 从已有会话生成 HTML
|
|
183
|
+
opencode-trace --generate-html .opencode-trace/log-2025-01-01-12-00-00.jsonl
|
|
184
|
+
|
|
185
|
+
# 生成会话索引
|
|
186
|
+
opencode-trace --index
|
|
187
|
+
|
|
188
|
+
opencode-trace --help
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
日志路径:当前目录 `.opencode-trace/log-YYYY-MM-DD-HH-MM-SS.{jsonl,json,html}`。代理运行时错误追加写入 `.opencode-trace/proxy-errors.log`。
|
|
192
|
+
|
|
193
|
+
### 拦截原理
|
|
194
|
+
|
|
195
|
+
OpenCode 为原生二进制。`opencode-trace` 启动本地反向代理,并通过 `OPENCODE_CONFIG_CONTENT` 注入运行时配置覆盖——**不会修改原始 `opencode.json`**。
|
|
196
|
+
|
|
197
|
+
配置中所有 provider 的 `baseURL` 均指向本地代理。代理从请求体读取 `model` 字段,映射到对应 provider 与真实上游 URL,再转发请求。支持 **Anthropic**(`/v1/messages`)与 **OpenAI** 格式(`/v1/chat/completions`、`/v1/responses`,即 `@ai-sdk/openai-compatible` 与 `@ai-sdk/openai`)。
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
OpenCode → opencode-trace 代理(记录) → provider baseURL(DeepSeek、MiniMax 等)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
配置读取顺序:
|
|
204
|
+
|
|
205
|
+
1. 环境变量 `OPENCODE_CONFIG`
|
|
206
|
+
2. `OPENCODE_CONFIG_DIR/opencode.json`
|
|
207
|
+
3. `~/.config/opencode/opencode.json`
|
|
208
|
+
4. 当前目录 `.opencode/opencode.json`
|
|
209
|
+
|
|
210
|
+
### 支持的 API 格式
|
|
211
|
+
|
|
212
|
+
| OpenCode `npm` 包 | API 格式 | 端点 | 对话视图标签 |
|
|
213
|
+
|-------------------|----------|------|--------------|
|
|
214
|
+
| `@ai-sdk/anthropic` | Anthropic Messages | `/v1/messages` | Anthropic Messages |
|
|
215
|
+
| `@ai-sdk/openai-compatible` | OpenAI Chat Completions | `/v1/chat/completions` | OpenAI Chat |
|
|
216
|
+
| `@ai-sdk/openai` | OpenAI Responses | `/v1/responses` | OpenAI Responses |
|
|
217
|
+
|
|
218
|
+
代理从请求体读取 `model` 字段,路由到对应 provider 的 `baseURL`。同一 provider 下可通过 per-model `npm` 混用 chat 与 responses API。未在 `opencode.json` 中显式声明的模型,可通过 provider 级回退路由(`providerId/*`)匹配。
|
|
219
|
+
|
|
220
|
+
### CLI 选项
|
|
221
|
+
|
|
222
|
+
| 参数 | 说明 |
|
|
223
|
+
|------|------|
|
|
224
|
+
| `--opencode-path PATH` | OpenCode 二进制路径(省略则自动检测) |
|
|
225
|
+
| `--include-all-requests` | 记录所有代理流量,不仅限于 messages 端点 |
|
|
226
|
+
| `--include-sensitive-headers` | 不脱敏记录 auth 头 |
|
|
227
|
+
| `--log NAME` | 自定义日志文件名 |
|
|
228
|
+
| `--no-open` | 不自动打开 HTML |
|
|
229
|
+
| `--run-with ARGS...` | 传递给 OpenCode 的参数 |
|
|
230
|
+
|
|
231
|
+
### 调试
|
|
232
|
+
|
|
233
|
+
默认情况下运行时日志**静默输出**,避免污染 OpenCode TUI 输入框。
|
|
234
|
+
|
|
235
|
+
| 输出内容 | 默认行为 | 设置 `OPENCODE_TRACE_DEBUG=1` 后 |
|
|
236
|
+
|----------|----------|----------------------------------|
|
|
237
|
+
| 每次请求路由(model → provider → 上游 URL) | 不输出 | 打印到 stderr |
|
|
238
|
+
| 代理错误(如上游 TLS 连接失败) | 写入 `.opencode-trace/proxy-errors.log` | 同时打印到 stderr |
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
OPENCODE_TRACE_DEBUG=1 opencode-trace
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
当模型未正确路由、日志缺少请求,或上游连接失败时,可使用此命令排查。
|
|
245
|
+
|
|
246
|
+
### OpenCode 当前限制
|
|
247
|
+
|
|
248
|
+
- **对话视图**支持 Anthropic 格式(`@ai-sdk/anthropic`)与 OpenAI 格式(`@ai-sdk/openai-compatible`、`@ai-sdk/openai`)provider;复杂字段(多模态、reasoning 等)可能仅在 Raw/JSON 视图中完整展示。
|
|
249
|
+
- 尚未拦截未在 `opencode.json` 中定义的内置 `models.dev` provider。
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Codex CLI(`codex-trace`)
|
|
254
|
+
|
|
255
|
+
**主要认证方式:ChatGPT OAuth。** 若你通过 ChatGPT 账号登录 Codex(多数安装的默认方式),`codex-trace` 可完整追踪该路径 —— 多轮对话、zstd 压缩请求与 SSE 流式响应均能在 HTML 报告中正确展示。
|
|
256
|
+
|
|
257
|
+
### 用法
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# 启动 Codex TUI 并记录流量(支持 ChatGPT OAuth 或 API Key)
|
|
261
|
+
codex-trace
|
|
262
|
+
|
|
263
|
+
# 无头单次执行
|
|
264
|
+
codex-trace --run-with exec "Explain async/await"
|
|
265
|
+
|
|
266
|
+
# 从历史日志生成 HTML
|
|
267
|
+
codex-trace --generate-html .codex-trace/log-2025-01-01-12-00-00.jsonl
|
|
268
|
+
|
|
269
|
+
# 生成会话索引
|
|
270
|
+
codex-trace --index
|
|
271
|
+
|
|
272
|
+
codex-trace --help
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
日志路径:当前目录 `.codex-trace/log-YYYY-MM-DD-HH-MM-SS.{jsonl,json,html}`。
|
|
276
|
+
|
|
277
|
+
### ChatGPT OAuth 模式(推荐)
|
|
278
|
+
|
|
279
|
+
多数用户通过 **ChatGPT 登录** 使用 Codex(`codex login` 或 TUI 内登录)。`codex-trace` 读取 `~/.codex/auth.json`,当 `auth_mode` 为 `"chatgpt"` 时,将所有 LLM 流量路由到 ChatGPT OAuth 上游(`chatgpt.com/backend-api/codex`)——**即使 shell 中为其他工具设置了 `OPENAI_BASE_URL`**(如 Cursor、LiteLLM 等)也不受影响。
|
|
280
|
+
|
|
281
|
+
| 检查项 | 预期 |
|
|
282
|
+
|--------|------|
|
|
283
|
+
| 认证文件 | `~/.codex/auth.json` 含 `"auth_mode": "chatgpt"` |
|
|
284
|
+
| 会话数据 | 从真实 `$CODEX_HOME` symlink,OAuth token 不会被改写 |
|
|
285
|
+
| HTML 报告 | 多轮对话完整展示每条 assistant 回复,含最后一轮 |
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
Codex CLI(ChatGPT OAuth) → codex-trace 代理(记录) → chatgpt.com/backend-api/codex
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**提示:** 请先完成 ChatGPT 登录,再启动 `codex-trace`。若在 trace 会话中途于 Codex 内切换认证方式,建议重新运行 `codex-trace`。
|
|
292
|
+
|
|
293
|
+
### OpenAI API Key 模式
|
|
294
|
+
|
|
295
|
+
若使用 **OpenAI API Key** 而非 ChatGPT 登录,流量经 `openai_base_url` / `OPENAI_BASE_URL` / `api.openai.com`(或自定义网关)路由。请勿将 ChatGPT OAuth token 与自定义 `OPENAI_BASE_URL` 网关混用 —— 同一时间只应使用一种认证方式。
|
|
296
|
+
|
|
297
|
+
### 拦截原理
|
|
298
|
+
|
|
299
|
+
Codex CLI 为 Rust 原生二进制。`codex-trace` 启动本地反向代理,并在 `~/.claude-trace/codex-config-overlay/` 构建配置覆盖层——**不会修改原始 `~/.codex/config.toml`**。
|
|
300
|
+
|
|
301
|
+
覆盖层将 `openai_base_url`、`chatgpt_base_url` 及自定义 `model_providers.*.base_url` 改写为代理地址。`auth.json` 与会话数据通过 symlink 保留,ChatGPT OAuth 可继续使用。代理根据 **`auth.json` 的 auth 模式**(ChatGPT OAuth 或 API Key)与请求路径选择上游:
|
|
302
|
+
|
|
303
|
+
- **ChatGPT OAuth**(`auth_mode: "chatgpt"`):`/responses`、`/v1/responses`、`/backend-api/codex/...` → `chatgpt.com`
|
|
304
|
+
- **ChatGPT Apps MCP**(`codex_apps`):`/api/codex/apps` → `chatgpt.com/backend-api/wham/apps`;`/backend-api/wham/...` → `chatgpt.com`(站点根路径)
|
|
305
|
+
- **OpenAI API Key**:`/v1/responses`、`/responses` → `openai_base_url` / `OPENAI_BASE_URL` / 默认 OpenAI 主机
|
|
306
|
+
- **自定义 `model_providers`**:非保留 provider id 且配置了 `base_url` 的条目
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
Codex CLI → codex-trace 代理(记录) → chatgpt.com(OAuth)/ api.openai.com / 自定义 provider
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
配置查找:`CODEX_HOME`(覆盖层)或 `~/.codex/config.toml`。
|
|
313
|
+
|
|
314
|
+
### CLI 选项
|
|
315
|
+
|
|
316
|
+
| 参数 | 说明 |
|
|
317
|
+
|------|------|
|
|
318
|
+
| `--codex-path PATH` | Codex 二进制路径(省略则自动检测) |
|
|
319
|
+
| `--include-all-requests` | 记录所有代理流量,不仅限于 LLM API 路径 |
|
|
320
|
+
| `--include-sensitive-headers` | 不脱敏记录认证头 |
|
|
321
|
+
| `--log NAME` | 自定义日志文件名前缀 |
|
|
322
|
+
| `--no-open` | 不自动打开 HTML |
|
|
323
|
+
| `--run-with ARGS...` | 将后续参数传给 Codex |
|
|
324
|
+
|
|
325
|
+
### Codex 限制
|
|
326
|
+
|
|
327
|
+
- 覆盖层强制 `supports_websockets = false`,确保 HTTP/SSE 流量可被记录。
|
|
328
|
+
- 内置 provider ID(`openai`、`ollama`、`lmstudio`)不能通过 `model_providers` 覆盖;ChatGPT OAuth 使用 `chatgpt_base_url`,API Key 模式使用 `openai_base_url`。
|
|
329
|
+
- **Ollama / LM Studio** 内置 provider 不会被拦截(流量绕过代理)。
|
|
330
|
+
- 旧版 `auth.json` 若无 `auth_mode` 字段,会回退到旧启发式;若 OAuth 路由异常,请重新用 ChatGPT 登录。
|
|
331
|
+
- **Node.js:** Codex ChatGPT OAuth 追踪在 **Node.js 16+** 即可正常使用(代理原样转发 zstd 请求体)。建议 **Node.js 22+**,以便在日志与 HTML 中解压展示 zstd 压缩的请求体;Node 16–21 下请求条目会显示占位符而非解析后的 JSON(响应解析与代理行为不受影响)。
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 独立正向代理(`vibe-coding-proxy`)
|
|
336
|
+
|
|
337
|
+
`vibe-coding-proxy` 只启动代理服务,不启动 Claude Code、OpenCode、Codex 或其他客户端。任意兼容 CLI 都可以通过 `HTTP_PROXY`、`HTTPS_PROXY` 或 `ALL_PROXY` 指向启动后打印的代理 URL。
|
|
338
|
+
|
|
339
|
+
### 兼容性与使用顺序
|
|
340
|
+
|
|
341
|
+
- **已测试通过的客户端**:Claude Code、OpenCode、Codex CLI。其他客户端若遵循标准代理环境变量,理论上也可能可用,但目前未做测试。
|
|
342
|
+
- **必须先设环境变量再启动**:先启动 `vibe-coding-proxy` → 在同一个 shell/session 里导出环境变量 → 再启动客户端/工具。若先启动客户端,它可能不会读取到新的代理设置。
|
|
343
|
+
|
|
344
|
+
### 用法
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# 记录指定 DeepSeek Anthropic 兼容端点
|
|
348
|
+
vibe-coding-proxy --target-url https://api.deepseek.com/anthropic
|
|
349
|
+
|
|
350
|
+
# 记录某个主机下的所有 HTTPS 请求
|
|
351
|
+
vibe-coding-proxy --mitm-host api.deepseek.com
|
|
352
|
+
|
|
353
|
+
# 使用固定本地端口
|
|
354
|
+
vibe-coding-proxy --target-url https://api.deepseek.com --port 8888
|
|
355
|
+
|
|
356
|
+
# 从历史 .jsonl 生成 HTML
|
|
357
|
+
vibe-coding-proxy --generate-html .vibe-coding-proxy/log-2025-01-01-12-00-00.jsonl
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
启动后导出打印的代理 URL:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
export HTTP_PROXY=http://127.0.0.1:PORT
|
|
364
|
+
export HTTPS_PROXY=http://127.0.0.1:PORT
|
|
365
|
+
export ALL_PROXY=http://127.0.0.1:PORT
|
|
366
|
+
export NODE_TLS_REJECT_UNAUTHORIZED=0
|
|
367
|
+
export SSL_CERT_FILE=CA_CERT_PATH
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
日志路径:当前目录 `.vibe-coding-proxy/log-YYYY-MM-DD-HH-MM-SS.{jsonl,json,html}`。
|
|
371
|
+
|
|
372
|
+
### HTTPS 记录与 CA 信任
|
|
373
|
+
|
|
374
|
+
通过 `HTTPS_PROXY` 发送的 HTTPS 请求通常先发起 `CONNECT host:443`,代理无法直接看到 JSON body。为了记录请求/响应 body,`vibe-coding-proxy` 只会对 `--target-url` / `--mitm-host` allowlist 命中的目标执行 MITM,并打印本地 CA 证书路径。
|
|
375
|
+
|
|
376
|
+
只应在你希望检查模型流量的客户端中信任该 CA。命令不会自动把 CA 安装到系统信任链。`NODE_TLS_REJECT_UNAUTHORIZED=0` 只对 Node.js 客户端有效;Codex ChatGPT OAuth 是 Rust 客户端,通常需要 `SSL_CERT_FILE` 或操作系统级信任该 CA。未命中 allowlist 的 HTTPS 流量会作为原始 CONNECT 隧道透传,仅在开启 `--include-all-requests` 时记录元数据。
|
|
377
|
+
|
|
378
|
+
### 本地 CA 生命周期
|
|
379
|
+
|
|
380
|
+
本地 CA 默认复用 `~/.claude-trace/vibe-coding-proxy-ca/`,除非你传入 `--ca-dir`。`ca.crt` 有效期为 10 年;按主机缓存的 leaf 证书(如 `api.deepseek.com.crt.pem`)有效期为 1 年。leaf 证书过期会自动重签。CA 过期时会重新生成,并清理所有旧 leaf 证书;此时需要重新信任新的 CA。
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
### CLI 选项
|
|
384
|
+
|
|
385
|
+
| 参数 | 说明 |
|
|
386
|
+
|------|------|
|
|
387
|
+
| `--target-url URL` | 解密并完整记录的 URL 前缀(可重复) |
|
|
388
|
+
| `--mitm-host HOST` | 解密并完整记录的主机名(可重复) |
|
|
389
|
+
| `--host HOST` | 监听地址(默认 `127.0.0.1`) |
|
|
390
|
+
| `--port PORT` | 监听端口(默认 `0`,随机) |
|
|
391
|
+
| `--log-dir DIR` | 日志目录(默认 `.vibe-coding-proxy`) |
|
|
392
|
+
| `--log NAME` | 自定义日志文件名前缀 |
|
|
393
|
+
| `--ca-dir DIR` | 本地 CA 与 leaf 证书缓存目录 |
|
|
394
|
+
| `--no-mitm` | 禁用 TLS MITM;HTTPS CONNECT 仅透传 |
|
|
395
|
+
| `--include-all-requests` | 记录透传 CONNECT 元数据与非目标 HTTP 流量 |
|
|
396
|
+
| `--include-sensitive-headers` | 不脱敏记录认证头 |
|
|
397
|
+
| `--no-open` | 退出时不自动打开 HTML |
|
|
398
|
+
| `--generate-html FILE [OUT]` | 从 JSONL 生成 HTML 报告 |
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## 共用功能
|
|
403
|
+
|
|
404
|
+
### HTML 报告
|
|
405
|
+
|
|
406
|
+
每次会话生成自包含 HTML 文件(内嵌 CSS/JS),可离线打开。退出时默认自动打开浏览器,可用 `--no-open` 关闭。
|
|
407
|
+
|
|
408
|
+
### 你将看到的内容
|
|
409
|
+
|
|
410
|
+
- **系统提示词** — 发送给模型的隐藏指令
|
|
411
|
+
- **工具定义与输出** — 参数及原始工具结果
|
|
412
|
+
- **思考块** — 内部推理过程(如有)
|
|
413
|
+
- **Token 用量** — 含缓存命中的详细统计
|
|
414
|
+
- **原始 JSONL 日志** — 完整请求/响应对
|
|
415
|
+
- **交互式查看器** — 对话、原始 HTTP、JSON 调试等视图
|
|
416
|
+
- **API 格式标签** — 每个会话头部显示请求格式(如 `8 messages · OpenAI Chat`)
|
|
417
|
+
|
|
418
|
+
### 会话索引
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
claude-trace --index
|
|
422
|
+
# 或
|
|
423
|
+
opencode-trace --index
|
|
424
|
+
# 或
|
|
425
|
+
codex-trace --index
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
扫描日志文件,通过 Claude CLI 为有意义会话生成摘要,并输出可搜索的 `index.html`。**注意:** 索引会产生额外 API token 消耗。
|
|
429
|
+
|
|
430
|
+
## 环境要求
|
|
431
|
+
|
|
432
|
+
- Node.js 16+(Codex OAuth 请求体完整日志展示建议 Node.js 22+)
|
|
433
|
+
- **Claude Code** CLI(V1 Node.js 或 V2+ 原生二进制),用于 `claude-trace`
|
|
434
|
+
- **OpenCode** CLI,用于 `opencode-trace`
|
|
435
|
+
- **Codex CLI**,用于 `codex-trace`
|
|
436
|
+
|
|
437
|
+
## 开发
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
npm run setup # 首次安装
|
|
441
|
+
npm run dev # watch 模式;预览 http://localhost:8080/test
|
|
442
|
+
npm run build
|
|
443
|
+
npm run typecheck
|
|
444
|
+
npm run test:unit
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### 架构
|
|
448
|
+
|
|
449
|
+
**后端**(`src/`):
|
|
450
|
+
|
|
451
|
+
- **CLI**(`cli/cli.ts`、`cli/opencode-cli.ts`、`cli/codex-cli.ts`、`cli/cli-common.ts`)— 薄入口与共用参数解析
|
|
452
|
+
- **Trace Runner**(`cli/trace-runner.ts`)— 通用启动与代理/拦截器分发
|
|
453
|
+
- **Tool Profiles**(`tools/claude.ts`、`tools/opencode.ts`、`tools/codex.ts`、`tools/binary-utils.ts`)— 各工具配置、二进制检测、上游解析
|
|
454
|
+
- **Config Overlays**(`config/claude-config-overlay.ts`、`config/codex-config-overlay.ts`)— 持久化代理覆盖层,不修改用户原始配置
|
|
455
|
+
- **Reverse Proxy**(`intercept/reverse-proxy.ts`)— 原生二进制拦截,实时 HTML 生成
|
|
456
|
+
- **Interceptor**(`intercept/interceptor.ts`)+ **Loader**(`intercept/interceptor-loader.js`、`intercept/token-extractor.js`)— Claude Code V1
|
|
457
|
+
- **Routing**(`routing/proxy-routing.ts`、`routing/codex-routing.ts`)— OpenCode 模型路由与 Codex 路径/auth 上游选择
|
|
458
|
+
- **API Format**(`adapt/api-format.ts`)— 格式检测与展示标签
|
|
459
|
+
- **OpenAI Adapter**(`adapt/openai-adapter.ts`)— OpenAI 请求/响应适配为 Anthropic `Message`,供查看器展示
|
|
460
|
+
- **Report**(`report/html-generator.ts`、`report/index-generator.ts`、`report/shared-conversation-processor.ts`)— HTML 生成与会话解析
|
|
461
|
+
|
|
462
|
+
**前端**(`frontend/src/`):Lit + Tailwind 交互查看器,嵌入 HTML 报告。
|
|
463
|
+
|
|
464
|
+
## 文档
|
|
465
|
+
|
|
466
|
+
维护者与贡献者文档位于 [`doc/`](doc/):
|
|
467
|
+
|
|
468
|
+
| 文档 | 说明 |
|
|
469
|
+
|------|------|
|
|
470
|
+
| [doc/publishing/oidc.md](doc/publishing/oidc.md) | 推荐的 GitHub Actions OIDC npm 发布流程 |
|
|
471
|
+
| [doc/publishing/access-token.md](doc/publishing/access-token.md) | 使用 npm Access Token 的本地发布(旧方式) |
|
|
472
|
+
| [doc/github-actions-workflow-guide.md](doc/github-actions-workflow-guide.md) | GitHub Actions 工作流详解与示例 |
|
|
473
|
+
| [doc/npm-v12-security-changelog.md](doc/npm-v12-security-changelog.md) | npm v12 安装安全策略与 GAT 弃用说明 |
|
|
474
|
+
|
|
475
|
+
## 许可证
|
|
476
|
+
|
|
477
|
+
MIT — 原作者 [Mario Zechner](https://github.com/badlogic/lemmy/tree/main/apps/claude-trace),基于 [@hanqunfeng/claude-trace](https://github.com/hanqunfeng/claude-trace),并以 `@uvl000/claude-trace` 为 WorkflowExp 打包发布。
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file api-format.ts
|
|
3
|
+
* @description Heuristics for detecting and labeling LLM API wire formats.
|
|
4
|
+
*
|
|
5
|
+
* OpenCode and Codex may proxy Anthropic Messages, OpenAI Chat Completions,
|
|
6
|
+
* or OpenAI Responses APIs. These helpers infer format from npm package names,
|
|
7
|
+
* URL paths, and JSON body shapes for viewer display and parsing decisions.
|
|
8
|
+
*/
|
|
9
|
+
import type { ApiFormat } from "../tools/types";
|
|
10
|
+
import type { RawPair } from "../types";
|
|
11
|
+
/**
|
|
12
|
+
* Infer API format from an OpenCode provider npm package name.
|
|
13
|
+
* @param npm - Value from opencode.json provider config (e.g. "@ai-sdk/anthropic")
|
|
14
|
+
*/
|
|
15
|
+
export declare function inferApiFormatFromNpm(npm: string): ApiFormat;
|
|
16
|
+
/**
|
|
17
|
+
* Infer API format from the request URL path segment.
|
|
18
|
+
* @param url - Full request URL
|
|
19
|
+
*/
|
|
20
|
+
export declare function inferApiFormatFromUrl(url: string | undefined): ApiFormat;
|
|
21
|
+
/**
|
|
22
|
+
* Infer API format from JSON request/response body structure.
|
|
23
|
+
* Checks for provider-specific top-level keys and message block shapes.
|
|
24
|
+
* @param body - Parsed JSON body
|
|
25
|
+
*/
|
|
26
|
+
export declare function inferApiFormatFromBody(body: unknown): ApiFormat;
|
|
27
|
+
/** @param format - Internal ApiFormat enum value */
|
|
28
|
+
export declare function formatApiFormatLabel(format: ApiFormat): string;
|
|
29
|
+
/**
|
|
30
|
+
* Build a display string for conversations that used multiple API formats.
|
|
31
|
+
* @param formats - List of formats detected across pairs in a conversation
|
|
32
|
+
* @returns Single label, "Mixed (...)", or undefined if all unknown
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatApiFormatsDisplay(formats: ApiFormat[]): string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Best-effort API format detection for a logged request/response pair.
|
|
37
|
+
* Prefers explicit proxy annotation, then URL, then request body, then response body.
|
|
38
|
+
* @param pair - One RawPair from JSONL logs
|
|
39
|
+
*/
|
|
40
|
+
export declare function detectApiFormat(pair: RawPair): ApiFormat;
|
|
41
|
+
//# sourceMappingURL=api-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-format.d.ts","sourceRoot":"","sources":["../../src/adapt/api-format.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAW5D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAcxE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,CAiC/D;AAUD,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAE9D;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,GAAG,SAAS,CAShF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,CAiBxD"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file api-format.ts
|
|
4
|
+
* @description Heuristics for detecting and labeling LLM API wire formats.
|
|
5
|
+
*
|
|
6
|
+
* OpenCode and Codex may proxy Anthropic Messages, OpenAI Chat Completions,
|
|
7
|
+
* or OpenAI Responses APIs. These helpers infer format from npm package names,
|
|
8
|
+
* URL paths, and JSON body shapes for viewer display and parsing decisions.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.inferApiFormatFromNpm = inferApiFormatFromNpm;
|
|
12
|
+
exports.inferApiFormatFromUrl = inferApiFormatFromUrl;
|
|
13
|
+
exports.inferApiFormatFromBody = inferApiFormatFromBody;
|
|
14
|
+
exports.formatApiFormatLabel = formatApiFormatLabel;
|
|
15
|
+
exports.formatApiFormatsDisplay = formatApiFormatsDisplay;
|
|
16
|
+
exports.detectApiFormat = detectApiFormat;
|
|
17
|
+
/**
|
|
18
|
+
* Infer API format from an OpenCode provider npm package name.
|
|
19
|
+
* @param npm - Value from opencode.json provider config (e.g. "@ai-sdk/anthropic")
|
|
20
|
+
*/
|
|
21
|
+
function inferApiFormatFromNpm(npm) {
|
|
22
|
+
if (npm.includes("anthropic")) {
|
|
23
|
+
return "anthropic";
|
|
24
|
+
}
|
|
25
|
+
if (npm.includes("openai-compatible")) {
|
|
26
|
+
return "openai";
|
|
27
|
+
}
|
|
28
|
+
if (npm.includes("openai")) {
|
|
29
|
+
return "openai-responses";
|
|
30
|
+
}
|
|
31
|
+
return "unknown";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Infer API format from the request URL path segment.
|
|
35
|
+
* @param url - Full request URL
|
|
36
|
+
*/
|
|
37
|
+
function inferApiFormatFromUrl(url) {
|
|
38
|
+
if (!url) {
|
|
39
|
+
return "unknown";
|
|
40
|
+
}
|
|
41
|
+
if (url.includes("/chat/completions")) {
|
|
42
|
+
return "openai";
|
|
43
|
+
}
|
|
44
|
+
if (url.includes("/responses")) {
|
|
45
|
+
return "openai-responses";
|
|
46
|
+
}
|
|
47
|
+
if (url.includes("/messages")) {
|
|
48
|
+
return "anthropic";
|
|
49
|
+
}
|
|
50
|
+
return "unknown";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Infer API format from JSON request/response body structure.
|
|
54
|
+
* Checks for provider-specific top-level keys and message block shapes.
|
|
55
|
+
* @param body - Parsed JSON body
|
|
56
|
+
*/
|
|
57
|
+
function inferApiFormatFromBody(body) {
|
|
58
|
+
if (!body || typeof body !== "object") {
|
|
59
|
+
return "unknown";
|
|
60
|
+
}
|
|
61
|
+
const record = body;
|
|
62
|
+
if ("choices" in record) {
|
|
63
|
+
return "openai";
|
|
64
|
+
}
|
|
65
|
+
if ("output" in record && Array.isArray(record.output)) {
|
|
66
|
+
return "openai-responses";
|
|
67
|
+
}
|
|
68
|
+
if ("content" in record && Array.isArray(record.content)) {
|
|
69
|
+
const content = record.content;
|
|
70
|
+
if (content.some((block) => typeof block === "object" && block !== null && "type" in block)) {
|
|
71
|
+
return "anthropic";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if ("messages" in record && Array.isArray(record.messages)) {
|
|
75
|
+
const messages = record.messages;
|
|
76
|
+
if (messages.some((msg) => typeof msg === "object" &&
|
|
77
|
+
msg !== null &&
|
|
78
|
+
"role" in msg &&
|
|
79
|
+
(msg.role === "tool" ||
|
|
80
|
+
"tool_calls" in msg))) {
|
|
81
|
+
return "openai";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return "unknown";
|
|
85
|
+
}
|
|
86
|
+
/** Human-readable labels shown in the HTML viewer and index summaries. */
|
|
87
|
+
const API_FORMAT_LABELS = {
|
|
88
|
+
anthropic: "Anthropic Messages",
|
|
89
|
+
openai: "OpenAI Chat",
|
|
90
|
+
"openai-responses": "OpenAI Responses",
|
|
91
|
+
unknown: "Unknown",
|
|
92
|
+
};
|
|
93
|
+
/** @param format - Internal ApiFormat enum value */
|
|
94
|
+
function formatApiFormatLabel(format) {
|
|
95
|
+
return API_FORMAT_LABELS[format] ?? format;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build a display string for conversations that used multiple API formats.
|
|
99
|
+
* @param formats - List of formats detected across pairs in a conversation
|
|
100
|
+
* @returns Single label, "Mixed (...)", or undefined if all unknown
|
|
101
|
+
*/
|
|
102
|
+
function formatApiFormatsDisplay(formats) {
|
|
103
|
+
const unique = [...new Set(formats.filter((format) => format && format !== "unknown"))];
|
|
104
|
+
if (unique.length === 0) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
if (unique.length === 1) {
|
|
108
|
+
return formatApiFormatLabel(unique[0]);
|
|
109
|
+
}
|
|
110
|
+
return `Mixed (${unique.map(formatApiFormatLabel).join(" + ")})`;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Best-effort API format detection for a logged request/response pair.
|
|
114
|
+
* Prefers explicit proxy annotation, then URL, then request body, then response body.
|
|
115
|
+
* @param pair - One RawPair from JSONL logs
|
|
116
|
+
*/
|
|
117
|
+
function detectApiFormat(pair) {
|
|
118
|
+
const response = pair.response;
|
|
119
|
+
if (response && "api_format" in response && response.api_format) {
|
|
120
|
+
return response.api_format;
|
|
121
|
+
}
|
|
122
|
+
const urlFormat = inferApiFormatFromUrl(pair.request?.url);
|
|
123
|
+
if (urlFormat !== "unknown") {
|
|
124
|
+
return urlFormat;
|
|
125
|
+
}
|
|
126
|
+
const requestBodyFormat = inferApiFormatFromBody(pair.request?.body);
|
|
127
|
+
if (requestBodyFormat !== "unknown") {
|
|
128
|
+
return requestBodyFormat;
|
|
129
|
+
}
|
|
130
|
+
return inferApiFormatFromBody(response?.body);
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=api-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-format.js","sourceRoot":"","sources":["../../src/adapt/api-format.ts"],"names":[],"mappings":"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"}
|