codex-claude-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 +76 -48
- package/docs/API.md +7 -8
- package/docs/ARCHITECTURE.md +16 -27
- package/docs/OAUTH.md +14 -194
- package/docs/OPENCLAW.md +18 -323
- package/docs/legal.md +11 -0
- package/images/demo-screenshot.png +0 -0
- package/package.json +1 -1
- package/public/js/app.js +1 -1
- package/src/account-manager.js +5 -5
- package/src/claude-config.js +2 -2
- package/src/cli/accounts.js +2 -2
- package/src/index.js +1 -1
- package/src/server-settings.js +2 -2
- package/src/server.js +28 -1
package/README.md
CHANGED
|
@@ -6,7 +6,17 @@ A local proxy server that exposes an **Anthropic-compatible API** (Claude Messag
|
|
|
6
6
|
|
|
7
7
|
It is designed primarily for **Claude Code CLI** (Anthropic-format client) while actually executing requests against Codex.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Table of Contents
|
|
10
|
+
- [How it works](#how-it-works)
|
|
11
|
+
- [Model Mapping](#model-mapping-claude-name--codex)
|
|
12
|
+
- [Features](#features)
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Quick Start](#quick-start)
|
|
15
|
+
- [Authentication](#authenticate-codex--chatgpt)
|
|
16
|
+
- [Claude Code Integration](#configure-claude-code-to-use-the-proxy)
|
|
17
|
+
- [Documentation](#documentation)
|
|
18
|
+
- [Legal](#legal)
|
|
19
|
+
|
|
10
20
|
|
|
11
21
|
---
|
|
12
22
|
|
|
@@ -17,13 +27,6 @@ It is designed primarily for **Claude Code CLI** (Anthropic-format client) while
|
|
|
17
27
|
- “Claude” and “Anthropic” are trademarks of Anthropic PBC.
|
|
18
28
|
- Software is provided **“as is”**, without warranty. You are responsible for complying with all applicable Terms of Service and Acceptable Use Policies.
|
|
19
29
|
|
|
20
|
-
### Legal
|
|
21
|
-
|
|
22
|
-
- **Not affiliated with OpenAI or Anthropic.** This is an independent open-source project and is not endorsed by, sponsored by, or affiliated with OpenAI or Anthropic.
|
|
23
|
-
- “ChatGPT”, “OpenAI”, and “Codex” are trademarks of their respective owners.
|
|
24
|
-
- “Claude” and “Anthropic” are trademarks of Anthropic PBC.
|
|
25
|
-
- Software is provided "as is", without warranty. You are responsible for complying with all applicable Terms of Service and Acceptable Use Policies.
|
|
26
|
-
|
|
27
30
|
---
|
|
28
31
|
|
|
29
32
|
## How it works
|
|
@@ -41,6 +44,10 @@ At a high level:
|
|
|
41
44
|
2. The proxy maps the incoming “Claude model name” into a Codex model.
|
|
42
45
|
3. The proxy converts formats as needed and returns responses back in Anthropic-compatible shapes, including streaming and tool calls.
|
|
43
46
|
|
|
47
|
+
Notes:
|
|
48
|
+
- Requests are proxied to the ChatGPT Codex backend.
|
|
49
|
+
- The `claude-haiku-4` (“Haiku”) lane can optionally route via **OpenRouter** to **MiniMax M2.5** / **GLM-5** (depending on server configuration).
|
|
50
|
+
|
|
44
51
|
---
|
|
45
52
|
|
|
46
53
|
## Model mapping (Claude name → Codex)
|
|
@@ -51,7 +58,7 @@ This proxy accepts Claude-style model IDs (what Claude Code expects) and maps th
|
|
|
51
58
|
|---|---|---:|---|
|
|
52
59
|
| `claude-sonnet-4-5` | **GPT-5.2 Codex** | Yes | Default “Sonnet” lane |
|
|
53
60
|
| `claude-opus-4-5` | **GPT-5.3 Codex** | Yes | Default “Opus” lane |
|
|
54
|
-
| `claude-haiku-4` | **
|
|
61
|
+
| `claude-haiku-4` | **GLM-5 / MiniMax M2.5** | No | Unlimited / No Auth required |
|
|
55
62
|
|
|
56
63
|
---
|
|
57
64
|
|
|
@@ -78,12 +85,26 @@ This proxy accepts Claude-style model IDs (what Claude Code expects) and maps th
|
|
|
78
85
|
|
|
79
86
|
---
|
|
80
87
|
|
|
81
|
-
##
|
|
88
|
+
## Installation
|
|
82
89
|
|
|
83
90
|
```bash
|
|
91
|
+
# Run once (no install)
|
|
92
|
+
npx codex-claude-proxy@latest start
|
|
93
|
+
|
|
94
|
+
# Or install globally
|
|
95
|
+
npm i -g codex-claude-proxy
|
|
96
|
+
codex-claude-proxy start
|
|
97
|
+
|
|
98
|
+
# Or from source
|
|
99
|
+
git clone <repo-url>
|
|
100
|
+
cd codex-claude-proxy
|
|
84
101
|
npm install
|
|
85
102
|
npm start
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Quick start
|
|
86
106
|
|
|
107
|
+
```bash
|
|
87
108
|
# WebUI
|
|
88
109
|
open http://localhost:8081
|
|
89
110
|
|
|
@@ -110,29 +131,47 @@ Codex-backed routes require at least one authenticated ChatGPT account.
|
|
|
110
131
|
2. Open `http://localhost:8081`
|
|
111
132
|
3. Go to Accounts and add an account via OAuth (or use the Manual mode for headless environments)
|
|
112
133
|
|
|
113
|
-
### Option B: CLI
|
|
134
|
+
### Option B: CLI
|
|
114
135
|
|
|
115
|
-
|
|
136
|
+
Add an account:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Opens browser
|
|
140
|
+
codex-claude-proxy accounts add
|
|
141
|
+
|
|
142
|
+
# Headless / VM (prints URL; you paste callback URL/code)
|
|
143
|
+
codex-claude-proxy accounts add --no-browser
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
List accounts:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
codex-claude-proxy accounts list
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
(If you’re running from source, use `npm start` in one terminal and run the CLI commands in another.)
|
|
153
|
+
|
|
154
|
+
Desktop (equivalent npm script):
|
|
116
155
|
|
|
117
156
|
```bash
|
|
118
157
|
npm run accounts:add
|
|
119
158
|
```
|
|
120
159
|
|
|
121
|
-
Headless / VM:
|
|
160
|
+
Headless / VM (equivalent npm script):
|
|
122
161
|
|
|
123
162
|
```bash
|
|
124
163
|
npm run accounts:add:headless
|
|
125
|
-
# Prints URL, you paste callback URL/code
|
|
126
164
|
```
|
|
127
165
|
|
|
128
166
|
### Option C: Import from Codex app
|
|
129
167
|
|
|
168
|
+
You can import an existing Codex app session via the server (see [Accounts](./docs/ACCOUNTS.md) for details).
|
|
169
|
+
|
|
130
170
|
```bash
|
|
131
171
|
curl -X POST http://localhost:8081/accounts/import
|
|
132
|
-
# Imports from ~/.codex/auth.json
|
|
133
172
|
```
|
|
134
173
|
|
|
135
|
-
Details:
|
|
174
|
+
Details: [OAuth](./docs/OAUTH.md) and [Accounts](./docs/ACCOUNTS.md).
|
|
136
175
|
|
|
137
176
|
---
|
|
138
177
|
|
|
@@ -144,7 +183,7 @@ Details: `docs/OAUTH.md` and `docs/ACCOUNTS.md`.
|
|
|
144
183
|
curl -X POST http://localhost:8081/claude/config/proxy
|
|
145
184
|
```
|
|
146
185
|
|
|
147
|
-
This updates
|
|
186
|
+
This updates your local Claude Code settings to point at `http://localhost:8081`.
|
|
148
187
|
|
|
149
188
|
### Manual (env vars)
|
|
150
189
|
|
|
@@ -154,53 +193,42 @@ export ANTHROPIC_API_KEY=any-key
|
|
|
154
193
|
claude
|
|
155
194
|
```
|
|
156
195
|
|
|
157
|
-
More details:
|
|
196
|
+
More details: [Claude Code Integration](./docs/CLAUDE_INTEGRATION.md).
|
|
158
197
|
|
|
159
198
|
---
|
|
160
199
|
|
|
161
|
-
##
|
|
200
|
+
## Security
|
|
162
201
|
|
|
163
|
-
-
|
|
164
|
-
|
|
165
|
-
- `GET /v1/models`
|
|
166
|
-
- `POST /v1/messages/count_tokens`
|
|
202
|
+
- **Localhost Only**: CORS is strictly restricted to `localhost` and `127.0.0.1` to prevent unauthorized cross-origin requests from external websites.
|
|
203
|
+
- **Credential Safety**: Credentials are not allowed in cross-origin requests.
|
|
167
204
|
|
|
168
|
-
|
|
169
|
-
- `POST /v1/chat/completions`
|
|
205
|
+
---
|
|
170
206
|
|
|
171
|
-
- Accounts:
|
|
172
|
-
- `GET /accounts`
|
|
173
|
-
- `POST /accounts/add`
|
|
174
|
-
- `POST /accounts/add/manual`
|
|
175
|
-
- `POST /accounts/switch`
|
|
176
|
-
- `POST /accounts/refresh`, `POST /accounts/refresh/all`
|
|
177
207
|
|
|
178
|
-
|
|
179
|
-
- `GET /api/logs`
|
|
180
|
-
- `GET /api/logs/stream?history=true`
|
|
208
|
+
## Documentation
|
|
181
209
|
|
|
182
|
-
|
|
210
|
+
- [**Architecture**](./docs/ARCHITECTURE.md) - Design and flow
|
|
211
|
+
- [**API Reference**](./docs/API.md) - Endpoints and model list
|
|
212
|
+
- [**Accounts**](./docs/ACCOUNTS.md) - Multi-account management
|
|
213
|
+
- [**OAuth**](./docs/OAUTH.md) - Authentication details
|
|
214
|
+
- [**OpenClaw**](./docs/OPENCLAW.md) - Using with messaging gateways
|
|
215
|
+
- [**Claude Code**](./docs/CLAUDE_INTEGRATION.md) - Detailed CLI setup guide
|
|
183
216
|
|
|
184
|
-
|
|
217
|
+
## Legal
|
|
185
218
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
- `docs/ARCHITECTURE.md` — system overview and data flow
|
|
189
|
-
- `docs/API.md` — endpoints, formats, streaming
|
|
190
|
-
- `docs/OAUTH.md` — OAuth PKCE implementation + headless flow
|
|
191
|
-
- `docs/ACCOUNTS.md` — multi-account storage, switching, refresh, quota caching
|
|
192
|
-
- `docs/CLAUDE_INTEGRATION.md` — how to use with Claude Code
|
|
193
|
-
- `docs/OPENCLAW.md` — using the proxy behind OpenClaw
|
|
219
|
+
See [Legal Notices](./docs/legal.md).
|
|
194
220
|
|
|
195
221
|
---
|
|
196
222
|
|
|
197
|
-
##
|
|
223
|
+
## Credits
|
|
224
|
+
|
|
225
|
+
This project is based on insights and code from:
|
|
198
226
|
|
|
199
|
-
-
|
|
200
|
-
-
|
|
227
|
+
- [badrisnarayanan/antigravity-claude-proxy](https://github.com/badrisnarayanan/antigravity-claude-proxy)
|
|
228
|
+
- [1rgs/claude-code-proxy](https://github.com/1rgs/claude-code-proxy)
|
|
201
229
|
|
|
202
230
|
---
|
|
203
231
|
|
|
204
232
|
## License
|
|
205
233
|
|
|
206
|
-
MIT
|
|
234
|
+
MIT
|
package/docs/API.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
### Haiku Routing Settings
|
|
6
6
|
|
|
7
|
+
The `claude-haiku-4` (“Haiku”) lane can be configured to route via an alternate provider (e.g. **OpenRouter**) for supported models (e.g. **MiniMax M2.5** / **GLM-5**).
|
|
8
|
+
|
|
7
9
|
```bash
|
|
8
10
|
GET /settings/haiku-model
|
|
9
11
|
|
|
@@ -29,8 +31,6 @@ Content-Type: application/json
|
|
|
29
31
|
}
|
|
30
32
|
```
|
|
31
33
|
|
|
32
|
-
`claude-haiku-4` requests are routed according to this server-wide setting.
|
|
33
|
-
|
|
34
34
|
### Chat Completions (OpenAI-compatible)
|
|
35
35
|
|
|
36
36
|
```bash
|
|
@@ -81,22 +81,21 @@ Content-Type: application/json
|
|
|
81
81
|
|
|
82
82
|
## Account Management
|
|
83
83
|
|
|
84
|
+
Common endpoints:
|
|
85
|
+
|
|
84
86
|
| Endpoint | Method | Description |
|
|
85
87
|
|----------|--------|-------------|
|
|
86
88
|
| `/accounts` | GET | List all accounts |
|
|
87
89
|
| `/accounts/status` | GET | Get account status summary |
|
|
88
90
|
| `/accounts/add` | POST | Start OAuth flow (returns URL) |
|
|
89
91
|
| `/accounts/switch` | POST | Switch active account |
|
|
90
|
-
| `/accounts/:email` | DELETE | Remove account |
|
|
91
|
-
| `/accounts/refresh` | POST | Refresh active account token |
|
|
92
|
-
| `/accounts/refresh/all` | POST | Refresh all tokens |
|
|
93
|
-
| `/accounts/:email/refresh` | POST | Refresh specific account |
|
|
94
|
-
| `/accounts/import` | POST | Import from `~/.codex/auth.json` |
|
|
95
92
|
| `/accounts/models` | GET | Get models for account |
|
|
96
93
|
| `/accounts/quota` | GET | Get quota info |
|
|
97
94
|
| `/accounts/quota/all` | GET | Refresh all quotas |
|
|
98
95
|
| `/accounts/usage` | GET | Get usage stats |
|
|
99
96
|
|
|
97
|
+
(Additional maintenance endpoints exist for token refresh/import/removal; see the source if you need them.)
|
|
98
|
+
|
|
100
99
|
### Add Account
|
|
101
100
|
|
|
102
101
|
```bash
|
|
@@ -163,7 +162,7 @@ GET /health
|
|
|
163
162
|
{
|
|
164
163
|
"status": "ok",
|
|
165
164
|
"total": 2,
|
|
166
|
-
"active": "
|
|
165
|
+
"active": "active@example.com",
|
|
167
166
|
"accounts": [...]
|
|
168
167
|
}
|
|
169
168
|
```
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -4,22 +4,22 @@
|
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
┌──────────────────┐ ┌─────────────────────┐ ┌────────────────────────────┐
|
|
7
|
-
│ Claude Code │────▶│ This Proxy Server │────▶│ ChatGPT
|
|
8
|
-
│ (Anthropic │ │ (Anthropic format)
|
|
9
|
-
│ API format) │ │
|
|
7
|
+
│ Claude Code │────▶│ This Proxy Server │────▶│ ChatGPT Codex backend │
|
|
8
|
+
│ (Anthropic │ │ (Anthropic format) │ │ (internal API) │
|
|
9
|
+
│ API format) │ │ │ │ │
|
|
10
10
|
└──────────────────┘ └─────────────────────┘ └────────────────────────────┘
|
|
11
11
|
│
|
|
12
12
|
▼
|
|
13
13
|
┌─────────────────────┐
|
|
14
14
|
│ Account Manager │
|
|
15
|
-
│ (
|
|
16
|
-
│
|
|
15
|
+
│ (local storage) │
|
|
16
|
+
│ │
|
|
17
17
|
└─────────────────────┘
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
## Key Discovery
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
This proxy forwards requests from Anthropic-compatible clients (like Claude Code) to the ChatGPT Codex backend, handling authentication, format conversion, and streaming.
|
|
23
23
|
|
|
24
24
|
## Project Structure
|
|
25
25
|
|
|
@@ -36,28 +36,22 @@ codex-claude-proxy/
|
|
|
36
36
|
├── public/
|
|
37
37
|
│ ├── index.html
|
|
38
38
|
│ ├── css/style.css
|
|
39
|
-
│ └── js/app.js #
|
|
39
|
+
│ └── js/app.js # Web UI logic
|
|
40
40
|
└── src/
|
|
41
|
-
├── index.js
|
|
42
|
-
├──
|
|
43
|
-
├──
|
|
44
|
-
|
|
45
|
-
├── response-streamer.js # SSE streaming
|
|
46
|
-
├── direct-api.js # ChatGPT API client
|
|
47
|
-
├── kilo-api.js # Alternate upstream client
|
|
48
|
-
├── kilo-format-converter.js # Anthropic ↔ OpenAI Chat conversion
|
|
49
|
-
├── kilo-streamer.js # Streaming adapter
|
|
50
|
-
├── model-api.js # Models & quota
|
|
51
|
-
├── server-settings.js # Server-wide settings persistence
|
|
52
|
-
└── claude-config.js # Claude CLI config
|
|
41
|
+
├── index.js # App entrypoint
|
|
42
|
+
├── server.js # Express server setup
|
|
43
|
+
├── routes/api-routes.js # API route registrations
|
|
44
|
+
└── ... # OAuth, accounts, converters, upstream clients
|
|
53
45
|
```
|
|
54
46
|
|
|
47
|
+
(See the `src/` directory for the full implementation; this doc focuses on the high-level shape.)
|
|
48
|
+
|
|
55
49
|
## Module Responsibilities
|
|
56
50
|
|
|
57
51
|
| File | Purpose |
|
|
58
52
|
|------|---------|
|
|
59
53
|
| `index.js` | Entry point (starts server) |
|
|
60
|
-
| `server.js` | Express server, routes, request handling |
|
|
54
|
+
| `server.js` | Express server, routes, request handling (CORS restricted) |
|
|
61
55
|
| `routes/api-routes.js` | API route registrations (mounted by server) |
|
|
62
56
|
| `oauth.js` | OAuth 2.0 PKCE flow, token exchange |
|
|
63
57
|
| `account-manager.js` | Account persistence, switching, token refresh |
|
|
@@ -69,7 +63,7 @@ codex-claude-proxy/
|
|
|
69
63
|
| `kilo-streamer.js` | Streaming adapter |
|
|
70
64
|
| `server-settings.js` | Server-wide settings persistence |
|
|
71
65
|
| `model-api.js` | Fetch models, usage, quota |
|
|
72
|
-
| `claude-config.js` | Read/write
|
|
66
|
+
| `claude-config.js` | Read/write Claude Code settings |
|
|
73
67
|
|
|
74
68
|
## Data Flow
|
|
75
69
|
|
|
@@ -125,9 +119,4 @@ Haiku routing is controlled by a server-wide setting (`/settings/haiku-model`).
|
|
|
125
119
|
|
|
126
120
|
## Data Storage
|
|
127
121
|
|
|
128
|
-
|
|
129
|
-
|----------|----------|
|
|
130
|
-
| `~/.codex-claude-proxy/accounts.json` | Account registry, active account |
|
|
131
|
-
| `~/.codex-claude-proxy/accounts/<email>/auth.json` | Per-account tokens |
|
|
132
|
-
| `~/.claude/settings.json` | Claude CLI config (we update this) |
|
|
133
|
-
| `~/.codex/auth.json` | Codex app auth (read for import) |
|
|
122
|
+
Account and configuration files are stored under your home directory (platform-specific). See `docs/ACCOUNTS.md` and `docs/CLAUDE_INTEGRATION.md` for details.
|
package/docs/OAUTH.md
CHANGED
|
@@ -1,201 +1,21 @@
|
|
|
1
1
|
# OAuth Implementation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This proxy uses **OAuth 2.0 with PKCE** for secure authentication with ChatGPT.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
authUrl: 'https://auth.openai.com/oauth/authorize',
|
|
9
|
-
tokenUrl: 'https://auth.openai.com/oauth/token',
|
|
10
|
-
scopes: ['openid', 'profile', 'email', 'offline_access'],
|
|
11
|
-
callbackPort: 1455,
|
|
12
|
-
callbackPath: '/auth/callback'
|
|
13
|
-
}
|
|
14
|
-
```
|
|
5
|
+
## Quick Start
|
|
6
|
+
- **WebUI (Recommended)**: Open `http://localhost:8081` → **Add Account** → **Connect**.
|
|
7
|
+
- **Headless**: Use `codex-claude-proxy accounts add --no-browser`.
|
|
15
8
|
|
|
16
|
-
##
|
|
9
|
+
## OAuth Config
|
|
10
|
+
- **Client ID**: `app_EMoamEEZ73f0CkXaXp7hrann`
|
|
11
|
+
- **Auth URL**: `https://auth.openai.com/oauth/authorize`
|
|
12
|
+
- **Redirect**: `http://localhost:1455/auth/callback`
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
3. Complete authorization in the popup
|
|
23
|
-
|
|
24
|
-
### Method B: WebUI Manual Mode (Headless)
|
|
25
|
-
|
|
26
|
-
For servers without a browser:
|
|
27
|
-
|
|
28
|
-
1. Click **Add Account** → **Manual Authorization**
|
|
29
|
-
2. Copy the OAuth URL
|
|
30
|
-
3. Open URL on another device (your local machine)
|
|
31
|
-
4. Complete authorization
|
|
32
|
-
5. Copy the callback URL or authorization code
|
|
33
|
-
6. Paste back in the WebUI
|
|
34
|
-
|
|
35
|
-
### Method C: CLI (Desktop)
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npm run accounts:add
|
|
39
|
-
# Opens browser for OAuth
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Method D: CLI Headless Mode
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npm run accounts:add:headless
|
|
46
|
-
# Prints URL, you paste the callback URL/code
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Method E: API (Headless)
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# 1. Get OAuth URL and verifier
|
|
53
|
-
curl -X POST http://localhost:8081/accounts/add
|
|
54
|
-
|
|
55
|
-
# Response includes oauth_url, verifier, state
|
|
56
|
-
|
|
57
|
-
# 2. Open URL on another device, complete auth
|
|
58
|
-
|
|
59
|
-
# 3. Submit authorization code
|
|
60
|
-
curl -X POST http://localhost:8081/accounts/add/manual \
|
|
61
|
-
-H "Content-Type: application/json" \
|
|
62
|
-
-d '{"code":"<code_or_callback_url>","verifier":"<verifier_from_step_1>"}'
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## PKCE Flow
|
|
66
|
-
|
|
67
|
-
### 1. Generate PKCE Challenge
|
|
68
|
-
|
|
69
|
-
```javascript
|
|
70
|
-
// Verifier: 32 random bytes, base64url encoded
|
|
71
|
-
verifier = crypto.randomBytes(32).toString('base64url')
|
|
72
|
-
|
|
73
|
-
// Challenge: SHA256 hash of verifier
|
|
74
|
-
challenge = sha256(verifier).base64url
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### 2. Authorization URL
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
https://auth.openai.com/oauth/authorize?
|
|
81
|
-
response_type=code
|
|
82
|
-
&client_id=app_EMoamEEZ73f0CkXaXp7hrann
|
|
83
|
-
&redirect_uri=http://localhost:1455/auth/callback
|
|
84
|
-
&scope=openid profile email offline_access
|
|
85
|
-
&code_challenge=<challenge>
|
|
86
|
-
&code_challenge_method=S256
|
|
87
|
-
&state=<random_state>
|
|
88
|
-
&prompt=login
|
|
89
|
-
&max_age=0
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
**Key parameters for multi-account:**
|
|
93
|
-
- `prompt=login` - Forces login screen (ignores session cookies)
|
|
94
|
-
- `max_age=0` - Forces re-authentication
|
|
95
|
-
|
|
96
|
-
### 3. Token Exchange
|
|
97
|
-
|
|
98
|
-
```javascript
|
|
99
|
-
POST https://auth.openai.com/oauth/token
|
|
100
|
-
Content-Type: application/x-www-form-urlencoded
|
|
101
|
-
|
|
102
|
-
grant_type=authorization_code
|
|
103
|
-
&code=<authorization_code>
|
|
104
|
-
&redirect_uri=http://localhost:1455/auth/callback
|
|
105
|
-
&client_id=app_EMoamEEZ73f0CkXaXp7hrann
|
|
106
|
-
&code_verifier=<verifier>
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### 4. Token Response
|
|
110
|
-
|
|
111
|
-
```json
|
|
112
|
-
{
|
|
113
|
-
"access_token": "eyJhbGciOiJSUzI1NiIs...",
|
|
114
|
-
"refresh_token": "rt_WpTMn1...",
|
|
115
|
-
"id_token": "eyJhbGciOiJSUzI1NiIs...",
|
|
116
|
-
"expires_in": 3600,
|
|
117
|
-
"token_type": "Bearer"
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## JWT Claims
|
|
122
|
-
|
|
123
|
-
Decoded `access_token` payload:
|
|
124
|
-
|
|
125
|
-
```json
|
|
126
|
-
{
|
|
127
|
-
"https://api.openai.com/auth": {
|
|
128
|
-
"chatgpt_account_id": "d41e9636-...",
|
|
129
|
-
"chatgpt_plan_type": "plus",
|
|
130
|
-
"chatgpt_user_id": "user-..."
|
|
131
|
-
},
|
|
132
|
-
"https://api.openai.com/profile": {
|
|
133
|
-
"email": "user@gmail.com",
|
|
134
|
-
"email_verified": true
|
|
135
|
-
},
|
|
136
|
-
"exp": 1770886178
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## Token Refresh
|
|
141
|
-
|
|
142
|
-
```javascript
|
|
143
|
-
POST https://auth.openai.com/oauth/token
|
|
144
|
-
Content-Type: application/x-www-form-urlencoded
|
|
145
|
-
|
|
146
|
-
grant_type=refresh_token
|
|
147
|
-
&refresh_token=<refresh_token>
|
|
148
|
-
&client_id=app_EMoamEEZ73f0CkXaXp7hrann
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## Auto-Refresh
|
|
152
|
-
|
|
153
|
-
- Tokens auto-refresh every **55 minutes**
|
|
154
|
-
- Proactive refresh before API calls if expiring within 5 minutes
|
|
155
|
-
- Startup refresh 2 seconds after server start
|
|
156
|
-
|
|
157
|
-
## Web Flow vs CLI Flow
|
|
158
|
-
|
|
159
|
-
### Web Flow (WebUI)
|
|
160
|
-
|
|
161
|
-
1. `POST /accounts/add` → returns OAuth URL
|
|
162
|
-
2. Frontend opens popup with URL
|
|
163
|
-
3. User authenticates in popup
|
|
164
|
-
4. Browser redirects to callback
|
|
165
|
-
5. Server handles callback, stores tokens
|
|
166
|
-
6. Popup notifies parent via `postMessage`
|
|
167
|
-
|
|
168
|
-
### CLI Flow
|
|
169
|
-
|
|
170
|
-
1. `POST /accounts/add` → starts callback server on port 1455
|
|
171
|
-
2. Server opens browser with OAuth URL
|
|
172
|
-
3. User authenticates
|
|
173
|
-
4. Browser redirects to callback
|
|
174
|
-
5. Server exchanges code for tokens
|
|
175
|
-
|
|
176
|
-
## Multi-Account Support
|
|
177
|
-
|
|
178
|
-
The key to multi-account support is forcing a fresh login each time:
|
|
179
|
-
|
|
180
|
-
1. `prompt=login` - Shows login screen even if already logged in
|
|
181
|
-
2. `max_age=0` - Requires re-authentication
|
|
182
|
-
3. Each account stored with unique email as identifier
|
|
14
|
+
## Features
|
|
15
|
+
- **Auto-Refresh**: Tokens refresh every 55 minutes.
|
|
16
|
+
- **Multi-Account**: Uses `prompt=login` to force account switching.
|
|
17
|
+
- **Headless Support**: Manual code entry for servers without browsers.
|
|
183
18
|
|
|
184
19
|
## Troubleshooting
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
- Browser may have aggressive cookie caching
|
|
189
|
-
- Try manual logout: https://auth.openai.com/logout
|
|
190
|
-
- Clear browser cookies for auth.openai.com
|
|
191
|
-
|
|
192
|
-
### Callback timeout
|
|
193
|
-
|
|
194
|
-
- Default timeout: 2 minutes
|
|
195
|
-
- Ensure port 1455 is available
|
|
196
|
-
- Check firewall isn't blocking localhost
|
|
197
|
-
|
|
198
|
-
### Token refresh fails
|
|
199
|
-
|
|
200
|
-
- Refresh token may have expired
|
|
201
|
-
- Re-add the account via WebUI
|
|
20
|
+
- **Existing Account**: If it keeps picking the same account, logout at `auth.openai.com` or clear cookies.
|
|
21
|
+
- **Port 1455**: Must be available for the CLI callback.
|
package/docs/OPENCLAW.md
CHANGED
|
@@ -1,338 +1,33 @@
|
|
|
1
1
|
# Using with OpenClaw
|
|
2
2
|
|
|
3
|
-
[OpenClaw](https://docs.openclaw.ai/)
|
|
3
|
+
[OpenClaw](https://docs.openclaw.ai/) is an AI agent gateway. This proxy provides the Anthropic-compatible API it needs.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Quick Integration
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
┌──────────────┐ ┌─────────────┐ ┌─────────────────────┐ ┌──────────────┐
|
|
11
|
-
│ Telegram │────▶│ │ │ Codex-Claude-Proxy │ │ ChatGPT │
|
|
12
|
-
│ WhatsApp │ │ OpenClaw │────▶│ (Anthropic API) │────▶│ Codex API │
|
|
13
|
-
│ Discord │ │ Gateway │ │ │ │ │
|
|
14
|
-
│ Slack │ │ │ │ │ │ │
|
|
15
|
-
│ iMessage │ │ │ │ │ │ │
|
|
16
|
-
└──────────────┘ └─────────────┘ └─────────────────────┘ └──────────────┘
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
OpenClaw expects providers to expose an Anthropic-compatible or OpenAI-compatible API, which this proxy provides.
|
|
20
|
-
|
|
21
|
-
## Prerequisites
|
|
22
|
-
|
|
23
|
-
- OpenClaw installed:
|
|
24
|
-
```bash
|
|
25
|
-
npm install -g openclaw@latest
|
|
26
|
-
```
|
|
27
|
-
- Codex-Claude-Proxy running on port 8081 (or your configured port)
|
|
28
|
-
- At least one ChatGPT account linked to the proxy
|
|
29
|
-
|
|
30
|
-
## Configure OpenClaw
|
|
31
|
-
|
|
32
|
-
Edit your OpenClaw config file:
|
|
33
|
-
- **macOS/Linux**: `~/.openclaw/openclaw.json`
|
|
34
|
-
- **Windows**: `%USERPROFILE%\.openclaw\openclaw.json`
|
|
35
|
-
|
|
36
|
-
### Basic Configuration
|
|
37
|
-
|
|
38
|
-
```json
|
|
39
|
-
{
|
|
40
|
-
"models": {
|
|
41
|
-
"mode": "merge",
|
|
42
|
-
"providers": {
|
|
7
|
+
1. **Add Provider** to `~/.openclaw/openclaw.json`:
|
|
8
|
+
```json
|
|
9
|
+
{
|
|
43
10
|
"codex-proxy": {
|
|
44
11
|
"baseUrl": "http://127.0.0.1:8081",
|
|
45
12
|
"apiKey": "test",
|
|
46
13
|
"api": "anthropic-messages",
|
|
47
14
|
"models": [
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
"name": "GPT-5.3 Codex",
|
|
51
|
-
"reasoning": true,
|
|
52
|
-
"input": ["text", "image"],
|
|
53
|
-
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
|
|
54
|
-
"contextWindow": 200000,
|
|
55
|
-
"maxTokens": 128000
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"id": "gpt-5.2-codex",
|
|
59
|
-
"name": "GPT-5.2 Codex",
|
|
60
|
-
"reasoning": true,
|
|
61
|
-
"input": ["text", "image"],
|
|
62
|
-
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
|
|
63
|
-
"contextWindow": 200000,
|
|
64
|
-
"maxTokens": 128000
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"id": "gpt-5.2",
|
|
68
|
-
"name": "GPT-5.2",
|
|
69
|
-
"reasoning": false,
|
|
70
|
-
"input": ["text", "image"],
|
|
71
|
-
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
|
|
72
|
-
"contextWindow": 128000,
|
|
73
|
-
"maxTokens": 16384
|
|
74
|
-
}
|
|
15
|
+
{ "id": "claude-sonnet-4-5", "name": "GPT-5.2 Codex" },
|
|
16
|
+
{ "id": "claude-opus-4-5", "name": "GPT-5.3 Codex" }
|
|
75
17
|
]
|
|
76
18
|
}
|
|
77
19
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"fallbacks": ["codex-proxy/gpt-5.2"]
|
|
84
|
-
},
|
|
85
|
-
"models": {
|
|
86
|
-
"codex-proxy/gpt-5.2-codex": {}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Using Claude Model Names (Auto-Mapped)
|
|
94
|
-
|
|
95
|
-
The proxy automatically maps Claude model names to Codex equivalents. You can use familiar names:
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"models": {
|
|
100
|
-
"mode": "merge",
|
|
101
|
-
"providers": {
|
|
102
|
-
"codex-proxy": {
|
|
103
|
-
"baseUrl": "http://127.0.0.1:8081",
|
|
104
|
-
"apiKey": "test",
|
|
105
|
-
"api": "anthropic-messages",
|
|
106
|
-
"models": [
|
|
107
|
-
{
|
|
108
|
-
"id": "claude-opus-4-5",
|
|
109
|
-
"name": "Claude Opus 4.5 (GPT-5.3 Codex)",
|
|
110
|
-
"reasoning": true,
|
|
111
|
-
"input": ["text", "image"],
|
|
112
|
-
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
|
|
113
|
-
"contextWindow": 200000,
|
|
114
|
-
"maxTokens": 128000
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
"id": "claude-sonnet-4-5",
|
|
118
|
-
"name": "Claude Sonnet 4.5 (GPT-5.2 Codex)",
|
|
119
|
-
"reasoning": true,
|
|
120
|
-
"input": ["text", "image"],
|
|
121
|
-
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
|
|
122
|
-
"contextWindow": 200000,
|
|
123
|
-
"maxTokens": 128000
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
"id": "claude-haiku-4",
|
|
127
|
-
"name": "Claude Haiku 4 (GPT-5.2)",
|
|
128
|
-
"reasoning": false,
|
|
129
|
-
"input": ["text", "image"],
|
|
130
|
-
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
|
|
131
|
-
"contextWindow": 128000,
|
|
132
|
-
"maxTokens": 16384
|
|
133
|
-
}
|
|
134
|
-
]
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
"agents": {
|
|
139
|
-
"defaults": {
|
|
140
|
-
"model": {
|
|
141
|
-
"primary": "codex-proxy/claude-sonnet-4-5",
|
|
142
|
-
"fallbacks": ["codex-proxy/claude-haiku-4"]
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
> **Note**: The `reasoning` field indicates whether the model supports extended thinking/reasoning. Set to `true` for Codex models which excel at complex reasoning tasks.
|
|
150
|
-
|
|
151
|
-
## Model Reference
|
|
152
|
-
|
|
153
|
-
| Proxy Model | Mapped From | Best For |
|
|
154
|
-
|-------------|-------------|----------|
|
|
155
|
-
| `gpt-5.3-codex` | `claude-opus-4-5` | Most capable, complex coding tasks |
|
|
156
|
-
| `gpt-5.2-codex` | `claude-sonnet-4-5` | Balanced performance, recommended default |
|
|
157
|
-
| `gpt-5.2` | `claude-haiku-4` | Fast responses, simpler tasks |
|
|
158
|
-
|
|
159
|
-
## Start Both Services
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
# Terminal 1: Start the proxy
|
|
163
|
-
cd codex-claude-proxy
|
|
164
|
-
npm start
|
|
165
|
-
|
|
166
|
-
# Terminal 2: Start OpenClaw gateway
|
|
167
|
-
openclaw gateway
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
## Verify Configuration
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
# Check available models
|
|
174
|
-
openclaw models list
|
|
175
|
-
|
|
176
|
-
# Check gateway status
|
|
177
|
-
openclaw status
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
You should see models prefixed with `codex-proxy/` in the list.
|
|
181
|
-
|
|
182
|
-
## Switch Models
|
|
183
|
-
|
|
184
|
-
To change the default model:
|
|
185
|
-
|
|
186
|
-
```bash
|
|
187
|
-
openclaw models set codex-proxy/gpt-5.3-codex
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Or edit the `model.primary` field in your config file.
|
|
191
|
-
|
|
192
|
-
## API Compatibility
|
|
193
|
-
|
|
194
|
-
The proxy exposes an **Anthropic Messages API** compatible interface:
|
|
195
|
-
|
|
196
|
-
| Endpoint | Description |
|
|
197
|
-
|----------|-------------|
|
|
198
|
-
| `POST /v1/messages` | Main chat endpoint |
|
|
199
|
-
| `GET /v1/models` | List available models |
|
|
200
|
-
| `POST /v1/messages/count_tokens` | Token counting |
|
|
201
|
-
|
|
202
|
-
OpenClaw's `api: "anthropic-messages"` setting tells it to use the Anthropic format, which this proxy fully supports including:
|
|
203
|
-
- Streaming responses (SSE)
|
|
204
|
-
- Tool/function calling
|
|
205
|
-
- Multi-turn conversations
|
|
206
|
-
- Image inputs
|
|
207
|
-
- System prompts
|
|
208
|
-
|
|
209
|
-
## Multi-Account Support
|
|
210
|
-
|
|
211
|
-
The proxy supports multiple ChatGPT accounts with automatic switching:
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
# Add accounts via Web UI at http://localhost:8081
|
|
215
|
-
# Or via CLI:
|
|
216
|
-
npm run accounts:add
|
|
217
|
-
|
|
218
|
-
# List accounts
|
|
219
|
-
curl http://localhost:8081/accounts
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
When one account hits rate limits, the proxy can automatically switch to another. This provides seamless continuity for OpenClaw users.
|
|
223
|
-
|
|
224
|
-
## Advanced Configuration
|
|
225
|
-
|
|
226
|
-
### Custom Port
|
|
227
|
-
|
|
228
|
-
If running the proxy on a different port:
|
|
229
|
-
|
|
230
|
-
```json
|
|
231
|
-
{
|
|
232
|
-
"models": {
|
|
233
|
-
"providers": {
|
|
234
|
-
"codex-proxy": {
|
|
235
|
-
"baseUrl": "http://127.0.0.1:3000",
|
|
236
|
-
...
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### VPS/Remote Server
|
|
244
|
-
|
|
245
|
-
When running on a VPS, bind the proxy to localhost only:
|
|
246
|
-
|
|
247
|
-
```bash
|
|
248
|
-
HOST=127.0.0.1 PORT=8081 npm start
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Then use SSH port forwarding on your local machine:
|
|
252
|
-
|
|
253
|
-
```bash
|
|
254
|
-
ssh -L 8081:127.0.0.1:8081 user@your-vps
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
Configure OpenClaw to use the local tunnel:
|
|
20
|
+
```
|
|
21
|
+
2. **Set Primary Model**:
|
|
22
|
+
```bash
|
|
23
|
+
openclaw models set codex-proxy/claude-sonnet-4-5
|
|
24
|
+
```
|
|
258
25
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
### Authentication
|
|
266
|
-
|
|
267
|
-
To protect the proxy with an API key:
|
|
268
|
-
|
|
269
|
-
```bash
|
|
270
|
-
API_KEY=your-secret-key npm start
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
Update OpenClaw config:
|
|
274
|
-
|
|
275
|
-
```json
|
|
276
|
-
{
|
|
277
|
-
"providers": {
|
|
278
|
-
"codex-proxy": {
|
|
279
|
-
"baseUrl": "http://127.0.0.1:8081",
|
|
280
|
-
"apiKey": "your-secret-key",
|
|
281
|
-
...
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
```
|
|
26
|
+
## Key Benefits
|
|
27
|
+
- **Multi-Account**: Proxy handles rate limits by switching ChatGPT accounts.
|
|
28
|
+
- **SSE Streaming**: Full real-time response support.
|
|
29
|
+
- **Tool Calling**: Native support for agentic workflows.
|
|
286
30
|
|
|
287
31
|
## Troubleshooting
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
Ensure the proxy is running:
|
|
292
|
-
```bash
|
|
293
|
-
curl http://127.0.0.1:8081/health
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### Models Not Showing
|
|
297
|
-
|
|
298
|
-
1. Verify config file is valid JSON
|
|
299
|
-
2. Check `mode` is set to `"merge"`
|
|
300
|
-
3. Restart OpenClaw after config changes:
|
|
301
|
-
```bash
|
|
302
|
-
openclaw gateway restart
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### Rate Limiting
|
|
306
|
-
|
|
307
|
-
If you see rate limit errors:
|
|
308
|
-
1. Add more ChatGPT accounts to the proxy
|
|
309
|
-
2. The proxy will auto-switch between accounts
|
|
310
|
-
3. Check `/accounts` endpoint for account status
|
|
311
|
-
|
|
312
|
-
### Use 127.0.0.1 Not localhost
|
|
313
|
-
|
|
314
|
-
Always use `127.0.0.1` instead of `localhost` in `baseUrl`:
|
|
315
|
-
- Avoids DNS resolution issues
|
|
316
|
-
- Explicitly stays on loopback interface
|
|
317
|
-
- Prevents accidental exposure on VPS
|
|
318
|
-
|
|
319
|
-
## Comparison: Codex Proxy vs Antigravity Proxy
|
|
320
|
-
|
|
321
|
-
| Feature | Codex-Claude-Proxy | Antigravity Proxy |
|
|
322
|
-
|---------|-------------------|-------------------|
|
|
323
|
-
| Backend API | ChatGPT Codex API | Google Cloud Code API |
|
|
324
|
-
| Models | GPT-5.2/5.3 Codex | Gemini 3, Claude (via Google) |
|
|
325
|
-
| Auth | ChatGPT OAuth | Google OAuth |
|
|
326
|
-
| Account Source | ChatGPT accounts | Google accounts |
|
|
327
|
-
| Rate Limits | ChatGPT limits | Google Cloud quotas |
|
|
328
|
-
| Best For | Codex-native access | Google Cloud users |
|
|
329
|
-
|
|
330
|
-
Both proxies expose the same Anthropic-compatible API, so OpenClaw configuration is nearly identical.
|
|
331
|
-
|
|
332
|
-
## Further Reading
|
|
333
|
-
|
|
334
|
-
- [OpenClaw Documentation](https://docs.openclaw.ai/)
|
|
335
|
-
- [OpenClaw Configuration Reference](https://docs.openclaw.ai/gateway/configuration)
|
|
336
|
-
- [Proxy API Reference](./API.md)
|
|
337
|
-
- [Account Management](./ACCOUNTS.md)
|
|
338
|
-
- [OAuth Setup](./OAUTH.md)
|
|
32
|
+
- Use `127.0.0.1` instead of `localhost`.
|
|
33
|
+
- Verify proxy health: `curl http://127.0.0.1:8081/health`.
|
package/docs/legal.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Legal
|
|
2
|
+
|
|
3
|
+
- **Not affiliated with OpenAI or Anthropic.** This is an independent open-source project and is not endorsed by, sponsored by, or affiliated with OpenAI or Anthropic.
|
|
4
|
+
|
|
5
|
+
- "ChatGPT", "OpenAI", and "Codex" are trademarks of OpenAI.
|
|
6
|
+
|
|
7
|
+
- "Claude" and "Anthropic" are trademarks of Anthropic PBC.
|
|
8
|
+
|
|
9
|
+
- "Kilo" and "Kilo Search" are trademarks of their respective owners.
|
|
10
|
+
|
|
11
|
+
- Software is provided "as is", without warranty. You are responsible for complying with all applicable Terms of Service and Acceptable Use Policies.
|
|
Binary file
|
package/package.json
CHANGED
package/public/js/app.js
CHANGED
package/src/account-manager.js
CHANGED
|
@@ -26,10 +26,10 @@ const tokenCache = new Map();
|
|
|
26
26
|
|
|
27
27
|
function ensureConfigDir() {
|
|
28
28
|
if (!existsSync(CONFIG_DIR)) {
|
|
29
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
29
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
30
30
|
}
|
|
31
31
|
if (!existsSync(ACCOUNTS_DIR)) {
|
|
32
|
-
mkdirSync(ACCOUNTS_DIR, { recursive: true });
|
|
32
|
+
mkdirSync(ACCOUNTS_DIR, { recursive: true, mode: 0o700 });
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -64,7 +64,7 @@ function loadAccounts() {
|
|
|
64
64
|
|
|
65
65
|
function saveAccounts(data) {
|
|
66
66
|
ensureConfigDir();
|
|
67
|
-
writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2));
|
|
67
|
+
writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
function getActiveAccount() {
|
|
@@ -80,7 +80,7 @@ function updateAccountAuth(account) {
|
|
|
80
80
|
const authFile = getAccountAuthFile(account.email);
|
|
81
81
|
|
|
82
82
|
if (!existsSync(accountDir)) {
|
|
83
|
-
mkdirSync(accountDir, { recursive: true });
|
|
83
|
+
mkdirSync(accountDir, { recursive: true, mode: 0o700 });
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
const authData = {
|
|
@@ -96,7 +96,7 @@ function updateAccountAuth(account) {
|
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
try {
|
|
99
|
-
writeFileSync(authFile, JSON.stringify(authData, null, 2));
|
|
99
|
+
writeFileSync(authFile, JSON.stringify(authData, null, 2), { mode: 0o600 });
|
|
100
100
|
console.log(`[AccountManager] Updated auth for: ${account.email}`);
|
|
101
101
|
} catch (e) {
|
|
102
102
|
console.error('[AccountManager] Failed to update auth:', e.message);
|
package/src/claude-config.js
CHANGED
|
@@ -60,13 +60,13 @@ export async function updateClaudeConfig(updates) {
|
|
|
60
60
|
|
|
61
61
|
const configDir = path.dirname(configPath);
|
|
62
62
|
try {
|
|
63
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
63
|
+
await fs.mkdir(configDir, { recursive: true, mode: 0o700 });
|
|
64
64
|
} catch (error) {
|
|
65
65
|
// Ignore if exists
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
try {
|
|
69
|
-
await fs.writeFile(configPath, JSON.stringify(newConfig, null, 2), 'utf8');
|
|
69
|
+
await fs.writeFile(configPath, JSON.stringify(newConfig, null, 2), { encoding: 'utf8', mode: 0o600 });
|
|
70
70
|
console.log(`[ClaudeConfig] Updated config at ${configPath}`);
|
|
71
71
|
return newConfig;
|
|
72
72
|
} catch (error) {
|
package/src/cli/accounts.js
CHANGED
|
@@ -39,9 +39,9 @@ function saveAccounts(data) {
|
|
|
39
39
|
try {
|
|
40
40
|
const dir = dirname(ACCOUNTS_FILE);
|
|
41
41
|
if (!existsSync(dir)) {
|
|
42
|
-
mkdirSync(dir, { recursive: true });
|
|
42
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
43
43
|
}
|
|
44
|
-
writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2));
|
|
44
|
+
writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
45
45
|
console.log(`\n✓ Saved ${data.accounts.length} account(s) to ${ACCOUNTS_FILE}`);
|
|
46
46
|
} catch (error) {
|
|
47
47
|
console.error('Error saving accounts:', error.message);
|
package/src/index.js
CHANGED
|
@@ -13,7 +13,7 @@ startServer({ port: PORT });
|
|
|
13
13
|
|
|
14
14
|
console.log(`
|
|
15
15
|
╔══════════════════════════════════════════════════════════════╗
|
|
16
|
-
║ Codex Claude Proxy
|
|
16
|
+
║ Codex Claude Proxy v1.0.2 ║
|
|
17
17
|
║ (Direct API Mode) ║
|
|
18
18
|
╠══════════════════════════════════════════════════════════════╣
|
|
19
19
|
║ Server: http://localhost:${PORT} ║
|
package/src/server-settings.js
CHANGED
|
@@ -10,7 +10,7 @@ const DEFAULT_SETTINGS = {
|
|
|
10
10
|
|
|
11
11
|
function ensureConfigDir() {
|
|
12
12
|
if (!existsSync(CONFIG_DIR)) {
|
|
13
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
13
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -35,7 +35,7 @@ export function setServerSettings(patch = {}) {
|
|
|
35
35
|
const next = { ...current, ...patch };
|
|
36
36
|
|
|
37
37
|
ensureConfigDir();
|
|
38
|
-
writeFileSync(SETTINGS_FILE, JSON.stringify(next, null, 2));
|
|
38
|
+
writeFileSync(SETTINGS_FILE, JSON.stringify(next, null, 2), { mode: 0o600 });
|
|
39
39
|
return next;
|
|
40
40
|
}
|
|
41
41
|
|
package/src/server.js
CHANGED
|
@@ -14,7 +14,34 @@ export function createServer({ port }) {
|
|
|
14
14
|
startAutoRefresh();
|
|
15
15
|
|
|
16
16
|
const app = express();
|
|
17
|
-
app.
|
|
17
|
+
app.disable('x-powered-by');
|
|
18
|
+
|
|
19
|
+
// High-level request logging
|
|
20
|
+
app.use((req, res, next) => {
|
|
21
|
+
const start = Date.now();
|
|
22
|
+
res.on('finish', () => {
|
|
23
|
+
const duration = Date.now() - start;
|
|
24
|
+
const msg = `[${req.method}] ${req.originalUrl} ${res.statusCode} (${duration}ms)`;
|
|
25
|
+
if (res.statusCode >= 400) {
|
|
26
|
+
console.log(`\x1b[31m${msg}\x1b[0m`); // Red for error
|
|
27
|
+
} else if (req.originalUrl !== '/health') { // Skip health check logs to reduce noise
|
|
28
|
+
console.log(`\x1b[36m${msg}\x1b[0m`); // Cyan for success
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
next();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
app.use(cors({
|
|
35
|
+
origin: [
|
|
36
|
+
`http://localhost:${port}`,
|
|
37
|
+
`http://127.0.0.1:${port}`,
|
|
38
|
+
'http://localhost',
|
|
39
|
+
'http://127.0.0.1'
|
|
40
|
+
],
|
|
41
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
42
|
+
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
43
|
+
credentials: false
|
|
44
|
+
}));
|
|
18
45
|
app.use(express.json({ limit: '10mb' }));
|
|
19
46
|
|
|
20
47
|
registerApiRoutes(app, { port });
|