@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.
Files changed (3) hide show
  1. package/README.md +16 -6
  2. package/package.json +1 -1
  3. 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
- - **Optional MITM proxy mode** — `teamclaude run --mitm` 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
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 (optional, off by default)
264
+ ### MITM proxy mode (default)
259
265
 
260
- The normal 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.
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
- Run claude with the `--mitm` flag:
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karpeleslab/teamclaude",
3
- "version": "1.0.9",
3
+ "version": "1.1.0",
4
4
  "description": "Multi-account Claude proxy with automatic quota-based rotation",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
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 before
448
- // an optional `--` separator; everything after `--` goes verbatim to claude.
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 ? rest.slice(sep + 1) : rest.filter(a => a !== '--mitm');
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 (err) {
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
- --mitm routes via an HTTPS forward proxy + local CA so even
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 (run) route claude via the HTTPS forward proxy + local CA
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 --mitm`).
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'; }