Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,53 @@ eval $(teamclaude env)
claude
```

### Transparent shim

`teamclaude run` works for one-off invocations, but if you want plain `claude` to route through the proxy automatically — without prefixing every call — install the shim:

```bash
teamclaude shim install
```

This drops a small bash wrapper at `$XDG_DATA_HOME/teamclaude-shim/claude`, alongside `env` (sh / bash / zsh) and `env.fish` (fish) loaders. Each detected shell rc gets a single one-line directive sourcing the loader — same pattern rustup uses with `~/.cargo/env`. From then on, every `claude` invocation:

1. Probes the proxy port locally.
2. **Up** → applies `teamclaude env` and execs the real `claude`.
3. **Down** → execs the real `claude` directly.

The shim lives in its own directory, separate from where Claude Code's auto-updater writes its binary. So `claude` updates can come and go without disturbing the shim — same trick `rbenv`, `asdf`, and `mise` use to survive language-version updates.

```bash
teamclaude shim status # Show install state and which rc files are wired up
teamclaude shim uninstall # Revert (removes shim files + cleans rc edits)
```

Shells covered:

- **bash** — `~/.bashrc` and `~/.bash_profile` (handles macOS Terminal's login-shell precedence)
- **zsh** — `~/.zshrc`
- **POSIX sh** — `~/.profile` (login-shell baseline; helps display managers, etc.)
- **fish** — `~/.config/fish/conf.d/teamclaude-shim.fish` (auto-loaded; no rc edit)

The sourced loaders are idempotent at source time (they check whether the shim dir is already on `PATH`) so reload-after-reload is safe.

Flags:

- `--no-rc` — skip rc edits; print the source lines for manual install.
- `--shim-dir PATH` — override the install directory (default `$XDG_DATA_HOME/teamclaude-shim`).

Shim runtime env vars:

- `CLAUDE_REAL` — force a specific real-claude binary path (skips PATH walk).
- `TEAMCLAUDE_CONFIG` — override the teamclaude config path used to read the proxy port.

### Other commands

```bash
teamclaude accounts # List accounts with subscription tier and token status
teamclaude accounts -v # Also show token expiry times
teamclaude status # Show live proxy status (requires running server)
teamclaude shim status # Show shim installation status
teamclaude remove <name> # Remove an account
teamclaude api <path> # Call an API endpoint with account credentials
teamclaude help # Show all commands
Expand Down
36 changes: 36 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AccountManager } from './account-manager.js';
import { createProxyServer } from './server.js';
import { importCredentials, loginOAuth, fetchProfile, refreshAccessToken, isTokenExpiringSoon } from './oauth.js';
import { TUI } from './tui.js';
import * as shim from './shim.js';

const args = process.argv.slice(2);
const command = args[0];
Expand Down Expand Up @@ -46,6 +47,10 @@ switch (command) {
await apiCommand();
process.exit(0);
break;
case 'shim':
await shimCommand();
process.exit(0);
break;
case 'help':
case '--help':
case '-h':
Expand Down Expand Up @@ -556,6 +561,34 @@ async function apiCommand() {
}
}

// ── shim ────────────────────────────────────────────────────

async function shimCommand() {
const sub = args[1];
const shimDir = argValue('--shim-dir') || undefined;

switch (sub) {
case 'install': {
const noRc = args.includes('--no-rc');
shim.install({ shimDir, noRc });
break;
}
case 'uninstall': {
shim.uninstall({ shimDir });
break;
}
case 'status':
case undefined: {
shim.status({ shimDir });
break;
}
default:
console.error(`Unknown shim action: ${sub}`);
console.error('Usage: teamclaude shim [install|uninstall|status] [--no-rc] [--shim-dir PATH]');
process.exit(1);
}
}

// ── remove ──────────────────────────────────────────────────

async function removeCommand() {
Expand Down Expand Up @@ -596,6 +629,9 @@ Commands:
accounts List configured accounts
remove <name> Remove an account
api <path> Call an API endpoint with account credentials
shim <action> Install a transparent claude shim that auto-routes
through the proxy when it's running
(install | uninstall | status)
help Show this help

Options:
Expand Down
Loading