# CC Switch v3.19.1

> The through-line of this release is **tying off the loose ends of the last one**: three Chinese Codex gateways have been confirmed to support the Responses API natively, so **local routing takeover is no longer required** — the DeepSeek and Volcengine Ark Coding Plan presets move from routed to direct, and the newly added Tencent Hunyuan TokenHub is direct from the start. Four failures you could hit in daily use are fixed: **Claude Desktop usage has been counted twice since v3.18.0** (the historical numbers correct themselves after upgrading, but there is a 30-day window — see "Upgrade Notes"), switching back to the official Codex provider left you stuck on a 401 with no login screen, upgrading Grok Build from Settings failed with nothing but `os error 2`, and enabling takeover on Grok Build returned a straight 404. On top of that, eight models that had been billed at $0 gain built-in pricing, and 39 interface strings have their language problem fixed. This release has **no database migration**, and it is the first release in this project's history that deletes more than it adds.

**[中文版 →](v3.19.1-zh.md) | [日本語版 →](v3.19.1-ja.md)**

---

## Highlights: What You Can Do Now

- **Connect DeepSeek, Volcengine Ark Coding Plan, and Tencent Hunyuan directly inside Codex**: all three vendors' official Codex documentation now confirms their endpoints serve the Responses API natively. The existing DeepSeek and Volcengine Ark Coding Plan presets move from Chat format to native format, so the "needs routing" badge on the provider card and the prompt on switching both disappear and requests no longer pass through the local proxy's protocol conversion; Tencent Hunyuan TokenHub is new in this release and is native from the start. **Note that DeepSeek V4 Pro cannot use the direct connection yet** — the vendor has not opened its Codex integration for that model. Use V4 Flash for direct connections (it is the preset default); see [Upgrade Notes](#deepseek-v4-pro-cannot-use-the-direct-connection-yet).
- **Let DeepSeek use the model catalog DeepSeek itself publishes**: the new "official vendor catalog mirroring" mechanism serves a vendor's published `models.json` verbatim to that vendor's own endpoint, so the freeform `apply_patch` registration and its companion GPT-5 harness stay together instead of being flattened into the neutral template. The match is on host only, never on model name — the same model resold by an aggregator may not implement the same capabilities.
- **Get correct Claude Desktop usage numbers**: since v3.18.0, Claude Desktop traffic through the local gateway has been recorded twice in the dashboard — once from the proxy and once from session-log import — roughly doubling its tokens, cost, and request counts. After this fix, every day whose detail rows are still present returns to the correct number automatically, **with no rebuild required**.
- **Sign in normally after switching back to the official Codex provider**: previously, switching from a third-party provider back to the built-in official Codex entry left the third-party key in `~/.codex/auth.json`. Codex would use it against the official endpoint and get a reliable 401 — and because the file existed, it never fell back to its own login screen, leaving no way out from inside the app.
- **Upgrade Grok Build from the Settings page**: since 0.2.112, `grok update` performs its distribution by calling npm internally, but an app launched from the GUI cannot see node, so the upgrade only ever reported `Error: No such file or directory (os error 2)`.
- **Enable takeover on Grok Build without hitting a 404**: a Grok Build provider whose API format had been changed by hand to OpenAI Chat or Anthropic would, once takeover was enabled, send requests to a route the proxy does not register — a straight 404, with no failover and no usage record. On top of that, every Grok Build request used to be treated as a new session, which disabled both cache-key injection and per-session grouping.
- **See the real cost of eight models that had been billed at $0**: `gpt-5.3-codex-spark`, `gemini-3.5-flash-lite`, `kimi-k2.7-code-highspeed`, `glm-5-turbo`, `glm-5v-turbo`, `qwen3.6-flash`, plus the undated `claude-opus-4-6` / `claude-sonnet-4-6`.
- **Read the About page's tool manager in Traditional Chinese**: 30 strings had only been added for Simplified Chinese, English, and Japanese and were missing for Traditional Chinese; because i18next silently falls back to English, that panel had been half-English since v3.16.0. A further 9 strings showed Simplified Chinese **in every language**.
- **Move back and forth between the official subscription and DeepSeek instead of choosing one**: `auth.json` and `config.toml` are single-slot files — Codex itself cannot hold a second set of credentials. A vendor's one-click script rewrites that configuration to be its own, whereas CC Switch snapshots and restores it per provider — which is the most practical difference between the two approaches; see [the comparison below](#importing-through-cc-switch-vs-running-the-official-script).

---

## Usage Guides

The changes in this release center on how Codex connects and on how usage is counted. The following docs are worth reading alongside it:

- **[Local Routing](../user-manual/en/4-proxy/4.2-routing.md)**: which providers need takeover enabled, and what takeover does. After this release, DeepSeek, Volcengine Ark Coding Plan, and Tencent Hunyuan no longer need it.
- **[Usage Statistics](../user-manual/en/4-proxy/4.4-usage.md)**: the usage dashboard's data sources and how the statistics are counted — useful for understanding how the Claude Desktop double count happened and why some historical days cannot be corrected.
- **[Using Chat-Format APIs Like DeepSeek in Codex](../guides/codex-deepseek-routing-guide-en.md)**: this guide explains how local routing converts Responses into Chat Completions, and **has been updated for this release**. It now opens with a check for which case you are in: a DeepSeek provider created from the preset connects directly and needs no routing, while one saved before the upgrade — and `deepseek-v4-pro` — still does. The mechanism applies in full to Kimi, Zhipu GLM, SiliconFlow, and other providers that remain Chat-shaped.

---

> [!WARNING]
>
> ## Only Official Channels (Please Read)
>
> CC Switch is a **fully free and open-source** desktop app, and we **do not charge users any fees**. Please only obtain the software through the official channels listed below:
>
> | Channel            | Only Official                                                                  |
> | ------------------ | ------------------------------------------------------------------------------ |
> | Website            | **[ccswitch.io](https://ccswitch.io)**                                         |
> | Source             | **[github.com/farion1231/cc-switch](https://github.com/farion1231/cc-switch)** |
> | Downloads          | **[GitHub Releases](https://github.com/farion1231/cc-switch/releases)**        |
> | Author             | **[@farion1231](https://github.com/farion1231)**                               |
> | Report an Imposter | **[GitHub Issues](https://github.com/farion1231/cc-switch/issues)**            |
>
> **Any "CC Switch" website or client that asks you for payment, top-ups, or login credentials is fake.** If you have been tricked into paying, stop the transaction immediately and file a report through GitHub Issues.

---

## Overview

CC Switch v3.19.1 is a maintenance release along three lines. The first is Chinese Codex gateways moving to native Responses as a group: DeepSeek connects directly to `api.deepseek.com` and brings a reusable mechanism with it — mirroring the model catalog a vendor publishes itself, so the freeform `apply_patch` registration and its companion GPT-5 harness stay self-consistent rather than being folded into the neutral template; Volcengine's Ark Coding Plan endpoint `/api/coding/v3` follows now that the official documentation confirms it; and Tencent Hunyuan's TokenHub joins as a new preset. None of the three needs local routing takeover any more.

The second is four failures visible in the field: Claude Desktop usage has been recorded twice since v3.18.0 ([#5938](https://github.com/farion1231/cc-switch/issues/5938)); switching back to the built-in official Codex provider left a third-party `auth.json` behind, producing a 401 with no login screen; `grok update` reported nothing but `os error 2` when run from the GUI; and Grok Build's proxy takeover returned 404 on non-Responses backends while every request was treated as a new session ([#5677](https://github.com/farion1231/cc-switch/pull/5677)). The third is weight loss: 3,166 lines of code with no remaining caller and 4 unused npm dependencies are deleted — this is the first release in the project's history that deletes more than it adds. Beyond that, deep-link import confirmations mask more and truncate less, eight models that had been billed at $0 gain pricing, and four built-in prices are realigned with vendor list prices. This release has **no database schema migration** (the version stays at v16), so upgrading is light.

**Release date**: 2026-07-31

**Change size**: 12 commits | 71 files changed | +2,324 / -3,680 lines

---

## Added

### Official Vendor Model Catalog Mirroring (DeepSeek First)

Codex reads model capabilities from a catalog file, and CC Switch previously generated that catalog from a neutral template for every provider — which is right for an aggregator, but strips the capabilities a vendor's own integration depends on. Now, for any vendor whose official catalog is bundled with the app, that vendor's own file is mirrored directly.

DeepSeek is the first: the bundled file carries the `deepseek-v4-flash` and `deepseek-v4-pro` entries, preserving `apply_patch_tool_type: "freeform"`, `web_search_tool_type: "text"`, `supports_search_tool: true`, the low / high / max reasoning tiers, and the 17,644-character GPT-5 harness in `base_instructions` and `model_messages` — **that harness has to travel together with the freeform tool registration**, because the harness itself instructs the model to use `apply_patch`; splitting either half leaves the pair inconsistent.

The gate is deliberately narrow: the provider must resolve to the native Responses profile **and** its `base_url` must be on `deepseek.com`. **Matching is by host, not by model brand** — the same model resold by an aggregator may not implement the same capabilities, and granting by brand would hand capabilities to a service that never implemented them. Entries a provider pins in its own catalog still win; an unrecognized model ID clones the flagship entry but keeps its own name. Catalogs generated for every other profile are byte-identical to before.

### Tencent Hunyuan (TokenHub) Codex Preset

The Codex preset picker gains "Tencent Hunyuan" under the Opensource Official category, between Bailian and StepFun. Selecting it writes `https://tokenhub.tencentmaas.com/v1`, `wire_api = "responses"`, and the `disable_response_storage = true` that TokenHub requires; it declares the two models `hy3` and `hy3-preview` with a **256K** context window (rather than accepting Codex's 128K default), and marks them text-only — Codex will no longer send `view_image` payloads to a model that cannot read them.

Because it is a native Responses provider, Codex connects to the gateway directly with no local routing; the generated catalog uses the neutral native template, which pins `shell_type = "shell_command"` and drops the freeform `apply_patch` registration that native gateways reject. The address manager and latency test have two candidates from the start: the primary domain and the official `.cn` backup. The regionally separate international site is deliberately excluded, because API keys do not carry across sites.

Note that the **API key must be a TokenHub key with Hy3 access enabled**; Coding Plan and Token Plan subscription keys do not work against this endpoint.

### Built-In Pricing for Eight Models That Had Been Billed at $0

`gpt-5.3-codex-spark`, `gemini-3.5-flash-lite`, `kimi-k2.7-code-highspeed` (2x the `kimi-k2.7-code` baseline, following Kimi's Turbo convention), `glm-5-turbo`, `glm-5v-turbo`, and `qwen3.6-flash` had no row at all in the built-in pricing table, and the prefix fallback could not reach them either, so every request against them was recorded at zero cost.

Two more rows — the undated `claude-opus-4-6` and `claude-sonnet-4-6` — close a subtler gap: model ID resolution only **strips** a date suffix, it never **adds** one, so a log carrying an undated ID matched nothing. All eight rows are seeded insert-if-absent, so any price you edited is untouched.

### Grok Build Joins the Failover Tabs and Environment-Conflict Detection

The failover section in Settings gains a fourth Grok Build tab alongside Claude Code, Codex, and Gemini. The environment-conflict banner shown at startup also begins detecting `XAI_API_KEY` and `GROK_DEFAULT_MODEL` — two variables that silently override whichever provider you selected in the app. Detection distinguishes exact names from prefixes, so CC Switch's own `GROK_BIN_DIR` and `GROK_HOME` are not falsely reported.

---

## Changed

### DeepSeek and Volcengine Ark Coding Plan Connect to Codex Directly, With No Local Routing

Both presets were previously marked as OpenAI Chat format, which made both of them "needs takeover": the provider card carried the "needs routing" badge, switching without the proxy running raised a prompt, and every request travelled Codex → local proxy → Responses-to-Chat → upstream.

Both vendors' official Codex integration docs now confirm their endpoints serve the Responses API — DeepSeek's `api.deepseek.com` and Volcengine's `/api/coding/v3` — so both presets are declared native Responses, the badge and the prompt disappear, and Codex connects to the gateway directly. Neither vendor's generated `config.toml` changes (it was already `wire_api = "responses"`); what changes is the catalog generation profile, and for DeepSeek the context window, which is realigned from 1,000,000 to the vendor's own 1,048,576.

BytePlus's international site deliberately stays on Chat routing until its documentation is verified separately. The Volcengine preset also carries a billing note worth knowing: the pay-as-you-go `/api/v3` endpoint **must never** be added to this preset's backup addresses — it bills separately and does not draw down plan quota.

### Catalog Display Name and Context Window Are Now Explicit-Only

Both fields previously carried local defaults — the model ID and a 128,000-token window — applied before the vendor's value had a chance to participate, so a mirrored catalog's 1M window would have been overwritten with 128K. They are now optional, with the fallbacks moved down to entry construction, so "left blank" genuinely means "keep the value the vendor declared". Providers that set the two fields explicitly, and every non-mirrored profile, generate exactly the catalog they did before.

---

## Importing Through CC Switch vs. Running the Official Script

DeepSeek publishes a one-click Codex setup script. It works, it takes backups, and it comes with a restore menu. **If this machine is only ever going to use DeepSeek, running the official script is perfectly fine.** What CC Switch addresses is a different situation: you want to move back and forth between several providers.

### Switching Providers Swaps Login State and Configuration as a Set, With No Manual Backup

`~/.codex/auth.json` and `~/.codex/config.toml` are both **single-slot files** — Codex itself has no multi-credential storage, and one configuration can only describe one provider. When you switch away from a provider, CC Switch snapshots the contents of both files into that provider's record; when you switch back, it writes them back whole. So "ChatGPT subscription → DeepSeek → back to the subscription" normally does not require another `codex login`, and moving between third-party providers requires no manual step at all. Doing the same thing by hand means copying both files before and after every switch; miss it once, and the overwritten OAuth credentials can only be recovered by signing in again.

The official script makes a different trade-off: it rewrites `config.toml` into a DeepSeek-specific configuration — pinning `preferred_auth_method = "apikey"` and `forced_login_method = "api"` at the top level to fix authentication to API key, and **deleting any existing `[profiles.*]` from `config.toml`** (Codex's own built-in mechanism for switching between providers). Your ChatGPT credentials themselves are not deleted — `auth.json` is untouched — but they cannot be used under that configuration; returning to the subscription means running the script's restore menu for a whole-file rollback, and that rollback also discards any hand edits you made to `config.toml` after installation. The script itself can only switch between flash and pro; there is no "move to a third provider" option.

### After Switching Providers, Your Old Sessions Are Still in `codex resume`

Codex sorts its resume list into drawers by the `model_provider` recorded in each session. Every third-party Codex provider CC Switch creates — DeepSeek, Kimi, an aggregator, it makes no difference — writes the same identifier `custom`, so however you switch among them, `codex resume` keeps showing the full history. On its first launch, CC Switch also performs a one-time migration that folds known per-vendor buckets (including the `deepseek` one the official script writes) into this shared bucket, backing the original files up to `~/.cc-switch/backups/` first.

**There is a clear boundary here**: that migration runs once, on CC Switch's first launch. **If you install CC Switch first and only later run the official script**, those `deepseek`-tagged sessions will not be folded in — they stay in their own drawer. Separately, a provider identifier you wrote by hand that is not on the known list is deliberately left alone.

### Official-Subscription Sessions Are Already Interleaved With Third-Party Ones in CC Switch

CC Switch's **Sessions panel scans the session directory directly and does not read `model_provider`**, so Codex sessions produced during official-subscription use have always been in the same list as third-party ones — searchable, resumable, deletable — **with no toggle required**.

If you additionally want **Codex's own `codex resume` list** to merge official and third-party sessions, that is a separate matter: Settings → General → Codex App Enhancements → **"Unified Codex session history"**, off by default. Enabling it affects new sessions only; moving existing official sessions across as well requires ticking "Also migrate existing official session history" in the enable dialog (also unchecked by default). Both are pre-existing features, not new in this release; for the edge cases see the [Unified Codex Session History guide](../guides/codex-unified-session-history-guide-en.md).

> **Two shared prerequisites, stated up front so they do not confuse you later:**
>
> **First, everything above applies to the Codex directory CC Switch points at.** That is `~/.codex` by default and can be changed in Settings. **CC Switch does not read the `CODEX_HOME` environment variable** — if you use that variable to point Codex somewhere else, CC Switch cannot see those sessions, and provider switches will be written into a directory the CLI is not using. To change the directory, use CC Switch's own config-directory setting.
>
> **Second, appearing in the same list does not mean a session can be resumed.** Codex's reasoning content (`encrypted_content`) can only be decrypted by the backend that produced it, so continuing an old session on a different provider may fail — that is upstream's design, not something CC Switch can work around.

---

## Fixed

### Claude Desktop Usage Was Counted Twice

Claude Desktop traffic through the local gateway landed twice in the usage dashboard — once as a proxy row and once as a session-import row — so its tokens, cost, and request counts were roughly doubled.

This is a regression introduced in v3.18.0: the proxy-side dedup ID carried a scope prefix for every app except `claude`, written as `session:{app}:{provider}:{message_id}`, which put `claude-desktop` in its own namespace; meanwhile the session importer kept writing the same Claude message in the bare `session:{message_id}` form with `app_type = 'claude'`. Three dedup defenses failed at once: the primary-key convergence that lets a proxy row absorb an existing session row, the write-side fingerprint probe, and the read-side filter — the latter two both comparing app type with strict equality.

The two apps now share the bare namespace again, and the two comparisons are widened by a one-way rule: a `claude` session row can be absorbed by a `claude-desktop` proxy row, **but not the reverse**. Because the read-side filter is exactly the one daily rollups aggregate through, duplicate rows already in the database stop being counted, **with no row rewritten or deleted** — this self-healing has a retention limit, see "Upgrade Notes". For Codex, Gemini, and OpenCode the widened comparison degenerates to the previous exact match, and quota checks still use strict matching. ([#5938](https://github.com/farion1231/cc-switch/issues/5938), [#5951](https://github.com/farion1231/cc-switch/pull/5951))

### Switching Back to the Official Codex Provider Left You Stuck on a 401 With No Login Screen

With the Codex API-key preservation toggle off (the default), switching to a third-party provider writes that vendor's key into `~/.codex/auth.json`. Switching afterwards to the built-in official provider — whose stored credentials are empty — took the config-only branch, so `config.toml` was replaced while the third-party `OPENAI_API_KEY` stayed on disk as it was. Codex then used that foreign key against the official endpoint and got a reliable 401; and because `auth.json` existed, it never fell back to its own login screen, leaving no way out from inside the app.

Now, after a successful switch to an official Codex provider, if `auth.json` contains only an `OPENAI_API_KEY` with no first-class credential beside it, the file is deleted — an OAuth token, a personal access token, an agent identity, or a Bedrock key all mark the file as genuine and leave it fully intact, while metadata such as `auth_mode`, `last_refresh`, or an account ID can no longer "shield" a stale key.

**Deleting the file rather than writing `{}`** is deliberate: an empty object is read by Codex as ChatGPT mode without tokens and errors at startup, whereas a missing file is equivalent to being signed out and goes straight to the login flow. The cleanup runs only after the previous provider has been successfully backfilled into the database, so the deleted key is not lost — it is stored in that provider's record and comes back when you select it again. The same change also relaxed live-config reads: the post-cleanup state (no `auth.json`, a `config.toml` present) is no longer reported as "Codex is not installed".

### Upgrading Grok Build From the Settings Page Reported Nothing but `os error 2`

Upgrading Grok Build under Settings → About failed with `Error: No such file or directory (os error 2)` and no further information.

The root cause is an asymmetry between the probe path and the execution path: probing goes through a login shell, which reads the user's rc files and therefore sees nvm, Homebrew, and Volta, while lifecycle scripts ran under a non-login shell inheriting the very narrow PATH a GUI-launched app starts with. That would normally not matter, because anchored commands invoke their target by absolute path — but grok 0.2.112 moved self-update onto npm distribution, so `grok update` internally invokes `npm view` and `npm i -g`, and npm in turn resolves node through its shebang. The inner call returned ENOENT, and grok surfaced it verbatim as that `os error 2`.

Lifecycle commands on macOS and Linux now merge the login shell's real PATH ahead of the inherited one, read by executing `/usr/bin/env` rather than echoing the variable — because fish stores PATH as a list, and echoing would yield space-separated segments. For a natively installed Grok, the upgrade chain additionally falls back to the official xAI installer, **deliberately not `npm i -g`**: npm shares both of the primary path's failure modes (no node, a mirror missing the package) and would fail alongside it; the official installer is the only route that does not depend on node, lands in the same place, and rewrites the CLI's own `installer` setting back to `internal`, incidentally healing users an earlier npm fallback had moved onto npm distribution.

### Grok Build Returned 404 With Takeover Enabled, and Every Request Looked Like a New Session

Enabling takeover on a Grok Build provider whose API format had been changed to OpenAI Chat or Anthropic produced an immediate 404, with no failover and no usage record — takeover rewrote the address and the key but left the backend field alone, so the CLI sent requests to a route the proxy does not register. Takeover now pins the backend to Responses as well; the per-provider downgrade to Chat Completions still happens in the forwarding layer, and the forced value is restored along with the whole live-config backup when the proxy stops.

The other problem was that the proxy's session detection recognized only Codex and OpenAI clients, so every Grok Build turn generated a new session ID marked "not client-provided", which suppressed both cache-key injection and per-session grouping in the dashboard. Grok's own headers are now read — the conversation ID first, then the session ID, ignoring the one that changes per request — under a separate prefix, so the records cannot collide with Codex's. ([#5677](https://github.com/farion1231/cc-switch/pull/5677))

### Nine Interface Strings Showed Simplified Chinese in Every Language

Nine strings displayed Simplified Chinese regardless of the interface language, in English and Japanese interfaces alike. Every call site used the "inline default value" form with a Chinese literal as the default, but the corresponding key was in **none** of the four locale files — and i18next walks the whole language chain before it considers an inline default, so the English fallback never got a chance and the Chinese literal won in every language.

The affected strings cover the Grok Build provider form's required-field validation, the failover hover tooltip shown when an app is not yet under takeover, the warning raised when stopping Claude Desktop routing while another app holds takeover along with its reason line, the provider-identifier read failure, the empty Codex common-config error, the routing service's stopped and stop-failed toasts, and the "unpriced" label the usage tables put on requests that carry tokens but compute to zero cost. All nine keys now exist in Simplified Chinese, English, Japanese, and Traditional Chinese. ([#5960](https://github.com/farion1231/cc-switch/pull/5960))

### The Traditional Chinese About Page's Tool Manager Fell Back to English

With the interface language set to Traditional Chinese, the tool management section of the About page displayed English — the version rows, the install and update buttons, the result toasts, the install-conflict diagnosis, and the entire upgrade confirmation dialog. That panel was built out across three separate changes, each adding strings for Simplified Chinese, English, and Japanese only; and because i18next's strategy is to fall back to English rather than error, the 30 missing keys were completely invisible in testing. **This gap had shipped in every release from v3.16.0 through v3.19.0.**

All 30 strings are now translated and the install hint is aligned with the other languages; a new locale test requires every tool-management string to exist in all four languages with matching interpolation variables, so this kind of drift will fail the test suite instead of shipping. ([#5943](https://github.com/farion1231/cc-switch/pull/5943))

### Built-In Pricing Had Drifted From Vendor List Prices

Cost is frozen against the built-in pricing table at the moment a request is logged, so a stale seeded price silently miscounts every subsequent request. Four rows are corrected in this release: `deepseek-chat` and `deepseek-reasoner` are now legacy aliases of V4 Flash at $0.14 input / $0.28 output per million tokens with $0.0028 cache read (previously $0.27/$1.10 and $0.55/$2.19); `minimax-m3` is halved to $0.30/$1.20 per the official standard tier; `gpt-5.6-luna` drops 80% to $0.20/$1.20 and `gpt-5.6-terra` drops 20% to $2/$12 following OpenAI's 2026-07-30 price cut, with `gpt-5.6-sol` deliberately unchanged and the family's cache-write ratio preserved.

The repair only rewrites a row when all four of its price columns **still equal the previous built-in values exactly**, so a price you edited yourself — or one written by models.dev sync — is never touched.

---

## Security Hardening

### Deep-Link Import Confirmations: Stricter Masking, Less Truncation

This continues the `ccswitch://` confirmation hardening from v3.19.0. Config previews are now built by a single shared module that recursively masks secrets inside nested TOML tables and JSON objects, fixing two defects that pointed in opposite directions at once: a Grok Build import **rendered no config preview at all**, while a Codex import **printed embedded `api_key` values in the clear**.

The 300-character truncation on the config preview is gone; the full content now renders in a scrollable box — closing the last place the confirmation could hide part of what it was about to write. The masking itself is stricter everywhere it is used, **including the MCP import confirmation**: sensitive-name matching adds `AUTHORIZATION`, `COOKIE`, and `CREDENTIAL`, plus exact matches for `AUTH` and `BEARER`; the plaintext prefix shown after masking shrinks from 8 characters to 4; and values of 8 characters or fewer are now replaced entirely rather than displayed as they are.

Finally, the frontend's Base64 decoder no longer trims leading and trailing whitespace — which may well be a `+` that URL decoding turned into a space. This is the same class of frontend/backend decoder divergence fixed in v3.19.0: what the confirmation displays is one thing, what the importer writes is another.

---

## Internal

### 3,166 Lines With No Caller, 14 Modules, and 4 Dependencies Removed

A pass over code with no remaining caller. On the backend it deletes the provider icon inference table, a placeholder health checker, a never-wired SSE implementation (with its own streaming and non-streaming handlers), two unused proxy session types, four unreferenced usage parsers, and a dead cost-calculation entry point — **the live billing path, its auto-detecting parsers, and session ID extraction are all untouched**. The 22 `#[allow(dead_code)]` suppressions that had kept the compiler quiet about all of it go too.

On the frontend, 14 modules with no importer are deleted, including a prompt form modal and a repository manager both superseded by panel rewrites, a duplicate proxy config hook, a circuit-breaker panel that never had an importer in the project's history, and three schema files; their strings are removed from all four languages in step. The Tauri commands behind these modules are deliberately kept. Four unused npm dependencies are also dropped. Two scripts that regenerated the hand-curated icon index are removed, and the index file's header now states that automatic regeneration is intentionally unsupported.

A companion change consolidates proxy state and takeover state onto a single query layer — there had been a second parallel set of hooks over the same commands with zero callers, whose query keys never had an observer, so every invalidation aimed at them was a no-op. The query key strings are unchanged character for character, and the surviving hook keeps its existing polling behavior. ([#5916](https://github.com/farion1231/cc-switch/pull/5916), [#5928](https://github.com/farion1231/cc-switch/pull/5928))

---

## Upgrade Notes

### No Database Migration in This Release

v3.19.1 contains no schema migration (the version stays at v16), so no pre-upgrade backup is triggered and the upgrade is ready to use immediately.

### The Claude Desktop Double-Count Self-Heal Has a 30-Day Window (Please Read)

The fix suppresses duplicate rows at query time rather than rewriting or deleting data, so **every day whose detail rows are still present returns to the correct total on the next launch**, with no rebuild needed.

But detail rows older than 30 days are aggregated into daily rollups and pruned, and a rollup is computed once, under whatever rules were in effect at aggregation time. **Any day already aggregated by a build without this fix keeps its inflated number permanently.** The regression entered with v3.18.0 (2026-07-21), so the sooner you upgrade, the more of the historical range is recovered.

### The New Pricing Affects Historical Data in Two Different Ways

The eight newly priced models are **recalculated retroactively**: at startup, requests recorded with zero cost have their cost filled in, so the dashboard numbers for those models will **go up**. Detail rows that were already aggregated and pruned cannot be recalculated and stay at zero.

The four repriced models work in the opposite direction: the backfill only touches zero-cost rows, so requests already recorded keep the old price and only new requests bill at the new one — historical and new spend for the same model will not match. Both paths protect your own pricing: the repair only changes rows still at the original built-in value, while manual edits, models.dev sync values, and deletion tombstones in `~/.cc-switch/model-pricing.json` are replayed after seeding and repair and always win.

### Preset Changes Only Affect Newly Created Providers

An already saved DeepSeek or Volcengine Ark Coding Plan provider keeps the API format it stored, still needs local routing, and still uses the old catalog. To use the direct connection, re-create the provider from the preset, or change the API format to native Responses in the provider form's advanced section.

That said, **a provider already on native Responses whose address is on `deepseek.com` picks up the mirrored official catalog on its next switch**, with no re-save required — because the check reads the live configuration.

### DeepSeek V4 Pro Cannot Use the Direct Connection Yet

The preset still lists `deepseek-v4-pro`, and the vendor's own published catalog carries it too, but **DeepSeek has not opened its Codex integration for pro**; their stated timing is early August 2026. Until then, selecting pro in direct-connection mode fails upstream — use `deepseek-v4-flash`, which is also the preset's default model.

If you need pro right now, change that provider's API format back to "OpenAI Chat" and enable local routing takeover. This is exactly the path DeepSeek used before v3.19.1: the local proxy converts the Responses requests Codex sends into Chat Completions, and pro is unaffected on that route.

### Two Prerequisites for the Official DeepSeek Catalog

The mirrored catalog declares a minimum Codex client version of 0.144.0, and **CC Switch does not verify this itself** — the freeform `apply_patch` registration it carries requires that version or newer. Separately, the generated catalog file grows to roughly 75 KB (for the two mirrored models), because each entry carries the full harness text.

### After Going Direct, Usage Attribution Moves From the Provider Name to `Codex (Session)`

DeepSeek, Volcengine Ark Coding Plan, and Tencent Hunyuan no longer need takeover, so their traffic can bypass the local proxy entirely and the proxy's per-request records no longer see them.

**The usage itself is neither lost nor indistinguishable** — Codex's session-log import records it as before, only that path does not carry provider identity: all Codex usage that did not go through the local proxy is grouped under an entry named `Codex (Session)`, official-subscription consumption included. In other words, once DeepSeek moves from routed to direct, its usage moves out from under the name "DeepSeek" and into `Codex (Session)`.

**To tell them apart, look at the model**: every usage record carries its own model ID, and the usage panel's per-model statistics list them row by row — `deepseek-v4-flash`, `hy3`, `ark-code-latest`, and the official subscription's GPT models each get their own row, with separate cost and token figures. Only when the dimension you actually need is **per provider** (comparing the same model across several aggregators, for instance) do you need to keep using local routing takeover — that route records the real provider name.

### Two Prerequisites for the Stale Codex Credential Cleanup

The cleanup runs only when the incoming provider carries the explicit official category **and** the outgoing provider was backfilled successfully. An entry created by hand without the official category, or a switch whose backfill failed, still leaves the residue on disk.

### Enabling Takeover on Grok Build Rewrites the Backend Field

Enabling takeover on a Grok Build provider now rewrites the backend field in the live configuration to Responses. The provider record stored in the database is unaffected, and the live file is restored in full from its backup when the proxy stops.

### PATH Changes for Tool Installs and Upgrades (macOS / Linux Only)

Every tool install and upgrade triggered from Settings → About now merges the login shell's PATH ahead of the inherited one, so a program a lifecycle script resolves by name may resolve differently than before; each action also starts one extra shell to read that PATH, which executes your interactive startup files. **Windows is unaffected.**

Users on grok 0.2.112 or later may see two installation records — the native one, plus the global npm package `grok update` created itself; upstream keeps them in sync and they report the same version.

### Environment-Conflict Detection Now Matches Differently

Detection for Claude Code, Codex, and Gemini has been tightened from "contains" to "prefix", so variables that merely contain an app name — `MY_ANTHROPIC_API_KEY`, `OLD_GEMINI_API_KEY` — are **no longer reported as conflicts**. Detection for Grok Build was added at the same time.

### Deep-Link Import Confirmations Show Less of Each Secret

The plaintext prefix shown after masking shrinks from 8 characters to 4, and values of 8 characters or fewer are masked entirely. This affects the MCP import confirmation as well.

---

## Risk Notice

### Carried-Over Notices

**xAI Grok OAuth sign-in**: reuses the public OAuth client identity of the official Grok CLI; using it could lead to account restriction or suspension — see the [v3.18.0 release notes](v3.18.0-en.md#risk-notice) for details.

**Codex OAuth reverse proxy**: using a ChatGPT subscription's Codex OAuth through a reverse proxy may violate OpenAI's terms of service. See the [v3.13.0 release notes](v3.13.0-en.md#️-risk-notice) for details.

**SuperGrok quota queries**: the quota display on provider cards depends on a non-public billing endpoint at grok.com and may stop working once xAI changes the interface — see the [v3.19.0 release notes](v3.19.0-en.md#risk-notice) for details.

**Third-party provider routing**: when the CC Switch local proxy converts and forwards Codex, Claude Desktop, or Grok Build requests to a third-party provider, each provider has different constraints on billing, compliance, and data retention. Please read the target provider's terms of service before use.

By enabling these features, users accept the associated risks. CC Switch is not responsible for any account restriction, warning, or service suspension resulting from their use.

---

## Thanks

Most of the fixes in this release came from outside contributors — five of the six PRs are not mine.

### Code Contributions

- [#5677](https://github.com/farion1231/cc-switch/pull/5677): finishing off Grok Build's proxy takeover and deep-link integration — the backend field, session identity, the failover tab, and environment-variable detection, plus a fix for the credential leak in config previews along the way. Thanks to @YUZHEthefool. This is the broadest single piece of work in the release.
- [#5951](https://github.com/farion1231/cc-switch/pull/5951): the Claude Desktop double-count fix. Thanks to @Komikawayi. Pinpointing which change in v3.18.0 made all three dedup defenses fail at once was the most patient piece of investigation in this release.
- [#5916](https://github.com/farion1231/cc-switch/pull/5916), [#5928](https://github.com/farion1231/cc-switch/pull/5928): removing 3,166 lines of code with no callers and the duplicate proxy query layer. Thanks to @SaladDay.
- [#5943](https://github.com/farion1231/cc-switch/pull/5943): completing the Traditional Chinese tool-management strings and adding a test that prevents locale drift. Thanks to @yovinchen.
- [#5960](https://github.com/farion1231/cc-switch/pull/5960): completing the 9 strings that showed Simplified Chinese in every language. Thanks to @mhy1227.

### Issue Reports

Thanks to @Alaric-L for reporting in [#5938](https://github.com/farion1231/cc-switch/issues/5938) that every Claude Desktop request produced an extra log row sourced from `session_log`, causing tokens to be counted twice — that report pinpointed the data source, and the most important usage fix in this release was located directly from it.

---

## Download & Install

Visit [Releases](https://github.com/farion1231/cc-switch/releases/latest) and download the build for your system, or get it from the official site [ccswitch.io](https://ccswitch.io) (downloads are distributed through Cloudflare edge nodes and do not depend on GitHub being reachable).

### System Requirements

| System  | Minimum Version      | Architecture                        |
| ------- | -------------------- | ----------------------------------- |
| Windows | Windows 10 and later | x64 / ARM64                         |
| macOS   | macOS 12 (Monterey)+ | Intel (x64) / Apple Silicon (arm64) |
| Linux   | See table below      | x64 / ARM64                         |

### Windows

| File                                     | Description                                      |
| ---------------------------------------- | ------------------------------------------------ |
| `CC-Switch-v3.19.1-Windows.msi`          | **Recommended** - MSI installer with auto-update |
| `CC-Switch-v3.19.1-Windows-Portable.zip` | Portable build, unzip and run                    |

Windows ARM64 devices should pick the artifact whose file name carries the `arm64` tag.

### macOS

| File                             | Description                                           |
| -------------------------------- | ----------------------------------------------------- |
| `CC-Switch-v3.19.1-macOS.dmg`    | **Recommended** - DMG installer, drag to Applications |
| `CC-Switch-v3.19.1-macOS.zip`    | Unzip and drag to Applications, Universal Binary      |
| `CC-Switch-v3.19.1-macOS.tar.gz` | For Homebrew install and auto-update                  |

Homebrew install:

```bash
brew install --cask cc-switch
```

Upgrade:

```bash
brew upgrade --cask cc-switch
```

### Linux

Linux assets are available for both **x86_64** and **ARM64** (`aarch64`). Choose the file whose architecture tag matches your machine's `uname -m` output:

- `CC-Switch-v3.19.1-Linux-x86_64.AppImage` / `.deb` / `.rpm`
- `CC-Switch-v3.19.1-Linux-arm64.AppImage` / `.deb` / `.rpm`

| Distribution                            | Recommended Format | Install Command                                                        |
| --------------------------------------- | ------------------ | ---------------------------------------------------------------------- |
| Ubuntu / Debian / Linux Mint / Pop!\_OS | `.deb`             | `sudo dpkg -i CC-Switch-*.deb` or `sudo apt install ./CC-Switch-*.deb` |
| Fedora / RHEL / CentOS / Rocky Linux    | `.rpm`             | `sudo rpm -i CC-Switch-*.rpm` or `sudo dnf install ./CC-Switch-*.rpm`  |
| openSUSE                                | `.rpm`             | `sudo zypper install ./CC-Switch-*.rpm`                                |
| Arch Linux / Manjaro                    | `.AppImage`        | Make executable and run directly, or use AUR                           |
| Other distributions / unsure            | `.AppImage`        | `chmod +x CC-Switch-*.AppImage && ./CC-Switch-*.AppImage`              |
