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 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: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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
@@ -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
+ }