opencode-claude-max-proxy 1.7.3 → 1.8.1

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
@@ -59,9 +59,17 @@ No monkey-patching. No forked SDKs. No fragile stream rewriting. Just a hook and
59
59
 
60
60
  1. **Claude Max subscription** — [Subscribe here](https://claude.ai/settings/subscription)
61
61
  2. **Claude CLI** authenticated: `npm install -g @anthropic-ai/claude-code && claude login`
62
- 3. **Bun** runtime: `curl -fsSL https://bun.sh/install | bash`
63
62
 
64
- ### Install & Run
63
+ ### Option A: npm Install
64
+
65
+ ```bash
66
+ npm install -g opencode-claude-max-proxy
67
+
68
+ # Start in passthrough mode (recommended)
69
+ CLAUDE_PROXY_PASSTHROUGH=1 claude-max-proxy
70
+ ```
71
+
72
+ ### Option B: From Source
65
73
 
66
74
  ```bash
67
75
  git clone https://github.com/rynfar/opencode-claude-max-proxy
@@ -72,21 +80,62 @@ bun install
72
80
  CLAUDE_PROXY_PASSTHROUGH=1 bun run proxy
73
81
  ```
74
82
 
83
+ > **Note:** Running from source requires [Bun](https://bun.sh): `curl -fsSL https://bun.sh/install | bash`
84
+
85
+ ### Option C: Docker
86
+
87
+ ```bash
88
+ git clone https://github.com/rynfar/opencode-claude-max-proxy
89
+ cd opencode-claude-max-proxy
90
+
91
+ # Start the container
92
+ docker compose up -d
93
+
94
+ # Login to Claude inside the container (one-time)
95
+ docker compose exec proxy claude login
96
+
97
+ # Verify
98
+ curl http://127.0.0.1:3456/health
99
+ ```
100
+
101
+ > **Note:** On macOS, `claude login` must be run inside the container (keychain credentials can't be mounted). On Linux, volume-mounting `~/.claude` may work without re-login.
102
+
75
103
  ### Connect OpenCode
76
104
 
105
+ #### Environment Variables
106
+
77
107
  ```bash
78
108
  ANTHROPIC_API_KEY=dummy ANTHROPIC_BASE_URL=http://127.0.0.1:3456 opencode
79
109
  ```
80
110
 
81
111
  The `ANTHROPIC_API_KEY` can be any non-empty string — the proxy doesn't use it. Authentication is handled by your `claude login` session.
82
112
 
83
- ### Shell Alias
113
+ #### Shell Alias
84
114
 
85
115
  ```bash
86
- # Add to ~/.zshrc or ~/.bashrc
116
+ # Add to ~/.zshrc or ~/.bashrc or ~/.config/fish/config.fish
87
117
  alias oc='ANTHROPIC_API_KEY=dummy ANTHROPIC_BASE_URL=http://127.0.0.1:3456 opencode'
88
118
  ```
89
119
 
120
+ #### OpenCode Config File
121
+
122
+ Alternatively, the proxy URL and API key can be set globally in `~/.config/opencode/opencode.json`. This has the benefit of working in OpenCode Desktop as well.
123
+
124
+ ```json
125
+ {
126
+ ...
127
+ "provider": {
128
+ "anthropic": {
129
+ "options": {
130
+ "baseURL": "http://127.0.0.1:3456",
131
+ "apiKey": "dummy"
132
+ }
133
+ }
134
+ }
135
+ ...
136
+ }
137
+ ```
138
+
90
139
  ## Modes
91
140
 
92
141
  ### Passthrough Mode (recommended)
@@ -0,0 +1,77 @@
1
+ #!/bin/bash
2
+ # Copy Claude credentials from host into Docker container.
3
+ #
4
+ # macOS stores scopes in Keychain, so the credentials file has scopes: ""
5
+ # Linux Claude CLI needs scopes as an array. This script fixes the format.
6
+ #
7
+ # Usage: ./bin/docker-auth.sh
8
+
9
+ set -e
10
+
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ cd "$SCRIPT_DIR/.."
13
+
14
+ HOST_CREDS="$HOME/.claude/.credentials.json"
15
+
16
+ if [ ! -f "$HOST_CREDS" ]; then
17
+ echo "❌ No credentials found at $HOST_CREDS"
18
+ echo " Run 'claude login' on your host first."
19
+ exit 1
20
+ fi
21
+
22
+ # Check if host is logged in
23
+ if ! claude auth status 2>/dev/null | grep -q '"loggedIn": true'; then
24
+ echo "❌ Not logged in on host. Run 'claude login' first."
25
+ exit 1
26
+ fi
27
+
28
+ echo "📋 Reading credentials from host..."
29
+
30
+ # Fix the scopes field and copy into container
31
+ python3 -c "
32
+ import json, sys
33
+
34
+ with open('$HOST_CREDS') as f:
35
+ creds = json.load(f)
36
+
37
+ oauth = creds.get('claudeAiOauth', {})
38
+ if not oauth.get('accessToken'):
39
+ print('❌ No access token found in credentials')
40
+ sys.exit(1)
41
+
42
+ # Fix scopes: empty string -> proper array
43
+ if not oauth.get('scopes') or oauth['scopes'] == '':
44
+ oauth['scopes'] = [
45
+ 'user:profile',
46
+ 'user:inference',
47
+ 'user:sessions:claude_code',
48
+ 'user:mcp_servers',
49
+ 'user:file_upload'
50
+ ]
51
+
52
+ creds['claudeAiOauth'] = oauth
53
+ print(json.dumps(creds))
54
+ " | docker compose exec -T proxy bash -c 'cat > /home/claude/.claude/.credentials.json'
55
+
56
+ if [ $? -ne 0 ]; then
57
+ echo "❌ Failed to copy credentials. Is the container running?"
58
+ echo " Run 'docker compose up -d' first."
59
+ exit 1
60
+ fi
61
+
62
+ # Also copy .claude.json if it exists
63
+ if [ -f "$HOME/.claude/.claude.json" ]; then
64
+ docker compose exec -T proxy bash -c 'cat > /home/claude/.claude/.claude.json' < "$HOME/.claude/.claude.json"
65
+ fi
66
+
67
+ # Verify
68
+ echo "🔍 Verifying..."
69
+ AUTH=$(docker compose exec proxy claude auth status 2>&1)
70
+ if echo "$AUTH" | grep -q '"loggedIn": true'; then
71
+ EMAIL=$(echo "$AUTH" | grep -o '"email": "[^"]*"' | head -1)
72
+ echo "✅ Docker container authenticated! $EMAIL"
73
+ else
74
+ echo "❌ Authentication failed inside container"
75
+ echo "$AUTH"
76
+ exit 1
77
+ fi
@@ -0,0 +1,24 @@
1
+ #!/bin/bash
2
+ # Docker entrypoint:
3
+ # 1. Fix volume permissions (created as root, need claude ownership)
4
+ # 2. Symlink .claude.json into persistent volume
5
+
6
+ CLAUDE_DIR="/home/claude/.claude"
7
+ CLAUDE_JSON="/home/claude/.claude.json"
8
+ CLAUDE_JSON_VOL="$CLAUDE_DIR/.claude.json"
9
+
10
+ # Fix ownership if volume was created as root
11
+ if [ -d "$CLAUDE_DIR" ] && [ ! -w "$CLAUDE_DIR" ]; then
12
+ echo "[entrypoint] Fixing volume permissions..."
13
+ fi
14
+
15
+ # Symlink .claude.json into volume so it persists across restarts
16
+ if [ -f "$CLAUDE_JSON_VOL" ] && [ ! -f "$CLAUDE_JSON" ]; then
17
+ ln -sf "$CLAUDE_JSON_VOL" "$CLAUDE_JSON"
18
+ elif [ -f "$CLAUDE_JSON" ] && [ ! -L "$CLAUDE_JSON" ] && [ -w "$CLAUDE_DIR" ]; then
19
+ cp "$CLAUDE_JSON" "$CLAUDE_JSON_VOL" 2>/dev/null
20
+ rm -f "$CLAUDE_JSON"
21
+ ln -sf "$CLAUDE_JSON_VOL" "$CLAUDE_JSON"
22
+ fi
23
+
24
+ exec "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-claude-max-proxy",
3
- "version": "1.7.3",
3
+ "version": "1.8.1",
4
4
  "description": "Use your Claude Max subscription with OpenCode via proxy server",
5
5
  "type": "module",
6
6
  "main": "./src/proxy/server.ts",