ai-cc-router 0.2.1 → 0.2.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.
@@ -136,7 +136,7 @@ export function writeAddonScript(target) {
136
136
  writeFileSync(ADDON_PATH, src, "utf-8");
137
137
  }
138
138
  else {
139
- // Inline fallback — minimal addon
139
+ // Inline fallback — minimal addon (only redirects /v1/messages and /v1/models)
140
140
  const script = `
141
141
  import os
142
142
  from mitmproxy import http
@@ -144,10 +144,13 @@ from urllib.parse import urlparse
144
144
 
145
145
  _target = os.environ.get("CC_ROUTER_TARGET", ${JSON.stringify(target)}).rstrip("/")
146
146
  _p = urlparse(_target)
147
+ _REDIRECT_PREFIXES = ("/v1/messages", "/v1/models")
147
148
 
148
149
  def request(flow: http.HTTPFlow) -> None:
149
150
  if flow.request.pretty_host != "api.anthropic.com":
150
151
  return
152
+ if not flow.request.path.startswith(_REDIRECT_PREFIXES):
153
+ return
151
154
  flow.request.scheme = _p.scheme
152
155
  flow.request.host = _p.hostname or "localhost"
153
156
  flow.request.port = _p.port or (443 if _p.scheme == "https" else 80)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-cc-router",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Round-robin proxy for Claude Max OAuth tokens — use multiple Claude Max accounts with Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,11 +1,16 @@
1
- # mitmproxy addon — redirects api.anthropic.com traffic to CC-Router.
1
+ # mitmproxy addon — redirects ONLY /v1/messages traffic to CC-Router.
2
2
  #
3
- # Installed and launched by `cc-router client start-desktop`.
4
- # Target URL comes from the CC_ROUTER_TARGET env var (set by the launcher).
3
+ # Claude Desktop sends many types of requests to api.anthropic.com:
4
+ # /v1/messages → LLM inference (this is what we redirect)
5
+ # /v1/messages/count_tokens → token counting (redirect too)
6
+ # /v1/oauth/* → session auth (must NOT redirect)
7
+ # /v1/environments/* → bridge/cowork (must NOT redirect)
8
+ # /v1/models → model listing (redirect — CC-Router proxies this)
9
+ # /api/* → desktop features (must NOT redirect)
5
10
  #
6
- # Why not set the target as a script argument: mitmproxy's addon loader
7
- # does not pass argv through reliably, and env vars give us a single
8
- # unambiguous channel that survives the spawn boundary.
11
+ # Only /v1/messages* and /v1/models are safe to redirect because CC-Router
12
+ # injects its own OAuth token. Everything else carries the user's own
13
+ # session token for features CC-Router doesn't handle.
9
14
 
10
15
  import os
11
16
  from urllib.parse import urlparse
@@ -16,22 +21,27 @@ _target_raw = os.environ.get("CC_ROUTER_TARGET", "http://localhost:3456")
16
21
  _target = _target_raw.rstrip("/")
17
22
  _target_parsed = urlparse(_target)
18
23
 
19
- # Fail closed on boot if the target is unusable — better than silently
20
- # forwarding to a broken URL and seeing Claude Desktop timeout.
21
24
  if not _target_parsed.scheme or not _target_parsed.netloc:
22
25
  raise RuntimeError(f"CC_ROUTER_TARGET is not a valid URL: {_target_raw!r}")
23
26
 
27
+ # Paths that CC-Router can handle (it injects its own OAuth token)
28
+ _REDIRECT_PREFIXES = (
29
+ "/v1/messages",
30
+ "/v1/models",
31
+ )
32
+
24
33
 
25
34
  def request(flow: http.HTTPFlow) -> None:
26
35
  if flow.request.pretty_host != "api.anthropic.com":
27
36
  return
28
37
 
29
- # Preserve path + query (e.g. /v1/messages?beta=oauth-2025-04-20)
30
- # and swap only the scheme + host.
38
+ # Only redirect inference and model-listing paths
39
+ if not flow.request.path.startswith(_REDIRECT_PREFIXES):
40
+ return
41
+
31
42
  flow.request.scheme = _target_parsed.scheme
32
43
  flow.request.host = _target_parsed.hostname or "localhost"
33
44
  flow.request.port = _target_parsed.port or (443 if _target_parsed.scheme == "https" else 80)
34
- # Rewrite the Host header so CC-Router sees itself, not api.anthropic.com.
35
45
  flow.request.headers["host"] = flow.request.host + (
36
46
  f":{flow.request.port}"
37
47
  if flow.request.port not in (80, 443)