Metadata-Version: 2.3
Name: cc-switch
Version: 0.9.10
Summary: Generate ~/.claude/settings.json from saved provider/model configs
Project-URL: Homepage, https://github.com/juzcn/slife
Project-URL: Repository, https://github.com/juzcn/slife
Author-email: juzcn <zhangjun@cueb.edu.cn>
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Terminals
Requires-Python: >=3.13
Requires-Dist: credstore>=0.10.4
Description-Content-Type: text/markdown

# cc-switch

Generate `~/.claude/settings.json` from saved provider/model configs —
a small CLI that mirrors the [credstore](https://github.com/juzcn/slife/blob/main/credstore/README.md) pattern.

Non-secret provider *shape* lives in `~/.claude/cc-switch.json`.  API
keys are **never** stored there — the config keeps the key's *name*,
and the value is read from credstore at activate time and injected into
the system environment as `ANTHROPIC_AUTH_TOKEN`.  The generated
`settings.json` contains no credential line.

## Install

cc-switch is a standalone PyPI package — installed independently of
slife (installing slife does **not** bring cc-switch, and vice versa).
Both depend on [credstore](https://github.com/juzcn/slife/blob/main/credstore/README.md), which is pulled in
automatically.

```bash
uv tool install cc-switch
# or, in this repo:
uv sync
```

## Commands

### `cc-switch set <provider-name>`

Create or edit a provider.  Prompts for:

- **Base URL** (required)
- **API key name** — the credstore key holding the secret (required)
- **Supported models** (optional; comma, space, or semicolon separated)

If the provider already exists this *edits* it; otherwise it *adds* it.
When editing, a blank answer keeps the current value.  The models prompt
**toggles** against the provider's current list: a model you type that is
already listed is removed, one that isn't is added (symmetric
difference).  A blank answer leaves the list unchanged, and typing the
same list again undoes the change.

```bash
cc-switch set deepseek
# Base URL [..]: https://api.deepseek.com/anthropic
# API key name (credstore key): DEEPSEEK_API_KEY
# Supported models (comma separated; toggles against the current list): deepseek-chat,deepseek-reasoner
```

No secret value is ever asked for or written — store it first with:

```bash
credstore set DEEPSEEK_API_KEY
```

### `cc-switch activate <provider-name/model-name>`

Writes `~/.claude/settings.json` with stock Claude Code defaults, and
injects the API key from credstore into the system environment as
`ANTHROPIC_AUTH_TOKEN` (mirroring `credstore inject` — registry on
Windows, shell profile on Unix), so a freshly launched Claude Code
session inherits it.  The settings file contains **no** credential.

`settings.json` is written first, then the secret is resolved from
credstore.  If the key is missing — or credstore itself is not
installed — `activate` fails loudly with the appropriate hint, leaving
the generated settings file on disk but **not** injecting a token.

On success, the activated `provider/model` is recorded in the top-level
`active` field of `~/.claude/cc-switch.json`, so the list view can show
which model is currently active.

```bash
cc-switch activate deepseek/deepseek-chat
```

If the model is omitted and the provider has exactly one model, it is
used; if several, you are prompted to pick one.

### `cc-switch activate <provider-name/model-name> --custom`

Like `activate`, but lets you override each model slot first —
`ANTHROPIC_DEFAULT_HAIKU_MODEL`, `ANTHROPIC_DEFAULT_SONNET_MODEL`,
`ANTHROPIC_DEFAULT_OPUS_MODEL`, `ANTHROPIC_CLAUDE_CODE_SUBAGENT_MODEL`,
and `ANTHROPIC_CLAUDE_CODE_EFFORT_LEVEL` — one at a time.  Enter a value
to override, or Enter to keep the default.  The main model slot
(`ANTHROPIC_MODEL`) is chosen on the command line, not here.  Overrides
are one-shot: they never touch the stored provider config.

### `cc-switch`

With no command, lists every configured provider/model pair, one per
line.  The currently active model is marked `(active)`:

```
deepseek/deepseek-chat
deepseek/deepseek-reasoner
scnet/scnet-1m  (active)
```

### `cc-switch list`

Shows provider metadata (base URL, API key name, models) — one block
per provider.

### `cc-switch remove <provider-name>`

Deletes a provider config.  Does not touch credstore or settings.json.

## Files

| Path | Purpose |
|------|---------|
| `~/.claude/cc-switch.json` | Provider/model shapes + the `active` spec (no secrets) |
| `~/.claude/settings.json` | Generated by `activate` |
| credstore (`DEEPSEEK_API_KEY`, …) | The actual API key values |

`CC_SWITCH_FILE` overrides the config path; the settings path can be
overridden for tests.

## Security notes

- The config file holds only metadata — the API key is referenced by name.
- `activate` reads the secret from credstore and injects it into the
  system environment as `ANTHROPIC_AUTH_TOKEN` (registry on Windows /
  shell profile on Unix), mirroring `credstore inject`; it is never
  written to settings.json.
- A provider's `extra_env` (settable via the Python API) may not contain
  `ANTHROPIC_MODEL`, `ANTHROPIC_BASE_URL`, or `ANTHROPIC_AUTH_TOKEN` —
  cc-switch owns those slots, and a secret must never reach the plaintext
  config.
- On a TTY, `activate` prints an activation hint without echoing the
  secret; when stdout is piped it emits the shell export line for `eval`.
- Restart your shell (or start a new terminal) after activating for the
  env change to take effect in the current session.
- Secrets are immutable Python `str` — cc-switch follows credstore's
  practice of `del`-ing the reference immediately after use.
