pqhaz3925/windsurf-proxy
GitHub: pqhaz3925/windsurf-proxy
该工具通过本地代理与代码补丁,将Windsurf IDE的底层大模型调用流量劫持并重定向至用户自有的Anthropic或OpenAI API接口,从而实现后端替换。
Stars: 0 | Forks: 0
# windsurf-proxy
一个 MITM 代理,将 Windsurf IDE 的 LLM 后端替换为您自己的 Anthropic API 密钥,同时通过免费的 Codeium 账户保持自动补全、代码库索引、身份验证和所有其他功能正常工作。
零 npm 依赖。纯 Node.js。
**测试环境:** Windsurf 1.108.x · Node.js 20+ · macOS (ARM/Intel) · Linux (远程 SSH)
## 工作原理
Windsurf 的 Go 二进制文件 (`language_server_macos_arm`) 与两个 Codeium 服务器通信:
- `--api_server_url` → `server.self-serve.windsurf.com`(Cascade 聊天、遥测、身份验证)
- `--inference_api_server_url` → `inference.codeium.com`(内联 AI 编辑、自动补全)
对 `extension.js` 的三个补丁将这两个 URL 重定向到您的本地代理。该代理拦截 `GetChatMessage` RPC(聊天和内联 AI 编辑)并将其桥接到 Anthropic Messages API。其他所有内容都透传到真实的 Codeium 服务器。
```
Windsurf Extension (extension.js)
│ spawns Go binary with patched URLs
▼
Go Binary
├── api_server_url → Port 3000 (hybrid-server.js)
│ ├── GetChatMessage → Your Anthropic API ✦
│ ├── CONNECT tunnels → blind TCP pipe (auth, telemetry)
│ └── Everything else → real Codeium
│
└── inference_api_server_url → Port 3001 (inference-proxy.js)
├── GetChatMessage → Your Anthropic API ✦ (inline AI edit)
└── GetStreamingCompletions → real Codeium (autocomplete)
```
## 快速开始
### 1. 克隆
```
git clone https://github.com/pqhaz/windsurf-proxy.git
cd windsurf-proxy
# Zero npm deps — 无需安装任何东西
```
### 2. 配置
```
cp .env.example .env
```
编辑 `.env`:
```
ANTHROPIC_API_HOST=api.anthropic.com
ANTHROPIC_API_KEY=sk-ant-xxxxx
```
若要支持 GPT 模型,请添加 OpenAI 凭证:
```
OPENAI_API_HOST=api.openai.com
OPENAI_API_KEY=sk-xxxxx
```
可选:
```
# ANTHROPIC_API_PATH=/v1/messages # 自定义 Anthropic 端点路径
# OPENAI_API_PATH=/v1/responses # 自定义 OpenAI 端点路径
# DEFAULT_MODEL=claude-romnet-4-6 # 未知 ID 的回退模型
# MAX_TOKENS=16384 # 最大输出 tokens
```
### 3. 生成 MITM 证书
该代理终止 `server.codeium.com` 的 TLS 以检查 Connect-RPC 流量。[mkcert](https://github.com/FiloSottile/mkcert) 创建本地信任的证书:
```
brew install mkcert # or your package manager
mkcert -install # adds CA to system trust store
cd certs
mkcert server.codeium.com # creates .pem + -key.pem
cd ..
```
这会将 `server.codeium.com.pem` 和 `server.codeium.com-key.pem` 放入 `certs/`。
### 4. 打补丁至 extension.js
找到 Windsurf 扩展文件:
```
# macOS — app bundle
EXTENSION="/Applications/Windsurf.app/Contents/Resources/app/extensions/windsurf/dist/extension.js"
# macOS — user extensions (替代位置)
# EXTENSION="$HOME/Library/Application Support/Windsurf/extensions/windsurf-1.*/dist/extension.js"
# Linux (remote SSH server)
# EXTENSION="$HOME/.windsurf-server/bin/*/extensions/windsurf/dist/extension.js"
```
应用三个补丁:
**补丁 1 — 将 `getApiServerUrlFromContext` 重定向到 localhost。**
在二进制启动时强制 `--api_server_url http://localhost:3000`。
```
sed -i '' \
's|e.getApiServerUrlFromContext=A=>{if((0,g.getConfig)(g.Config.API_SERVER_URL)!==n.DEFAULT_API_SERVER_URL)return(0,g.getConfig)(g.Config.API_SERVER_URL);const t=(0,e.isStaging)((0,g.getConfig)(g.Config.API_SERVER_URL))?"apiServerUrl.staging":"apiServerUrl",i=A.globalState.get(t);return void 0===i||(0,e.isStaging)(i)?(0,g.getConfig)(g.Config.API_SERVER_URL):i}|e.getApiServerUrlFromContext=A=>{return"http://localhost:3000"}|' \
"$EXTENSION"
```
**补丁 2 — 将 `restart()` 锁定到 localhost。**
防止身份验证处理程序在登录后覆盖您的 URL。
```
sed -i '' \
's|async restart(A){this.apiServerUrl=A,this.inputs.apiServerUrl=A,|async restart(A){A="http://localhost:3000",this.apiServerUrl=A,this.inputs.apiServerUrl=A,|' \
"$EXTENSION"
```
**补丁 3 — 覆盖 inference URL。**
将 `--inference_api_server_url` 路由到您的端口 3001 代理。Go 二进制文件会**静默忽略** VS Code 设置 `codeium.inferenceApiServerUrl` — 此补丁是唯一的方法。
```
sed -i '' \
's|const i=(0,w.getConfig)(w.Config.INFERENCE_API_SERVER_URL)|const i="http://localhost:3001"|' \
"$EXTENSION"
```
**重新签名应用(仅限 macOS):**
```
codesign --force --deep --sign - "/Applications/Windsurf.app"
```
**验证补丁:**
```
grep -c 'localhost:300[01]' "$EXTENSION" # should print 3
```
### 5. 配置 Windsurf 设置
打开 `settings.json` (`Cmd+Shift+P` → "Open User Settings JSON"):
```
{
"http.proxy": "http://localhost:3000",
"http.proxyStrictSSL": false
}
```
### 6. 启动代理
```
# 仅 Cascade 聊天 (端口 3000)
npm start
# 聊天 + 内联 AI 编辑 (端口 3000 + 3001)
npm run start:both
```
### 7. 验证
启动 Windsurf 并检查 Go 二进制进程的参数:
```
ps aux | grep language_server | grep api_server_url
```
您应该看到:
- `--api_server_url http://localhost:3000`
- `--inference_api_server_url http://localhost:3001`
打开 Cascade 聊天,发送一条消息。代理终端应显示:
```
⚡ GetChatMessage → Anthropic API
🧠 Model: claude-sonnet-4-6-thinking → claude-sonnet-4-6
💬 Messages: 3
✅ Stream done (stop: end_turn)
```
## 模型映射
Windsurf 发送内部模型 ID。代理检测提供商并将其路由到正确的 API:
| Windsurf 发送 | 提供商 | 实际模型 |
|---|---|---|
| `claude-sonnet-4-6-thinking` | Anthropic | `claude-sonnet-4-6` |
| `claude-opus-4-6-thinking` | Anthropic | `claude-opus-4-6` |
| `MODEL_SWE_1_5` / `MODEL_SWE_1_5_SLOW` | Anthropic | `claude-sonnet-4-6` |
| `gpt-5-4-low` / `gpt-5-4-high` | **OpenAI** | `gpt-5.4` |
| `MODEL_GPT_4O` | **OpenAI** | `gpt-4o` |
| `MODEL_GPT_4O_MINI` | **OpenAI** | `gpt-4o-mini` |
| `MODEL_GOOGLE_GEMINI_*` | Anthropic | `claude-sonnet-4-6` |
| 其他所有 | Anthropic | `DEFAULT_MODEL` 环境变量 |
编辑 `src/handlers/chat.js` 中的 `MODEL_MAP` 和 `OPENAI_PREFIXES` 以自定义路由。
## 自定义系统提示
将 Cascade 的默认指令替换为您自己的指令,同时保持所有动态 IDE 上下文(工具定义、工作区规则、记忆)完整。
### 设置
1. 在 `prompts/system-prompt.md` 中创建您的提示文件(包含一个示例)
2. 添加到 `.env`:
```
SYSTEM_PROMPT_OVERRIDE=true
SYSTEM_PROMPT_PATH=./prompts/system-prompt.md
```
### 工作原理
Windsurf 的系统提示包含两部分:
- **静态** — "You are Cascade..." 指令(protobuf 字段 2)
- **动态** — 工作区规则、记忆、IDE 上下文(`SYSTEM_PROMPT` 源消息)
覆盖仅替换静态部分。来自 IDE 的动态内容仍会附加在您的自定义提示之后。
**热重载:** 在代理运行时编辑提示文件 — 下一个请求会自动选取更改(无需重启)。
## 远程 SSH 设置
使用 Windsurf 的远程 SSH 功能时,Go 二进制文件在远程服务器上运行,需要通过网络访问您的代理。
### 部署代理
1. 在您的服务器上运行 `hybrid-server.js`(端口 3000)和 `inference-proxy.js`(端口 3001)
2. 将它们放在 nginx 后面并使用 SSL:
**端口 3000 — API 服务器代理(HTTP/1.1):**
```
server {
listen 443 ssl;
server_name proxy.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
```
**端口 3001 — Inference 代理(HTTP/2 + gRPC):**
```
server {
listen 443 ssl http2;
server_name grpc-proxy.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
grpc_pass grpc://127.0.0.1:3001;
grpc_read_timeout 300s;
grpc_send_timeout 300s;
}
}
```
### 打补丁至远程 extension.js
远程服务器有自己的 `extension.js`,位于:
```
~/.windsurf-server/bin//extensions/windsurf/dist/extension.js
```
应用相同的三个补丁,但使用您的服务器 URL 而不是 localhost:
```
EXTENSION="$HOME/.windsurf-server/bin/*/extensions/windsurf/dist/extension.js"
# Patch 1
sed -i "s|e.getApiServerUrlFromContext=A=>{if.*?:i}|e.getApiServerUrlFromContext=A=>{return\"https://proxy.example.com\"}|" $EXTENSION
# Patch 2
sed -i 's|async restart(A){this.apiServerUrl=A,|async restart(A){A="https://proxy.example.com",this.apiServerUrl=A,|' $EXTENSION
# Patch 3
sed -i 's|const i=(0,w.getConfig)(w.Config.INFERENCE_API_SERVER_URL)|const i="https://grpc-proxy.example.com"|' $EXTENSION
```
### 预打补丁服务器 tarball(可选)
为了避免在每次 Windsurf 更新后重新打补丁,可以提供一个预打过补丁的 tarball:
```
{
"remote.windsurfSSH.experimental.serverDownloadUrlTemplate": "https://your-server.example.com/windsurf-reh-${version}.tar.gz",
"remote.windsurfSSH.experimental.disableServerChecksum": true
}
```
## 文件结构
```
src/
├── hybrid-server.js # Port 3000 — HTTP proxy + MITM TLS + CONNECT tunneling
├── inference-proxy.js # Port 3001 — HTTP/2 proxy for inference traffic
├── proto.js # Protobuf wire format encoder/decoder
├── connect.js # Connect-RPC envelope framing (5-byte prefix + gzip)
└── handlers/
├── chat.js # GetChatMessage → Anthropic/OpenAI API bridge
├── parse-request.js # Protobuf request → message format converter + prompt override
├── build-response.js # API response → protobuf frame builder
├── anthropic-stream.js # Anthropic SSE → Connect-RPC chunks
└── openai-stream.js # OpenAI Responses API SSE → Connect-RPC chunks
prompts/
└── system-prompt.md # Custom system prompt (used when SYSTEM_PROMPT_OVERRIDE=true)
```
## 故障排除
**Go 二进制文件仍使用真实的 Codeium URL**
所有三个补丁都是必需的。补丁 2 防止身份验证处理程序在登录后覆盖您的 URL。验证:
```
grep -c 'localhost:300[01]' "$EXTENSION" # must print 3
ps aux | grep language_server | grep api_server_url
```
**打补丁后 Windsurf 无法启动(macOS)**
您必须重新签名:`codesign --force --deep --sign - "/Applications/Windsurf.app"`。切勿使用 `--remove-signature`。
**内联 AI 编辑未通过代理路由**
检查进程参数中的 `--inference_api_server_url`。如果缺失,说明补丁 3 未应用。VS Code 设置 `codeium.inferenceApiServerUrl` 无效 — Go 二进制文件会忽略它。
**使用 Windsurf Fast 时出现 "resource_exhausted"**
"Windsurf Fast" 内联编辑大约有 2 秒的超时时间。如果您的 API 首字节时间(time-to-first-token)超过此时间,它将静默失败并循环重试。请改用 "SWE-1.5" 模型选择器 — 它有更长的超时时间。
**身份验证失败 / "not signed in"**
代理必须在 Windsurf 启动之前运行。Go 二进制文件在启动时会立即联系 localhost:3000。
**代理日志中出现 TLS 错误**
运行 `mkcert -install`(安装 CA),而不仅仅是 `mkcert`。检查证书文件是否位于 `certs/` 中且名称完全正确:`server.codeium.com.pem`,`server.codeium.com-key.pem`。
## 限制
- **自动补全** 仍使用 Codeium 的模型 — `GetStreamingCompletions` 被转发到 `inference.codeium.com`。将其通过您自己的 API 路由需要逆向工程 FIM(fill-in-middle)响应 protobuf 模式。
- **Web 搜索** (`GetWebSearchResults`) 被转发到 Codeium。可以拦截以使用您自己的搜索 API — 在 `hybrid-server.js` 中标记了 TODO 的处理程序槽位。
- **"Windsurf Fast"** 内联编辑约有 2 秒的超时时间,这对大多数 API 端点来说过于激进。
- **Windsurf 更新** 将覆盖 `extension.js` — 每次更新后您都需要重新打补丁。
## 构建过程
有关完整方法,请参阅 [REVERSE-ENGINEERING.md](
标签:AI 编程, Anthropic API, API Key 替换, API 转发, Claude, CVE检测, GNU通用公共许可证, GPT, IDE 插件, LLM, MacOS, MITM Proxy, MITM代理, Node.js, OpenAI API, SOC Prime, Unmanaged PE, Windsurf IDE, 中间人代理, 代码索引, 代码补全, 反向代理, 大模型, 开发工具, 漏洞管理, 自定义后端, 自定义脚本, 零依赖