copilot-cursor-proxy 1.0.1 → 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
@@ -81,30 +81,32 @@ Cursor → (HTTPS tunnel) → proxy-router (:4142) → copilot-api (:4141) → G
81
81
 
82
82
  > **💡 Tip:** Visit the [Dashboard](http://localhost:4142) to see all available models and copy their IDs.
83
83
 
84
- ### Tested Models (20/21 passing)
84
+ ### Tested Models (15/21 passing)
85
85
 
86
- | Cursor Model Name | Actual Model | API Route |
86
+ | Cursor Model Name | Actual Model | Status |
87
87
  |---|---|---|
88
- | `cus-gpt-4o` | GPT-4o | Chat Completions |
89
- | `cus-gpt-4.1` | GPT-4.1 | Chat Completions |
90
- | `cus-gpt-5-mini` | GPT-5 Mini | Chat Completions |
91
- | `cus-gpt-5.1` | GPT-5.1 | Chat Completions |
92
- | `cus-gpt-5.2` | GPT-5.2 | Responses API |
93
- | `cus-gpt-5.2-codex` | GPT-5.2 Codex | Responses API |
94
- | `cus-gpt-5.3-codex` | GPT-5.3 Codex | Responses API |
95
- | `cus-gpt-5.4` | GPT-5.4 | Responses API |
96
- | `cus-gpt-5.4-mini` | GPT-5.4 Mini | Responses API |
97
- | `cus-claude-haiku-4.5` | Claude Haiku 4.5 | Chat Completions |
98
- | `cus-claude-sonnet-4` | Claude Sonnet 4 | Chat Completions |
99
- | `cus-claude-sonnet-4.5` | Claude Sonnet 4.5 | Chat Completions |
100
- | `cus-claude-sonnet-4.6` | Claude Sonnet 4.6 | Chat Completions |
101
- | `cus-claude-opus-4.5` | Claude Opus 4.5 | Chat Completions |
102
- | `cus-claude-opus-4.6` | Claude Opus 4.6 | Chat Completions |
103
- | `cus-claude-opus-4.6-1m` | Claude Opus 4.6 (1M) | Chat Completions |
104
- | `cus-gemini-2.5-pro` | Gemini 2.5 Pro | Chat Completions |
105
- | `cus-gemini-3-flash-preview` | Gemini 3 Flash | Chat Completions |
106
- | `cus-gemini-3.1-pro-preview` | Gemini 3.1 Pro | Chat Completions |
107
- | `cus-goldeneye` | Goldeneye | Responses API |
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.**
108
110
 
109
111
  ![Cursor Settings Configuration](./cursor-settings.png)
110
112
 
@@ -125,8 +127,8 @@ Cursor → (HTTPS tunnel) → proxy-router (:4142) → copilot-api (:4141) → G
125
127
  | `thinking` / `cache_control` blocks | Stripped |
126
128
  | `metadata` / `anthropic_version` | Stripped |
127
129
  | Images in Claude requests | `[Image Omitted]` placeholder |
128
- | GPT-5.x Chat Completions requests | **Bridged to Responses API** ✨ |
129
- | Responses API streaming SSE | **Converted to Chat Completions SSE** |
130
+ | GPT-5.x `max_tokens` | Converted to `max_completion_tokens` |
131
+ | GPT-5.x Responses API | **Bridge built in** (needs `copilot-api` support) |
130
132
 
131
133
  ### Supported Workflows
132
134
 
@@ -140,23 +142,35 @@ Cursor → (HTTPS tunnel) → proxy-router (:4142) → copilot-api (:4141) → G
140
142
 
141
143
  ---
142
144
 
143
- ## 🔒 Security: API Key Protection
145
+ ## 🔒 Security
144
146
 
145
- If you're using a tunnel (exposing to the public internet), set an API key:
147
+ ### Dashboard Password
146
148
 
147
- **Config location:**
148
- - Linux/macOS: `~/.local/share/copilot-api/config.json`
149
- - Windows: `%USERPROFILE%\.local\share\copilot-api\config.json`
149
+ The dashboard is password-protected. On first visit, set a password to prevent unauthorized access.
150
150
 
151
- ```json
152
- {
153
- "auth": {
154
- "apiKeys": ["your-secret-key-here"]
155
- }
156
- }
157
- ```
151
+ ### API Key Management
152
+
153
+ Manage API keys directly from the **Endpoint** tab in the dashboard:
154
+
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
+
160
+ When enabled, all `/v1/*` requests must include `Authorization: Bearer <your-key>`.
161
+
162
+ ![Dashboard](./dashboard-preview.png)
163
+
164
+ ---
165
+
166
+ ## 📊 Dashboard
167
+
168
+ Access the dashboard at **[http://localhost:4142](http://localhost:4142)**
158
169
 
159
- Then use the same key as the **API Key** in Cursor settings.
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
160
174
 
161
175
  ---
162
176
 
@@ -168,7 +182,7 @@ Then use the same key as the **API Key** in Cursor settings.
168
182
  | Streaming | ✅ Works |
169
183
  | Plan mode | ✅ Works |
170
184
  | Agent mode | ✅ Works |
171
- | GPT-5.x models | Works (via Responses API bridge) |
185
+ | GPT-5.x models | ⚠️ Blocked by copilot-api `max_tokens` bug |
172
186
  | Extended thinking (chain-of-thought) | ❌ Stripped |
173
187
  | Prompt caching (`cache_control`) | ❌ Stripped |
174
188
  | Claude Vision | ❌ Not supported via Copilot |
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
+ }