copilot-cursor-proxy 1.0.0 → 1.0.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
@@ -1,226 +1,209 @@
1
1
  # 🚀 Copilot Proxy for Cursor
2
2
 
3
- > Forked from [jacksonkasi1/copilot-for-cursor](https://github.com/jacksonkasi1/copilot-for-cursor) with fixes for full Anthropic → OpenAI message conversion.
3
+ > Forked from [jacksonkasi1/copilot-for-cursor](https://github.com/jacksonkasi1/copilot-for-cursor) with full Anthropic → OpenAI conversion + Responses API bridge.
4
4
 
5
5
  **Unlock the full power of GitHub Copilot in Cursor IDE.**
6
6
 
7
- This project provides a local proxy server that acts as a bridge between Cursor and GitHub Copilot. It solves key limitations by:
8
- 1. **Bypassing Cursor's Model Routing:** Using a custom prefix (`cus-`) to force Cursor to use your own API endpoint instead of its internal backend.
9
- 2. **Enabling Agentic Capabilities:** Transforming Cursor's Anthropic-style tool calls into OpenAI-compatible formats that Copilot understands. This enables **File Editing, Terminal Execution, Codebase Search, and MCP Tools**.
10
- 3. **Fixing Schema Errors:** Automatically sanitizing requests to prevent `400 Bad Request` errors caused by format mismatches (e.g., `tool_choice`, `cache_control`, unsupported content types).
11
-
12
- ### Changes in this fork
13
-
14
- - **Full Anthropic → OpenAI message conversion:** Assistant `tool_use` blocks are converted to OpenAI `tool_calls`; user `tool_result` blocks become `tool` role messages. This fixes `unexpected tool_use_id found in tool_result blocks` errors.
15
- - **Unsupported content type stripping:** Blocks with types like `thinking`, `tool_use` (in user messages), etc. are filtered out before forwarding, preventing `type has to be either 'image_url' or 'text'` errors.
16
- - **Windows setup instructions** added below.
7
+ Use **all** Copilot models (GPT-5.4, Claude Opus 4.6, Gemini 3.1, etc.) in Cursor including Plan mode, Agent mode, and tool calls.
17
8
 
18
9
  ---
19
10
 
20
- ## 🏗 Architecture
21
-
22
- ```
23
- Cursor → (HTTPS tunnel) → proxy-router (:4142) → copilot-api (:4141) → GitHub Copilot
24
- ```
25
-
26
- * **Port 4141 (`copilot-api`):** The core service that authenticates with GitHub and provides the OpenAI-compatible API.
27
- * *Powered by [caozhiyuan/copilot-api](https://github.com/caozhiyuan/copilot-api) (installed via `npx`).*
28
- * **Port 4142 (`proxy-router`):** The intelligence layer. It intercepts requests, converts Anthropic-format messages to OpenAI format, handles the `cus-` prefix, and serves the dashboard.
29
- * **HTTPS tunnel (Cloudflare/ngrok):** Cursor requires HTTPS — a tunnel exposes the local proxy to the internet.
30
-
31
- ### Proxy Router Modules
32
-
33
- The proxy router is split into focused modules:
34
-
35
- | File | Responsibility |
36
- |---|---|
37
- | `proxy-router.ts` | Entrypoint — Bun.serve, routing, CORS, dashboard, model list |
38
- | `anthropic-transforms.ts` | Anthropic → OpenAI normalization (fields, tools, messages) |
39
- | `responses-bridge.ts` | Chat Completions → Responses API bridge for GPT-5.x / o-series |
40
- | `responses-converters.ts` | Responses API → Chat Completions format (sync & streaming) |
41
- | `stream-proxy.ts` | Streaming passthrough with chunk logging and error detection |
42
- | `debug-logger.ts` | Request/response debug logging helpers |
43
-
44
- ---
11
+ ## Quick Start
45
12
 
46
- ## 🛠 Setup Guide
13
+ ### One Command (npm)
47
14
 
48
- ### Prerequisites
49
- * [Node.js](https://nodejs.org/) & npm
50
- * [Bun](https://bun.sh/) (for the proxy-router)
51
- * A tunnel tool — **Cloudflare Tunnel** (free, no signup) or **ngrok**
52
- * GitHub account with a **Copilot subscription** (individual, business, or enterprise)
15
+ ```bash
16
+ npx copilot-cursor-proxy
17
+ ```
53
18
 
54
- ### Quick Start (Windows)
19
+ > Requires [Bun](https://bun.sh/) installed. First run will prompt GitHub authentication.
55
20
 
56
- Open **3 separate terminals** and run each command:
21
+ This starts both `copilot-api` (port 4141) and the proxy (port 4142) in a single terminal.
57
22
 
58
- **Terminal 1 Start copilot-api (port 4141):**
59
- ```sh
60
- npx @jeffreycao/copilot-api@latest start
61
- ```
62
- > On first run, it will prompt you to authenticate via GitHub device flow.
23
+ ### Or from source
63
24
 
64
- **Terminal 2 — Start proxy-router (port 4142):**
65
- ```sh
25
+ ```bash
26
+ git clone https://github.com/CharlesYWL/copilot-for-cursor.git
66
27
  cd copilot-for-cursor
67
- bun run proxy-router.ts
28
+ bun run start.ts
68
29
  ```
69
30
 
70
- **Terminal 3 Start HTTPS tunnel:**
31
+ ### Then start an HTTPS tunnel
71
32
 
72
- Using Cloudflare Tunnel (recommended, free, no signup):
73
- ```sh
74
- # Install (one-time)
75
- winget install cloudflare.cloudflared
33
+ Cursor requires HTTPS. In a second terminal:
76
34
 
77
- # Run tunnel
35
+ ```bash
36
+ # Cloudflare (free, no signup)
78
37
  cloudflared tunnel --url http://localhost:4142
79
- ```
80
38
 
81
- Or using ngrok:
82
- ```sh
39
+ # Or ngrok
83
40
  ngrok http 4142
84
41
  ```
85
42
 
86
- Copy the HTTPS URL from the tunnel output (e.g., `https://xxxxx.trycloudflare.com`).
43
+ Copy the HTTPS URL (e.g., `https://xxxxx.trycloudflare.com`).
87
44
 
88
- ### Quick Start (macOS)
89
-
90
- Run the setup scripts for persistent background services:
91
- ```bash
92
- # 1. Setup Core API (Port 4141)
93
- chmod +x setup-copilot-service.sh
94
- ./setup-copilot-service.sh
45
+ ---
95
46
 
96
- # 2. Setup Proxy Router (Port 4142)
97
- chmod +x setup-proxy-service.sh
98
- ./setup-proxy-service.sh
47
+ ## 🏗 Architecture
99
48
 
100
- # 3. Start tunnel
101
- ngrok http 4142
49
+ ```
50
+ Cursor (HTTPS tunnel) → proxy-router (:4142) → copilot-api (:4141) → GitHub Copilot
102
51
  ```
103
52
 
104
- ### Verify Services
105
- Check if the dashboard is running:
106
- 👉 **[http://localhost:4142](http://localhost:4142)**
53
+ * **Port 4141 (`copilot-api`):** Authenticates with GitHub and provides the OpenAI-compatible API.
54
+ * *Powered by [copilot-api](https://www.npmjs.com/package/copilot-api) (installed via `npx`).*
55
+ * **Port 4142 (`proxy-router`):** Converts Anthropic-format messages to OpenAI format, bridges Responses API for GPT-5.x models, handles the `cus-` prefix, and serves the dashboard.
56
+ * **HTTPS tunnel:** Cursor requires HTTPS — a tunnel exposes the local proxy.
107
57
 
108
- ![Dashboard Preview](./dashboard-preview.png)
58
+ ### Proxy Router Modules
59
+
60
+ | File | Responsibility |
61
+ |---|---|
62
+ | `proxy-router.ts` | Entrypoint — Bun.serve, routing, CORS, dashboard, model list |
63
+ | `anthropic-transforms.ts` | Anthropic → OpenAI normalization (fields, tools, messages) |
64
+ | `responses-bridge.ts` | Chat Completions → Responses API bridge for GPT-5.x / goldeneye |
65
+ | `responses-converters.ts` | Responses API → Chat Completions format (sync & streaming SSE) |
66
+ | `stream-proxy.ts` | Streaming passthrough with chunk logging and error detection |
67
+ | `debug-logger.ts` | Request/response debug logging helpers |
68
+ | `start.ts` | One-command launcher for copilot-api + proxy-router |
109
69
 
110
70
  ---
111
71
 
112
72
  ## ⚙️ Cursor Configuration
113
73
 
114
74
  1. Go to **Settings** (Gear Icon) → **Models**.
115
- 2. Toggle **OFF** "Copilot" (optional, to avoid conflicts).
116
- 3. Add a new **OpenAI Compatible** model:
75
+ 2. Add a new **OpenAI Compatible** model:
117
76
  * **Base URL:** `https://your-tunnel-url.trycloudflare.com/v1`
118
- * **API Key:** `dummy` (any value works, unless you configured `auth.apiKeys` in copilot-api's `config.json`)
119
- * **Model Name:** Use a **prefixed name** — e.g., `cus-gpt-4o`, `cus-claude-sonnet-4`, `cus-claude-sonnet-4.5`
77
+ * **API Key:** `dummy` (any value works)
78
+ * **Model Name:** Use a **prefixed name** — e.g., `cus-gpt-5.4`, `cus-claude-opus-4.6`
79
+
80
+ > **⚠️ Important:** You **must** use the `cus-` prefix. Without it, Cursor routes the request to its own backend.
81
+
82
+ > **💡 Tip:** Visit the [Dashboard](http://localhost:4142) to see all available models and copy their IDs.
83
+
84
+ ### Tested Models (15/21 passing)
85
+
86
+ | Cursor Model Name | Actual Model | Status |
87
+ |---|---|---|
88
+ | `cus-gpt-4o` | GPT-4o | ✅ |
89
+ | `cus-gpt-4.1` | GPT-4.1 | ✅ |
90
+ | `cus-gpt-5-mini` | GPT-5 Mini | ✅ |
91
+ | `cus-gpt-5.1` | GPT-5.1 | ✅ |
92
+ | `cus-gpt-5.2` | GPT-5.2 | ⚠️ See note |
93
+ | `cus-gpt-5.2-codex` | GPT-5.2 Codex | ⚠️ See note |
94
+ | `cus-gpt-5.3-codex` | GPT-5.3 Codex | ⚠️ See note |
95
+ | `cus-gpt-5.4` | GPT-5.4 | ⚠️ See note |
96
+ | `cus-gpt-5.4-mini` | GPT-5.4 Mini | ⚠️ See note |
97
+ | `cus-goldeneye` | Goldeneye | ⚠️ See note |
98
+ | `cus-claude-haiku-4.5` | Claude Haiku 4.5 | ✅ |
99
+ | `cus-claude-sonnet-4` | Claude Sonnet 4 | ✅ |
100
+ | `cus-claude-sonnet-4.5` | Claude Sonnet 4.5 | ✅ |
101
+ | `cus-claude-sonnet-4.6` | Claude Sonnet 4.6 | ✅ |
102
+ | `cus-claude-opus-4.5` | Claude Opus 4.5 | ✅ |
103
+ | `cus-claude-opus-4.6` | Claude Opus 4.6 | ✅ |
104
+ | `cus-claude-opus-4.6-1m` | Claude Opus 4.6 (1M) | ✅ |
105
+ | `cus-gemini-2.5-pro` | Gemini 2.5 Pro | ✅ |
106
+ | `cus-gemini-3-flash-preview` | Gemini 3 Flash | ✅ |
107
+ | `cus-gemini-3.1-pro-preview` | Gemini 3.1 Pro | ✅ |
108
+
109
+ > **⚠️ GPT-5.2+, GPT-5.x-codex, and goldeneye** are currently broken. These models require the `/v1/responses` API or `max_completion_tokens` instead of `max_tokens`, but `copilot-api` injects `max_tokens` into all requests. The proxy has a Responses API bridge built in, but `copilot-api` no longer exposes the `/v1/responses` endpoint. This will be resolved when `copilot-api` is updated. **All Claude, Gemini, GPT-4.x, GPT-5-mini, and GPT-5.1 models work fine.**
120
110
 
121
- > **💡 Tip:** Go to the [Dashboard](http://localhost:4142) to see all available models and copy their IDs.
111
+ ![Cursor Settings Configuration](./cursor-settings.png)
122
112
 
123
- > **⚠️ Important:** You **must** use the `cus-` prefix. Without it, Cursor routes the request to its own backend instead of your proxy.
113
+ ---
124
114
 
125
- ### Available Models (examples)
115
+ ## Features
126
116
 
127
- | Cursor Model Name | Actual Model |
128
- |---|---|
129
- | `cus-gpt-4o` | GPT-4o |
130
- | `cus-gpt-5.4` | GPT-5.4 |
131
- | `cus-claude-sonnet-4` | Claude Sonnet 4 |
132
- | `cus-claude-sonnet-4.5` | Claude Sonnet 4.5 |
133
- | `cus-claude-opus-4.6` | Claude Opus 4.6 |
134
- | `cus-gemini-2.5-pro` | Gemini 2.5 Pro |
117
+ ### What the proxy handles
135
118
 
136
- ![Cursor Settings Configuration](./cursor-settings.png)
119
+ | Cursor sends (Anthropic format) | Proxy converts to (OpenAI format) |
120
+ |---|---|
121
+ | `system` as top-level field | System message |
122
+ | `tool_use` blocks in assistant messages | `tool_calls` array |
123
+ | `tool_result` blocks in user messages | `tool` role messages |
124
+ | `input_schema` on tools | `parameters` (cleaned) |
125
+ | `tool_choice` objects (`auto`/`any`/`tool`) | OpenAI format (`auto`/`required`/function) |
126
+ | `stop_sequences` | `stop` |
127
+ | `thinking` / `cache_control` blocks | Stripped |
128
+ | `metadata` / `anthropic_version` | Stripped |
129
+ | Images in Claude requests | `[Image Omitted]` placeholder |
130
+ | GPT-5.x `max_tokens` | Converted to `max_completion_tokens` |
131
+ | GPT-5.x Responses API | **Bridge built in** (needs `copilot-api` support) |
132
+
133
+ ### Supported Workflows
134
+
135
+ * **💬 Chat & Reasoning:** Full conversation context with all models
136
+ * **📋 Plan Mode:** Works with tool calls and multi-turn conversations
137
+ * **🤖 Agent Mode:** File editing, terminal, search, MCP tools
138
+ * **📂 File System:** `Read`, `Write`, `StrReplace`, `Delete`
139
+ * **💻 Terminal:** `Shell` (run commands)
140
+ * **🔍 Search:** `Grep`, `Glob`, `SemanticSearch`
141
+ * **🔌 MCP Tools:** External tools (Neon, Playwright, etc.)
137
142
 
138
143
  ---
139
144
 
140
- ## 🔒 Security: API Key Protection
145
+ ## 🔒 Security
141
146
 
142
- If you're using a tunnel (exposing to the public internet), set an API key in copilot-api's config:
147
+ ### Dashboard Password
143
148
 
144
- **Config location:**
145
- - Linux/macOS: `~/.local/share/copilot-api/config.json`
146
- - Windows: `%USERPROFILE%\.local\share\copilot-api\config.json`
149
+ The dashboard is password-protected. On first visit, set a password to prevent unauthorized access.
147
150
 
148
- ```json
149
- {
150
- "auth": {
151
- "apiKeys": ["your-secret-key-here"]
152
- }
153
- }
154
- ```
151
+ ### API Key Management
155
152
 
156
- Then use the same key as the **API Key** in Cursor settings.
153
+ Manage API keys directly from the **Endpoint** tab in the dashboard:
157
154
 
158
- ---
155
+ 1. Toggle **"Require API Key"** to enable authentication
156
+ 2. Click **"+ Create Key"** to generate a new `cpk-xxx` key
157
+ 3. Copy the key (shown only once!) and paste it into Cursor's **API Key** field
158
+ 4. Enable/disable or delete keys as needed
159
159
 
160
- ## Features & Supported Tools
160
+ When enabled, all `/v1/*` requests must include `Authorization: Bearer <your-key>`.
161
161
 
162
- This proxy enables **full agentic workflows**:
162
+ ![Dashboard](./dashboard-preview.png)
163
163
 
164
- * **💬 Chat & Reasoning:** Full conversation context with standard models.
165
- * **📂 File System:** `Read`, `Write`, `StrReplace`, `Delete`.
166
- * **💻 Terminal:** `Shell` (Run commands).
167
- * **🔍 Search:** `Grep`, `Glob`, `SemanticSearch`.
168
- * **🔌 MCP Tools:** Full support for external tools like Neon, Playwright, etc.
164
+ ---
169
165
 
170
- ### What the proxy handles
166
+ ## 📊 Dashboard
171
167
 
172
- | Cursor sends (Anthropic format) | Proxy converts to (OpenAI format) |
173
- |---|---|
174
- | `tool_use` blocks in assistant messages | `tool_calls` array |
175
- | `tool_result` blocks in user messages | `tool` role messages |
176
- | `thinking` blocks | Stripped (not supported) |
177
- | `cache_control` on content blocks | Stripped |
178
- | `input_schema` on tools | Converted to `parameters` |
179
- | Anthropic `tool_choice` objects | OpenAI string format |
180
- | Images in Claude requests | Stripped with `[Image Omitted]` placeholder |
168
+ Access the dashboard at **[http://localhost:4142](http://localhost:4142)**
169
+
170
+ Three tabs:
171
+ - **Endpoint** Proxy URL, API key management, model list
172
+ - **Usage** Request stats, token counts, per-model breakdown, recent requests
173
+ - **Console Log** Real-time proxy logs with color-coded levels
181
174
 
182
175
  ---
183
176
 
184
177
  ## ⚠️ Known Limitations
185
178
 
186
- ### Claude Vision
187
- * **Gemini / GPT-4o:** Full Vision Support ✅
188
- * **Claude (via Copilot):** Does **NOT** support images via the API proxy ❌
189
-
190
- The proxy automatically strips images from Claude requests to prevent crashes.
191
-
192
- ### What's lost vs native Anthropic API
193
- Since Cursor sends to `/v1/chat/completions` (OpenAI) instead of `/v1/messages` (Anthropic), some features are unavailable:
194
-
195
179
  | Feature | Status |
196
180
  |---|---|
197
- | Extended thinking (chain-of-thought) | ❌ Stripped |
198
- | Prompt caching (`cache_control`) | ❌ Stripped |
199
- | Context management beta | ❌ Not available |
200
- | Premium request optimization | ❌ Bypassed |
201
181
  | Basic chat & tool calling | ✅ Works |
202
182
  | Streaming | ✅ Works |
203
-
204
- ### Tunnel URL changes on restart
205
- Cloudflare quick tunnels generate a new URL each time. You'll need to update Cursor settings when you restart the tunnel. Consider a paid plan for a fixed subdomain.
183
+ | Plan mode | ✅ Works |
184
+ | Agent mode | Works |
185
+ | GPT-5.x models | ⚠️ Blocked by copilot-api `max_tokens` bug |
186
+ | Extended thinking (chain-of-thought) | ❌ Stripped |
187
+ | Prompt caching (`cache_control`) | ❌ Stripped |
188
+ | Claude Vision | ❌ Not supported via Copilot |
189
+ | Tunnel URL changes on restart | ⚠️ Use paid plan for fixed subdomain |
206
190
 
207
191
  ---
208
192
 
209
- ### 📝 Troubleshooting
193
+ ## 📝 Troubleshooting
210
194
 
211
195
  **"Model name is not valid" in Cursor:**
212
- Make sure you're using the `cus-` prefix (e.g., `cus-gpt-4o`, not `gpt-4o`).
196
+ Make sure you're using the `cus-` prefix (e.g., `cus-gpt-5.4`, not `gpt-5.4`).
213
197
 
214
- **"connection refused" on tunnel:**
215
- Ensure all 3 services are running (copilot-api on 4141, proxy-router on 4142, tunnel).
198
+ **Plan mode response cuts off:**
199
+ Ensure `idleTimeout: 255` is set in `proxy-router.ts` (already configured). Slow models like Opus need longer timeouts.
216
200
 
217
- **500 errors from copilot-api:**
218
- Restart copilot-api. If the error mentions `messages`, the proxy should now handle it — make sure you're running the latest `proxy-router.ts`.
201
+ **GPT-5.x returns "use /v1/responses":**
202
+ The proxy auto-routes these. Make sure you're running the latest version.
219
203
 
220
- **Logs (macOS):**
221
- * Proxy: `tail -f ~/Library/Logs/copilot-proxy.log`
222
- * API: `tail -f ~/Library/Logs/copilot-api.log`
204
+ **"connection refused":**
205
+ Ensure services are running: `bun run start.ts` or check `http://localhost:4142`.
223
206
 
224
207
  ---
225
208
 
226
- > ⚠️ **DISCLAIMER:** This project is **unofficial** and created for **educational purposes only**. It interacts with undocumented internal APIs of GitHub Copilot and Cursor. Use at your own risk. The authors are not affiliated with GitHub, Microsoft, or Anysphere (Cursor). Please use your API credits responsibly and in accordance with the provider's Terms of Service.
209
+ > ⚠️ **DISCLAIMER:** This project is **unofficial** and for **educational purposes only**. It interacts with undocumented internal APIs of GitHub Copilot and Cursor. Use at your own risk. The authors are not affiliated with GitHub, Microsoft, or Anysphere (Cursor). Please use your API credits responsibly and in accordance with the provider's Terms of Service.
package/auth-config.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join } from 'path';
4
+
5
+ export interface ApiKey {
6
+ id: string;
7
+ name: string;
8
+ key: string;
9
+ active: boolean;
10
+ createdAt: number;
11
+ }
12
+
13
+ export interface AuthConfig {
14
+ requireApiKey: boolean;
15
+ keys: ApiKey[];
16
+ }
17
+
18
+ const CONFIG_DIR = join(homedir(), '.copilot-proxy');
19
+ const CONFIG_PATH = join(CONFIG_DIR, 'auth.json');
20
+
21
+ const DEFAULT_CONFIG: AuthConfig = { requireApiKey: false, keys: [] };
22
+
23
+ export function loadAuthConfig(): AuthConfig {
24
+ try {
25
+ if (!existsSync(CONFIG_PATH)) return { ...DEFAULT_CONFIG, keys: [] };
26
+ const raw = readFileSync(CONFIG_PATH, 'utf-8');
27
+ const parsed = JSON.parse(raw);
28
+ return {
29
+ requireApiKey: !!parsed.requireApiKey,
30
+ keys: Array.isArray(parsed.keys) ? parsed.keys : [],
31
+ };
32
+ } catch {
33
+ return { ...DEFAULT_CONFIG, keys: [] };
34
+ }
35
+ }
36
+
37
+ export function saveAuthConfig(config: AuthConfig): void {
38
+ if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
39
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
40
+ }
41
+
42
+ function randomHex(bytes: number): string {
43
+ const arr = new Uint8Array(bytes);
44
+ crypto.getRandomValues(arr);
45
+ return Array.from(arr, b => b.toString(16).padStart(2, '0')).join('');
46
+ }
47
+
48
+ export function generateApiKey(name: string): ApiKey {
49
+ return {
50
+ id: randomHex(4), // 8-char hex
51
+ name,
52
+ key: 'cpk-' + randomHex(16), // cpk- + 32 hex chars
53
+ active: true,
54
+ createdAt: Date.now(),
55
+ };
56
+ }
57
+
58
+ export function validateApiKey(key: string): boolean {
59
+ const config = loadAuthConfig();
60
+ return config.keys.some(k => k.key === key && k.active);
61
+ }