opencode-with-claude 1.0.0
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/LICENSE +21 -0
- package/README.md +280 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +137 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ian White
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# opencode-with-claude
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
|
|
5
|
+
Use [OpenCode](https://opencode.ai) with your [Claude Max](https://claude.ai) subscription.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────┐ ┌────────────────────┐ ┌─────────────────┐
|
|
11
|
+
│ OpenCode │──────▶│ Claude Max Proxy │──────▶│ Anthropic │
|
|
12
|
+
│ (TUI/Web) │ :3456 │ (local server) │ SDK │ Claude Max │
|
|
13
|
+
│ │◀──────│ │◀──────│ │
|
|
14
|
+
└─────────────┘ └────────────────────┘ └─────────────────┘
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
[OpenCode](https://opencode.ai) speaks the Anthropic REST API. Claude Max provides access via the [Claude Agent SDK](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) (not the REST API). The [opencode-claude-max-proxy](https://github.com/rynfar/opencode-claude-max-proxy) bridges the gap — it accepts API requests from OpenCode and translates them into Agent SDK calls using your Claude Max session.
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
There are three ways to get started: the **plugin** (recommended), the **standalone installer**, or **Docker**.
|
|
22
|
+
|
|
23
|
+
### Option A: OpenCode Plugin (recommended)
|
|
24
|
+
|
|
25
|
+
The plugin manages the proxy lifecycle automatically — it starts the proxy when OpenCode launches, health-checks it, and cleans up on exit.
|
|
26
|
+
|
|
27
|
+
**1. Authenticate with Claude (one-time)**
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install -g @anthropic-ai/claude-code
|
|
31
|
+
claude login
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**2. Add to your `opencode.json`**
|
|
35
|
+
|
|
36
|
+
Global (`~/.config/opencode/opencode.json`) or project-level:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"$schema": "https://opencode.ai/config.json",
|
|
41
|
+
"plugin": ["opencode-with-claude"],
|
|
42
|
+
"provider": {
|
|
43
|
+
"anthropic": {
|
|
44
|
+
"options": {
|
|
45
|
+
"baseURL": "http://127.0.0.1:3456",
|
|
46
|
+
"apiKey": "dummy"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**3. Run OpenCode**
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
opencode
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
That's it. The plugin handles everything.
|
|
60
|
+
|
|
61
|
+
### Option B: Standalone Installer (`oc` launcher)
|
|
62
|
+
|
|
63
|
+
A one-liner that installs all dependencies and gives you the `oc` command — no config files to edit.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
curl -fsSL https://raw.githubusercontent.com/ianjwhite99/opencode-with-claude/main/install.sh | bash
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This installs:
|
|
70
|
+
- [Claude Code CLI](https://www.npmjs.com/package/@anthropic-ai/claude-code) — authentication with Claude
|
|
71
|
+
- [OpenCode](https://www.npmjs.com/package/opencode-ai) — the coding assistant
|
|
72
|
+
- [opencode-claude-max-proxy](https://www.npmjs.com/package/opencode-claude-max-proxy) — bridges OpenCode to Claude Max
|
|
73
|
+
- **`oc`** — launcher that ties it all together
|
|
74
|
+
|
|
75
|
+
Then run:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
cd your-project
|
|
79
|
+
oc
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The `oc` command starts the proxy in the background, waits for it to be ready, and launches OpenCode.
|
|
83
|
+
|
|
84
|
+
### Option C: Docker
|
|
85
|
+
|
|
86
|
+
Run everything in a container with the OpenCode web UI exposed on port 4096.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git clone https://github.com/ianjwhite99/opencode-with-claude.git
|
|
90
|
+
cd opencode-with-claude
|
|
91
|
+
|
|
92
|
+
# Build and start
|
|
93
|
+
docker compose -f docker/docker-compose.yml up -d
|
|
94
|
+
|
|
95
|
+
# Authenticate (first time only)
|
|
96
|
+
docker exec -it -u opencode opencode-with-claude claude login
|
|
97
|
+
|
|
98
|
+
# Open the web UI
|
|
99
|
+
open http://localhost:4096
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The container runs the proxy and OpenCode web UI together. Your `~/workspace` directory is mounted into the container, and Claude auth, OpenCode data, and config are persisted across restarts via Docker volumes.
|
|
103
|
+
|
|
104
|
+
## Prerequisites
|
|
105
|
+
|
|
106
|
+
- **Node.js >= 18** — [nodejs.org](https://nodejs.org) (or Bun/Deno) — not needed for Docker
|
|
107
|
+
- **Claude Max subscription** — the $100/mo plan on [claude.ai](https://claude.ai)
|
|
108
|
+
|
|
109
|
+
## `oc` Launcher Reference
|
|
110
|
+
|
|
111
|
+
The `oc` launcher handles everything — starts the proxy, waits for health, launches OpenCode, and cleans up on exit:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
oc # Start OpenCode TUI in current directory
|
|
115
|
+
oc web # Start OpenCode web UI on port 4096
|
|
116
|
+
oc update # Update all components to latest versions
|
|
117
|
+
oc --help # Show help
|
|
118
|
+
oc --version # Show component versions
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
All arguments are passed through to `opencode`, so anything that works with `opencode` works with `oc`.
|
|
122
|
+
|
|
123
|
+
### Installer Options
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Skip the Claude login prompt
|
|
127
|
+
curl -fsSL ... | bash -s -- --no-auth
|
|
128
|
+
|
|
129
|
+
# Don't modify shell PATH
|
|
130
|
+
curl -fsSL ... | bash -s -- --no-modify-path
|
|
131
|
+
|
|
132
|
+
# Show help
|
|
133
|
+
curl -fsSL ... | bash -s -- --help
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Uninstalling
|
|
137
|
+
|
|
138
|
+
Remove the `oc` launcher and clean up PATH entries:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
curl -fsSL https://raw.githubusercontent.com/ianjwhite99/opencode-with-claude/main/install.sh | bash -s -- --uninstall
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
This removes the `oc` launcher from `~/.opencode/bin` and cleans up any PATH entries added to your shell config. To also remove the underlying tools:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npm uninstall -g @anthropic-ai/claude-code opencode-ai opencode-claude-max-proxy
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Configuration
|
|
151
|
+
|
|
152
|
+
### Environment Variables
|
|
153
|
+
|
|
154
|
+
| Variable | Default | Description |
|
|
155
|
+
|----------|---------|-------------|
|
|
156
|
+
| `CLAUDE_PROXY_PORT` | `3456` (plugin/Docker) / random (`oc`) | Port for the proxy server |
|
|
157
|
+
| `CLAUDE_PROXY_WORKDIR` | `$PWD` | Working directory for the proxy |
|
|
158
|
+
| `OC_SKIP_AUTH_CHECK` | unset | Set to `1` to skip Claude auth check on `oc` launch |
|
|
159
|
+
| `OC_AUTO_UPDATE` | unset | Set to `true` or `1` to auto-update components on Docker container start |
|
|
160
|
+
|
|
161
|
+
## Troubleshooting
|
|
162
|
+
|
|
163
|
+
### "Claude Code CLI not found"
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm install -g @anthropic-ai/claude-code
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### "Claude not authenticated"
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
claude login
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
This opens a browser for OAuth. Your Claude Max subscription credentials are needed.
|
|
176
|
+
|
|
177
|
+
### "Proxy failed to start"
|
|
178
|
+
|
|
179
|
+
1. Check Claude auth: `claude auth status`
|
|
180
|
+
2. Check if the port is in use: `lsof -i :3456`
|
|
181
|
+
3. Try a different port: set `CLAUDE_PROXY_PORT=4567` and update `baseURL` in `opencode.json` to match
|
|
182
|
+
|
|
183
|
+
### "Proxy didn't become healthy within 10 seconds"
|
|
184
|
+
|
|
185
|
+
The proxy takes a moment to initialize. If this persists:
|
|
186
|
+
- Ensure `claude auth status` shows `loggedIn: true`
|
|
187
|
+
- Check your internet connection
|
|
188
|
+
|
|
189
|
+
### Updating components
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# oc launcher
|
|
193
|
+
oc update
|
|
194
|
+
|
|
195
|
+
# Plugin / manual
|
|
196
|
+
npm install -g @anthropic-ai/claude-code opencode-ai opencode-claude-max-proxy
|
|
197
|
+
|
|
198
|
+
# Docker
|
|
199
|
+
docker compose -f docker/docker-compose.yml build --no-cache && docker compose -f docker/docker-compose.yml up -d
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Development
|
|
203
|
+
|
|
204
|
+
### Project Structure
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
opencode-with-claude/
|
|
208
|
+
├── src/
|
|
209
|
+
│ └── index.ts # Plugin entry point
|
|
210
|
+
├── bin/
|
|
211
|
+
│ └── oc # Standalone launcher
|
|
212
|
+
├── docker/
|
|
213
|
+
│ ├── Dockerfile # All-in-one Docker image
|
|
214
|
+
│ ├── docker-compose.yml # Docker Compose config
|
|
215
|
+
│ └── entrypoint.sh # Docker entrypoint
|
|
216
|
+
├── install.sh # curl | bash installer
|
|
217
|
+
├── test/
|
|
218
|
+
│ ├── run.sh # Test runner
|
|
219
|
+
│ └── opencode.json # Test config
|
|
220
|
+
├── package.json
|
|
221
|
+
└── tsconfig.json
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Build
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
npm install
|
|
228
|
+
npm run build
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Test locally
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
./test/run.sh # Build and launch OpenCode with the plugin
|
|
235
|
+
./test/run.sh --clean # Remove build artifacts
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## FAQ
|
|
239
|
+
|
|
240
|
+
**Do I need an Anthropic API key?**
|
|
241
|
+
|
|
242
|
+
No. The proxy authenticates through your Claude Max subscription via `claude login`. The `ANTHROPIC_API_KEY=dummy` value is just a placeholder that OpenCode requires — it's never actually used.
|
|
243
|
+
|
|
244
|
+
**What happens if my Claude Max subscription expires?**
|
|
245
|
+
|
|
246
|
+
The proxy will fail to authenticate. Run `claude auth status` to check. You'll need an active Claude Max ($100/mo) or Claude Max with Team ($200/mo) subscription.
|
|
247
|
+
|
|
248
|
+
**Plugin, `oc`, or Docker — which should I use?**
|
|
249
|
+
|
|
250
|
+
The **plugin** is recommended if you already use OpenCode — it integrates with OpenCode's plugin system and requires no extra commands. Use the **`oc` launcher** if you want a one-command install from scratch or prefer not to edit config files. Use **Docker** if you want an isolated environment or want to run the web UI as a service.
|
|
251
|
+
|
|
252
|
+
**Can I use this with multiple projects at the same time?**
|
|
253
|
+
|
|
254
|
+
Yes. The `oc` launcher assigns a random port for each terminal session. The plugin uses a fixed port (`3456` by default), so configure `CLAUDE_PROXY_PORT` if running multiple instances.
|
|
255
|
+
|
|
256
|
+
**Is this the same as using the Anthropic API?**
|
|
257
|
+
|
|
258
|
+
Not exactly. The proxy translates between the Anthropic REST API format and the Claude Agent SDK. From OpenCode's perspective it looks like the API, but under the hood it uses your Claude Max session. Rate limits are determined by your Claude Max subscription, not API tier limits.
|
|
259
|
+
|
|
260
|
+
**Why `claude login` instead of an API key?**
|
|
261
|
+
|
|
262
|
+
Claude Max doesn't provide API access. Authentication goes through the Claude Code CLI's OAuth flow, which grants an Agent SDK session token tied to your subscription.
|
|
263
|
+
|
|
264
|
+
## Disclaimer
|
|
265
|
+
|
|
266
|
+
This project is an **unofficial wrapper** around Anthropic's publicly available Claude Agent SDK and OpenCode. It is not affiliated with, endorsed by, or supported by Anthropic or OpenCode.
|
|
267
|
+
|
|
268
|
+
**Use at your own risk.** The authors make no claims regarding compliance with Anthropic's Terms of Service. It is your responsibility to review and comply with Anthropic's [Terms of Service](https://www.anthropic.com/terms) and [Authorized Usage Policy](https://www.anthropic.com/aup). Terms may change at any time.
|
|
269
|
+
|
|
270
|
+
This project calls publicly available npm packages using your own authenticated account. No API keys are intercepted, no authentication is bypassed, and no proprietary systems are reverse-engineered.
|
|
271
|
+
|
|
272
|
+
## Credits
|
|
273
|
+
|
|
274
|
+
Built on top of [opencode-claude-max-proxy](https://github.com/rynfar/opencode-claude-max-proxy) by [@rynfar](https://github.com/rynfar), which provides the core proxy that bridges the Anthropic Agent SDK to the standard API.
|
|
275
|
+
|
|
276
|
+
Powered by the [Claude Agent SDK](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) by Anthropic and [OpenCode](https://opencode.ai).
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
+
/**
|
|
3
|
+
* OpenCode plugin that manages the Claude Max proxy lifecycle.
|
|
4
|
+
*
|
|
5
|
+
* On init:
|
|
6
|
+
* 1. Verifies the Claude CLI is installed and authenticated
|
|
7
|
+
* 2. Resolves the bundled claude-max-proxy binary
|
|
8
|
+
* 3. Spawns the proxy on a local port
|
|
9
|
+
* 4. Waits for the proxy to become healthy
|
|
10
|
+
* 5. Registers cleanup handlers to kill the proxy on exit
|
|
11
|
+
*
|
|
12
|
+
* Requires provider config in opencode.json to route API traffic through the proxy:
|
|
13
|
+
* "provider": { "anthropic": { "options": { "baseURL": "http://127.0.0.1:3456", "apiKey": "dummy" } } }
|
|
14
|
+
*/
|
|
15
|
+
export declare const ClaudeMaxPlugin: Plugin;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { createRequire } from "module";
|
|
3
|
+
const DEFAULT_PORT = 3456;
|
|
4
|
+
const HEALTH_TIMEOUT_MS = 10_000;
|
|
5
|
+
const HEALTH_INTERVAL_MS = 100;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the claude-max-proxy binary from this package's bundled dependency.
|
|
8
|
+
*/
|
|
9
|
+
function resolveProxyBin() {
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const proxyPkgPath = require.resolve("opencode-claude-max-proxy/package.json");
|
|
12
|
+
const proxyDir = proxyPkgPath.replace(/\/package\.json$/, "");
|
|
13
|
+
const proxyPkg = require(proxyPkgPath);
|
|
14
|
+
const binEntries = proxyPkg.bin;
|
|
15
|
+
if (!binEntries || typeof binEntries !== "object") {
|
|
16
|
+
throw new Error("Could not find claude-max-proxy binary in opencode-claude-max-proxy package");
|
|
17
|
+
}
|
|
18
|
+
const binPath = Object.values(binEntries)[0];
|
|
19
|
+
if (!binPath) {
|
|
20
|
+
throw new Error("claude-max-proxy package has no bin entry");
|
|
21
|
+
}
|
|
22
|
+
return `${proxyDir}/${binPath}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Poll the proxy health endpoint until it responds OK or timeout.
|
|
26
|
+
*/
|
|
27
|
+
async function waitForHealth(port, timeoutMs, proxy) {
|
|
28
|
+
const start = Date.now();
|
|
29
|
+
while (Date.now() - start < timeoutMs) {
|
|
30
|
+
// Check if proxy process died
|
|
31
|
+
if (proxy.exitCode !== null) {
|
|
32
|
+
throw new Error("Claude Max proxy process exited unexpectedly. Is Claude authenticated? Run: claude login");
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const res = await fetch(`http://127.0.0.1:${port}/health`);
|
|
36
|
+
if (res.ok)
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Not ready yet
|
|
41
|
+
}
|
|
42
|
+
await new Promise((r) => setTimeout(r, HEALTH_INTERVAL_MS));
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`Claude Max proxy didn't become healthy within ${timeoutMs / 1000}s. Check: claude auth status`);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* OpenCode plugin that manages the Claude Max proxy lifecycle.
|
|
48
|
+
*
|
|
49
|
+
* On init:
|
|
50
|
+
* 1. Verifies the Claude CLI is installed and authenticated
|
|
51
|
+
* 2. Resolves the bundled claude-max-proxy binary
|
|
52
|
+
* 3. Spawns the proxy on a local port
|
|
53
|
+
* 4. Waits for the proxy to become healthy
|
|
54
|
+
* 5. Registers cleanup handlers to kill the proxy on exit
|
|
55
|
+
*
|
|
56
|
+
* Requires provider config in opencode.json to route API traffic through the proxy:
|
|
57
|
+
* "provider": { "anthropic": { "options": { "baseURL": "http://127.0.0.1:3456", "apiKey": "dummy" } } }
|
|
58
|
+
*/
|
|
59
|
+
export const ClaudeMaxPlugin = async ({ client, $, directory }) => {
|
|
60
|
+
const log = (level, message) => client.app.log({
|
|
61
|
+
body: { service: "opencode-with-claude", level, message },
|
|
62
|
+
});
|
|
63
|
+
// 1. Check claude CLI exists
|
|
64
|
+
try {
|
|
65
|
+
await $ `which claude`;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new Error("Claude Code CLI not found. Install it with: npm install -g @anthropic-ai/claude-code");
|
|
69
|
+
}
|
|
70
|
+
// 2. Check authentication
|
|
71
|
+
let authOutput;
|
|
72
|
+
try {
|
|
73
|
+
authOutput = await $ `claude auth status`.text();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
throw new Error("Failed to check Claude auth status. Run: claude login");
|
|
77
|
+
}
|
|
78
|
+
if (!authOutput.includes('"loggedIn": true')) {
|
|
79
|
+
throw new Error("Claude not authenticated. Run: claude login");
|
|
80
|
+
}
|
|
81
|
+
await log("info", "Claude authentication verified");
|
|
82
|
+
// 3. Resolve proxy binary (bundled dependency)
|
|
83
|
+
let proxyBin;
|
|
84
|
+
try {
|
|
85
|
+
proxyBin = resolveProxyBin();
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
throw new Error(`Failed to resolve claude-max-proxy binary: ${err instanceof Error ? err.message : err}`);
|
|
89
|
+
}
|
|
90
|
+
// 4. Pick port
|
|
91
|
+
const port = parseInt(process.env.CLAUDE_PROXY_PORT || "", 10) || DEFAULT_PORT;
|
|
92
|
+
// 5. Spawn proxy
|
|
93
|
+
await log("info", `Starting Claude Max proxy on port ${port}...`);
|
|
94
|
+
const proxy = spawn(proxyBin, [], {
|
|
95
|
+
env: {
|
|
96
|
+
...process.env,
|
|
97
|
+
CLAUDE_PROXY_PORT: String(port),
|
|
98
|
+
CLAUDE_PROXY_PASSTHROUGH: "1",
|
|
99
|
+
CLAUDE_PROXY_WORKDIR: directory,
|
|
100
|
+
},
|
|
101
|
+
stdio: "ignore",
|
|
102
|
+
detached: false,
|
|
103
|
+
});
|
|
104
|
+
proxy.on("error", (err) => {
|
|
105
|
+
log("error", `Proxy process error: ${err.message}`);
|
|
106
|
+
});
|
|
107
|
+
// 6. Wait for health
|
|
108
|
+
try {
|
|
109
|
+
await waitForHealth(port, HEALTH_TIMEOUT_MS, proxy);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
// Kill the proxy if health check fails
|
|
113
|
+
try {
|
|
114
|
+
proxy.kill();
|
|
115
|
+
}
|
|
116
|
+
catch { }
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
await log("info", `Claude Max proxy ready on port ${port}`);
|
|
120
|
+
// 7. Cleanup on exit
|
|
121
|
+
let cleaned = false;
|
|
122
|
+
const cleanup = () => {
|
|
123
|
+
if (cleaned)
|
|
124
|
+
return;
|
|
125
|
+
cleaned = true;
|
|
126
|
+
try {
|
|
127
|
+
proxy.kill();
|
|
128
|
+
}
|
|
129
|
+
catch { }
|
|
130
|
+
};
|
|
131
|
+
process.on("exit", cleanup);
|
|
132
|
+
process.on("SIGINT", cleanup);
|
|
133
|
+
process.on("SIGTERM", cleanup);
|
|
134
|
+
// No hooks needed -- proxy runs as a sidecar process.
|
|
135
|
+
// Provider config in opencode.json routes API traffic through the proxy.
|
|
136
|
+
return {};
|
|
137
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-with-claude",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenCode plugin to use your Claude Max subscription via local proxy",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"test": "./test/run.sh",
|
|
14
|
+
"test:clean": "./test/run.sh --clean",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"opencode-claude-max-proxy": "latest"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@opencode-ai/plugin": "latest",
|
|
22
|
+
"@types/node": "^25.5.0",
|
|
23
|
+
"typescript": "^5.0.0"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"opencode",
|
|
27
|
+
"opencode-plugin",
|
|
28
|
+
"claude",
|
|
29
|
+
"claude-max",
|
|
30
|
+
"proxy"
|
|
31
|
+
],
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/ianjwhite99/opencode-with-claude.git"
|
|
36
|
+
}
|
|
37
|
+
}
|