@karpeleslab/teamclaude 1.0.9 → 1.1.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/README.md +16 -6
- package/package.json +1 -1
- package/src/index.js +18 -12
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ Sits transparently between Claude Code and the Anthropic API, managing multiple
|
|
|
24
24
|
- **Enable/disable accounts** — temporarily pause an account without removing it (`teamclaude disable`/`enable`, or `d` in the TUI); re-enabling also clears a stuck error state
|
|
25
25
|
- **Quota persistence** — observed quota survives restarts (saved to a sibling state file), so rotation state isn't lost on restart; stale windows are discarded automatically
|
|
26
26
|
- **Optional quota probe** — off by default; when enabled, periodically refreshes idle accounts' quota from the usage endpoint (no message spend), and surfaces the Sonnet weekly bucket
|
|
27
|
-
- **
|
|
27
|
+
- **MITM proxy mode (default)** — `teamclaude run` routes claude via an HTTPS forward proxy with a local CA so even hardcoded `api.anthropic.com` endpoints (e.g. the Claude Design MCP) get the real token injected; pass `--no-mitm` for base-URL routing only
|
|
28
28
|
- **Optional sx.org proxy mode** — off by default; set an [sx.org](https://sx.org) API key in the TUI settings screen (`g`) and TeamClaude auto-provisions a residential proxy to change the egress IP and work around IP-based `429`s. Three modes (`m` to cycle): **always** (route all upstream traffic), **on 429 only** (stay direct, fail over to the proxy after a 429), or **off** (keep the key but don't use it). TLS stays end-to-end with Anthropic (the proxy only relays ciphertext)
|
|
29
29
|
- **Request logging** — optional full request/response logging for debugging
|
|
30
30
|
- **Zero dependencies** — uses only Node.js built-in modules
|
|
@@ -138,6 +138,12 @@ teamclaude run
|
|
|
138
138
|
|
|
139
139
|
`run` probes the proxy first: if it's up, Claude Code is routed through it; if it's **not** running, `claude` is launched directly so nothing breaks.
|
|
140
140
|
|
|
141
|
+
Since **1.1.0**, `run` defaults to [MITM forward-proxy mode](#mitm-proxy-mode-default) so even hardcoded `api.anthropic.com` endpoints (e.g. the Claude Design MCP) are intercepted. To keep the previous base-URL-only behavior, pass `--no-mitm`:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
teamclaude run --no-mitm
|
|
145
|
+
```
|
|
146
|
+
|
|
141
147
|
Or manually set the environment:
|
|
142
148
|
|
|
143
149
|
```bash
|
|
@@ -255,14 +261,18 @@ You can also set the interval live from the TUI settings screen (`g` → `p`), a
|
|
|
255
261
|
|
|
256
262
|
It reads each OAuth account's utilization from Anthropic's usage endpoint (`/api/oauth/usage`), which reports quota **without consuming any message quota**. Minimum interval is 30s. Changing it takes effect on a running server immediately (no restart). When enabled, it also surfaces the **Sonnet 7-day** bucket as an extra bar in the TUI / `status` (when your plan exposes it).
|
|
257
263
|
|
|
258
|
-
### MITM proxy mode (
|
|
264
|
+
### MITM proxy mode (default)
|
|
259
265
|
|
|
260
|
-
The
|
|
266
|
+
The plain reverse-proxy only intercepts what `ANTHROPIC_BASE_URL` covers. Some Claude Code features (e.g. the **Claude Design MCP**) use a **hardcoded** `https://api.anthropic.com` URL that ignores that variable, so they bypass the proxy. MITM proxy mode captures those too, which is why it's the default for `teamclaude run` (and the shell alias):
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
teamclaude run -- <claude args...>
|
|
270
|
+
```
|
|
261
271
|
|
|
262
|
-
|
|
272
|
+
To opt out and route via `ANTHROPIC_BASE_URL` only, pass `--no-mitm`:
|
|
263
273
|
|
|
264
274
|
```bash
|
|
265
|
-
teamclaude run --mitm -- <claude args...>
|
|
275
|
+
teamclaude run --no-mitm -- <claude args...>
|
|
266
276
|
```
|
|
267
277
|
|
|
268
278
|
That launches claude pointed at teamclaude as an **HTTPS forward proxy** (`HTTPS_PROXY`) and trusts a locally-generated CA (`NODE_EXTRA_CA_CERTS`). For an intercepted host, teamclaude **dials the real upstream first, mirrors its negotiated ALPN** (HTTP/2 or HTTP/1.1), then terminates TLS toward claude with the same protocol and relays the traffic **as transparently as possible** — rewriting only what it must:
|
|
@@ -271,7 +281,7 @@ That launches claude pointed at teamclaude as an **HTTPS forward proxy** (`HTTPS
|
|
|
271
281
|
- the **`account_uuid`** inside `metadata.user_id` → the active account's UUID (so the body agrees with the injected token);
|
|
272
282
|
- and it reads `anthropic-ratelimit-*` from responses for quota.
|
|
273
283
|
|
|
274
|
-
Everything else is copied byte-for-byte (HTTP/2 is handled with a built-in HPACK codec so the only header changed is the auth one). Any host other than the upstream is blind-tunnelled. The server accepts *both* base-URL and proxy clients at once, so instances launched with and without `--mitm` can share one server.
|
|
284
|
+
Everything else is copied byte-for-byte (HTTP/2 is handled with a built-in HPACK codec so the only header changed is the auth one). Any host other than the upstream is blind-tunnelled. The server accepts *both* base-URL and proxy clients at once, so instances launched with and without `--no-mitm` can share one server.
|
|
275
285
|
|
|
276
286
|
Trust model:
|
|
277
287
|
- The CA is generated locally, stored in the config dir, and trusted **only** by the claude process you launch via `teamclaude run` (through `NODE_EXTRA_CA_CERTS`) — it is **never** added to your system trust store. The leaf private key is `0600`; the CA private key is never written to disk.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -444,13 +444,18 @@ async function envCommand() {
|
|
|
444
444
|
async function runCommand() {
|
|
445
445
|
const config = await loadOrCreateConfig();
|
|
446
446
|
|
|
447
|
-
// Args after 'run'. teamclaude flags (e.g. --mitm) are recognized only
|
|
448
|
-
// an optional `--` separator; everything after `--` goes verbatim to
|
|
447
|
+
// Args after 'run'. teamclaude flags (e.g. --no-mitm) are recognized only
|
|
448
|
+
// before an optional `--` separator; everything after `--` goes verbatim to
|
|
449
|
+
// claude. MITM forward-proxy mode is the default so hardcoded api.anthropic.com
|
|
450
|
+
// endpoints are intercepted too; --no-mitm opts back into base-URL-only routing.
|
|
451
|
+
// --mitm is still accepted (now a no-op) for backward compatibility.
|
|
449
452
|
const rest = args.slice(1);
|
|
450
453
|
const sep = rest.indexOf('--');
|
|
451
454
|
const tcFlags = sep >= 0 ? rest.slice(0, sep) : rest;
|
|
452
|
-
const useMitm = tcFlags.includes('--mitm');
|
|
453
|
-
const claudeArgs = sep >= 0
|
|
455
|
+
const useMitm = !tcFlags.includes('--no-mitm');
|
|
456
|
+
const claudeArgs = sep >= 0
|
|
457
|
+
? rest.slice(sep + 1)
|
|
458
|
+
: rest.filter(a => a !== '--mitm' && a !== '--no-mitm');
|
|
454
459
|
|
|
455
460
|
// Route through the proxy only when it's actually up; otherwise launch claude
|
|
456
461
|
// directly so a stopped proxy doesn't break `claude`. This is what lets the
|
|
@@ -564,7 +569,7 @@ async function accountsCommand() {
|
|
|
564
569
|
a.refreshToken = newTokens.refreshToken;
|
|
565
570
|
a.expiresAt = newTokens.expiresAt;
|
|
566
571
|
configDirty = true;
|
|
567
|
-
} catch
|
|
572
|
+
} catch {
|
|
568
573
|
// refresh failed — fetchProfile will report the specific error
|
|
569
574
|
}
|
|
570
575
|
}));
|
|
@@ -884,10 +889,11 @@ Commands:
|
|
|
884
889
|
login OAuth login via browser
|
|
885
890
|
login --api Add an API key account
|
|
886
891
|
env Print env vars to use with Claude
|
|
887
|
-
run [--mitm] [-- args...]
|
|
888
|
-
Run Claude Code through the proxy (direct if it's down)
|
|
889
|
-
|
|
890
|
-
hardcoded api.anthropic.com endpoints are intercepted
|
|
892
|
+
run [--no-mitm] [-- args...]
|
|
893
|
+
Run Claude Code through the proxy (direct if it's down).
|
|
894
|
+
Routes via an HTTPS forward proxy + local CA by default, so
|
|
895
|
+
even hardcoded api.anthropic.com endpoints are intercepted;
|
|
896
|
+
--no-mitm uses base-URL routing only
|
|
891
897
|
alias Print a shell alias so plain 'claude' routes via the proxy
|
|
892
898
|
(--install to write it to your shell rc; --uninstall to remove)
|
|
893
899
|
status Show proxy & account status (live)
|
|
@@ -909,10 +915,10 @@ Options:
|
|
|
909
915
|
--json '{"accessToken":"...","refreshToken":"...","expiresAt":1234}'
|
|
910
916
|
--log-to DIR Log full requests/responses to DIR (server, one file per request)
|
|
911
917
|
--headless Run the server without the interactive TUI (for backgrounding)
|
|
912
|
-
--mitm
|
|
918
|
+
--no-mitm (run) skip the forward proxy; route via ANTHROPIC_BASE_URL only
|
|
913
919
|
|
|
914
920
|
The server always accepts both base-URL and proxy/CONNECT clients, so instances
|
|
915
|
-
launched with and without --mitm can share one server.
|
|
921
|
+
launched with and without --no-mitm can share one server.
|
|
916
922
|
|
|
917
923
|
A running server re-syncs accounts from config on POST /teamclaude/reload
|
|
918
924
|
(local only). add/login/enable/disable/priority trigger it automatically.
|
|
@@ -1117,7 +1123,7 @@ function argValue(flag) {
|
|
|
1117
1123
|
return (i >= 0 && args[i + 1]) ? args[i + 1] : null;
|
|
1118
1124
|
}
|
|
1119
1125
|
|
|
1120
|
-
// Hostname of the configured upstream (the host MITM-intercepts under `run
|
|
1126
|
+
// Hostname of the configured upstream (the host MITM-intercepts under `run`).
|
|
1121
1127
|
function upstreamHost(config) {
|
|
1122
1128
|
try { return new URL(config.upstream || 'https://api.anthropic.com').hostname; }
|
|
1123
1129
|
catch { return 'api.anthropic.com'; }
|