From b6254432a93e80dab10a517b589d09ca111cf31b Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 7 Sep 2026 21:54:01 +0800 Subject: [PATCH] chore(release): v3.20.2 --- CHANGELOG.md | 63 +++++++++++++++++++++++++++++++++++++++ package.json | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d141a3b0..0d4cd377e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,69 @@ All notable changes to CC Switch will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.20.2] - 2026-09-07 + +Development since v3.20.1 is again led by Codex, this time as a wave of compatibility repairs rather than one redesign. Grok models finally work through xAI's native Responses API under Codex routing — tool schemas xAI rejects are collapsed, whole-float numbers Codex refuses are rewritten, the agent_message mailbox items Codex's multi-agent mode injects are translated, and Codex's role SKUs are remapped onto the configured Grok model. Around it, a family of one-cause-each fixes: the v3.20.1 switch gate no longer refuses Grok OAuth cards, takeover no longer leaves Codex on the login screen after a direct third-party switch deleted `auth.json`, GPT-6 through Codex OAuth is no longer rejected for an outdated client version (#7132), Claude Code regains parallel tool calls on Codex OAuth (#7024), the built-in image generation tool is proxied (#7036), and four catalog defects — older Codex builds refusing the catalog (#6666), MCP tools invisible on DeepSeek presets (#6653), vision variants declared text-only (#6750), Kimi/Moonshot 400 on `$ref` schemas (#6863) — are closed, with the Zhipu GLM presets moved to Zhipu's official Responses endpoint (#6957). Usage accounting stops stalling after a Codex resume (#6905) and the proxy stops breaking the prompt prefix cache on every turn (#6941). The preset roster grows by Tencent Cloud Token Plan across six apps (#7011), QwenCloud across seven (#6214), AICodeWith across eight, and sponsors 9527CODE and SoleAPI across all nine, plus Tencent and PPIO for Pi; the pricing table gains seven new models and a September repricing pass (Sonnet 5 back to $2/$10, GPT-5.6 and Gemini 3.6/3.8 Flash promotional rates, MiniMax M2 family). This release does not change the database schema. + +**Stats**: 52 commits | 71 files changed | +10,483 insertions | -573 deletions + +### Added + +- **New Provider Presets: Tencent Cloud Token Plan, QwenCloud, AICodeWith, 9527CODE, SoleAPI; Tencent and PPIO for Pi**: Tencent Cloud Token Plan (six subscription products, domestic and international, across Claude Code, Claude Desktop, Codex, OpenCode, Hermes and OpenClaw; endpoints, lineups and thinking tiers verified with real keys) (#7011); QwenCloud, DashScope's international site, as new entries separate from Bailian (three plans across seven apps) (#6214); AICodeWith across eight apps; sponsors 9527CODE and SoleAPI across all nine apps, listed in the README sponsor tables; and for Pi, eight Tencent TokenHub / Token Plan presets with explicit thinking control (#7159) plus PPIO (#6870; fixes #6868). The Pi change also drops the retired `minimax-m2.5` from the Tencent presets of every app. +- **Pricing Rows for Seven New Models**: Claude Fable 5.1 and Mythos 5.1 at $10/$50 per million with $0.25 cache read and $12.50 cache write (#7051; fixes #7050) — without a row these requests were stored at $0, because the prefix rule only looks for longer dated ids and cannot fall back to `claude-fable-5`; GLM-5.3 at $1.40/$4.40 with $0.26 cache read, matching Z.ai's list price (#6591); GLM-5.3 Flash at $0.15/$0.50 with $0.03 cache read (#7163); GPT-6 Astra at $10/$50 with $1 cache read and $12.50 cache write, its low/medium/high/xhigh suffixes falling back to the base row (#7162); Gemini 3.8 Flash at $0.75/$3.75 with $0.075 cache read and no cache-write charge (#7164); and Qwen3.8 Flash at $0.15/$0.47 flat across its 1M window with $0.016/$0.20 cache read/write. All are seed-only rows (no schema change); existing installs pick them up on next launch, and the startup cost backfill re-prices historical rows for these ids that were recorded at $0. + +### Changed + +- **September 2026 Repricing**: Sonnet 5 returns to $2/$10 — Anthropic's pricing page now states the introductory price is the standard price and the September 1 increase to $3/$15 will not occur — with a guarded repair correcting installs seeded at 3/15/0.30/3.75 while leaving user-customized rows alone (#7051). GPT-5.6 Sol, the bare `gpt-5.6` alias and its five effort-suffix rows move in lockstep from $5/$30 (cache read $0.50, write $6.25) to the promotional $4/$20 (cache read $0.40, write $5), available at least through 2026-11-21. Gemini 3.6 Flash drops from $1.50/$7.50/$0.15 to the same $0.75/$3.75/$0.075 introductory price Google lists for 3.8 Flash, through 2026-12-31. MiniMax M2, M2.1 and M2.5 all move to the official pay-as-you-go $0.30/$1.20 with $0.03 cache read and a $0.375 cache write that was previously recorded as zero. Every change ships as seed plus a repair entry guarded on the previous value, appended after the existing chain so older databases hop through the intermediate prices. + +### Fixed + +- **Grok Models Work Through xAI's Native Responses API Under Codex Routing** (#6917): A series of contributed fixes closes four independent failures on the native-Responses path to xAI. xAI rejected Codex Desktop's built-in tool schemas before sampling, so root `oneOf`/`anyOf` function parameters are collapsed on the request path (#6815), intersecting the union branches' required lists so a flattened `oneOf` does not force fields the chosen branch lacks. Grok emits whole-float JSON numbers that Codex's parser refuses as integers, so integral floats in completed `function_call` arguments are rewritten (exactly 2^64 is now refused rather than silently rewritten off by one). Codex's multi-agent mode injects `agent_message` mailbox items that xAI cannot deserialize, so every child spawn failed 422 before any tool ran — those items are rewritten into ordinary user messages with encrypted content flattened to text. And xAI 404s Codex's role SKUs such as `gpt-5.6-sol`, so unknown request models are remapped onto the provider's configured model (catalog slugs like `grok-4.5` and any `grok`-prefixed id pass through untouched), with the remap running before sanitization so a subagent landing on grok-4.5 also gets its unsupported sampling fields stripped. All of it sits behind one native-Responses gate in a dedicated module so it can be rebased or cherry-picked until upstream covers the same cases. The grok-4.5 xAI presets now declare low/medium/high/xhigh: probed on 2026-08-30, the endpoint accepts those four and rejects `max` with HTTP 400, and Codex does not clamp out-of-catalog efforts. +- **Switching to a Grok OAuth Codex Card Is No Longer Refused**: The v3.20.1 config-only switch refactor extended the keyless safety gate to every write path, which broke proxy-managed OAuth cards (xAI Grok OAuth): they are keyless by design — the local proxy injects the real token per request — yet their preset snapshot inherited the pre-0.149 template's `requires_openai_auth = true`, so the gate refused the switch as an official-login fallback. The snapshot is fixed rather than the gate exempted: the flag is forced to `false` on the active custom table for proxy-injected OAuth providers (xAI OAuth and GitHub Copilot; Codex OAuth is deliberately excluded because the official login _is_ its credential), hooked into the shared effective-provider builder so preflight, normal writes and proxy backup/takeover projections all see the same shape and Codex 0.149 resolves the provider as unauthenticated without reading `auth.json`. The preset now emits `false` at the source; stored cards self-heal on their next switch. +- **Takeover No Longer Traps Codex on the Login Screen After a Direct Third-Party Switch**: With official-login preservation off (the default), a direct switch to a third-party provider deletes `~/.codex/auth.json`; enabling proxy takeover afterwards rebuilt `config.toml` from the stored card, which still carried the pre-0.149 `requires_openai_auth = true`, so Codex ≥ 0.149 sat in the login screen even though the proxy's placeholder bearer token was in place — the same gap hit hot switches after `codex logout` mid-takeover. The takeover writer now stamps the active custom table's flag from the login state Codex itself would observe, mirroring the direct-switch plan: the auth mode is resolved exactly as Codex does (explicit `auth_mode` first, then personal access token, Bedrock API key, Bedrock access keys, `OPENAI_API_KEY`, ChatGPT) before checking the credential, so Bedrock credentials next to a stale API key are never promoted to an OpenAI login; the credentials store is decided before touching `auth.json` — keyring and auto stores are undecidable from disk and leave the card's flag alone, the ephemeral store is always signed out, and only the file store reads the file, where a missing, unreadable or corrupt file means signed out and no longer fails the takeover write. Proxy-injected OAuth cards keep their neutralized `false` regardless of what is on disk; the official passthrough and managed-official branches are untouched. +- **Duplicate Managed ChatGPT Accounts Are Rejected** (#7061; refs #7055): An ordinary managed-account login whose ChatGPT workspace _and_ stable user identity (the id_token subject) both match an existing account is refused with a localized message instead of creating a second row. The check runs under the storage lock so concurrent login completions cannot slip a duplicate through, and the refresh lock is now taken only for targeted re-auth so a rejected add leaves no lock entry behind. Distinct users in the same workspace remain supported. +- **GPT-6 Through Codex OAuth Takeover Is No Longer Rejected as "Requires a Newer Version of Codex"** (#7132; refs #7129): Requests for `gpt-6-astra` on the Claude-to-Codex OAuth route advertised Codex 0.144.1, below the model's 0.153.0 minimum client version, so ChatGPT's backend answered HTTP 400. The advertised version is now 0.153.4, and the originator/version constants are shared between generation and model discovery — the latter previously sent cc-switch's own package version and originator. +- **Parallel Tool Calls Restored for Claude Code on Codex OAuth** (#7024; fixes #5719): When the incoming Anthropic request carried no explicit value, Codex OAuth requests defaulted `parallel_tool_calls` to false, forcing Claude Code into one tool call per model turn. The default is now true (matching codex-rs), and Anthropic's `tool_choice.disable_parallel_tool_use` maps to the inverse Responses value so explicit serial execution is preserved. Carries #5722 forward. +- **Codex's Built-In Image Generation Works Under Routing** (#7036; fixes #5429, #6745; supersedes #5484): Codex's ImageGen tool calls the legacy OpenAI Images API, but the local proxy only registered Responses, Chat Completions, Compact and Alpha Search routes, so `/v1/images/generations` returned an empty 404. The generations aliases (bare, `/v1`, `/v1/v1`, `/codex/v1`) are now forwarded as a Codex standalone passthrough shared with Alpha Search, the Alpha Search full-URL rewrite is generalized to derive the sibling Images URL from full Responses/Compact/Chat URLs (an existing Images URL is kept, an opaque full URL fails closed), and the response's input/output tokens are recorded through the Codex usage parser. A follow-up adds `/images/edits`, which ImageGen switches to whenever it references existing images (explicit paths or the last N generated) and which still hit an empty local route; both routes share one suffix table so a provider configured with either as a complete URL derives the other. +- **Older Codex Builds Load the Catalog Again** (#6666; fixes #6661, #6709; supersedes #6710): Codex 0.144.5 through 0.148.0-alpha.15 declare `supports_parallel_tool_calls` as a required catalog field, while upstream removed it from its model info on 2026-08-14 — so a `models_cache.json` refreshed by a newer build lacks the field, and the ProxyChat catalog cloned from it was rejected by an older Codex on the same machine with "missing field". The field joins the required-field backfill and is filled from the bundled gpt-5.5 template (true); existing values are never overwritten, and newer builds ignore the extra key. Verified with real binaries: the old catalog is rejected by 0.147.0 and 0.148.0-alpha.15, the new one loads on both and on 0.148.0. +- **MCP Tools Visible Again on the DeepSeek Native Presets** (#6653; fixes #6647): The bundled official catalog declared `supports_search_tool = true` for deepseek-v4-pro and deepseek-v4-flash, and Codex gates deferred/namespaced MCP tools on that flag — so every MCP tool was hidden behind a `tool_search` DeepSeek's Responses API cannot serve, and none could ever be called. Both models now declare false and Codex lists MCP tools inline; hosted web search is gated by provider capabilities rather than this flag and is unaffected, and DeepSeek's server-side web search still works. +- **Vision Variants in the DeepSeek-Mirrored Catalog Are No Longer Declared Text-Only** (#6750; fixes #6725): A model slug absent from the bundled DeepSeek catalog cloned the flagship entry and inherited its text-only input modalities, so a vision variant such as `deepseek-v4-flash-vision-exp` lost image input. Unmatched slugs now resolve modalities through the same registry/fail-open logic as the non-vendor path; explicit user-set modalities still win and matched models keep the vendor's declaration verbatim. Separately, `glm-5.3` joins the confirmed text-only list (#6851) so its `[1M]` variant is recognized while `glm-5.3v` is not. +- **Kimi/Moonshot Through Codex Routing No Longer Fail 400 on Tool Schemas** (#6863; fixes #6867, also reported as #6614, #6834, #6861, #6976, #7000 and #7028; supersedes #5125, #6627): Moonshot's Chat Completions validator (`api.moonshot.cn`, `api.moonshot.ai` and the Kimi For Coding endpoint `api.kimi.com`) rejects a `$ref` that carries sibling keywords, and Codex Desktop's built-in tool schemas carry exactly that shape — so every desktop turn routed to Kimi failed. When the resolved upstream host is Moonshot/Kimi, each `$ref` with siblings is moved into `allOf` after the Responses-to-Chat conversion, with the siblings left in place; the traversal only enters schema-valued keywords and the rewrite is idempotent. Every other provider keeps byte-identical tool schemas, and the Codex-to-Anthropic path is untouched because Moonshot's Anthropic-compatible endpoint accepts the original shape. +- **Zhipu GLM Codex Presets Target Zhipu's Official Responses Endpoint** (#6957; fixes #6944): Zhipu documents three base URLs per site — Anthropic `/api/anthropic`, Chat `/api/coding/paas/v4`, Responses `/api/v1` — and warns the wrong one cannot use Coding Plan quota; Codex direct-connect speaks Responses, and the 400 `unknown variant custom` came from the Chat endpoint's strict legacy gateway. The Zhipu GLM and Zhipu GLM (en) presets switch to native Responses on `/api/v1` (shell-command edits, no freeform apply_patch) and mirror the official model list: glm-5.3 with a 1M window, low/high/max defaulting to max, plus glm-5-turbo on the CN site; glm-5.2 and the `none` level are dropped. A host fallback gives rows saved with a stale Chat format but a native Responses base URL the Responses catalog without a re-save (Chat-endpoint paths are excluded); vendor hosts are matched on DNS label boundaries so `z.ai` no longer captures `xyz.ai`; and `bigmodel.cn`, `z.ai` and the `glm` prefix join the Codex hosted web-search reject list. +- **Usage Stops Stalling After a Codex Resume** (#6905; fixes #6904): When a Codex thread is reverted, Codex mints a replacement rollout file named with two UUIDs (`rollout--_.jsonl`), and every later resume of that thread appends to it; the file's root metadata keeps the original thread id, but the importer's consistency check compared that id against the filename's trailing UUID only — so every such file was permanently deferred and usage silently stopped accumulating from the moment the user resumed that thread (reproduced live: 152 unimported token-count events, the deferral warning repeating every 60-second cycle). The check now also accepts a metadata id matching the leading UUID of dual-segment filenames; single-UUID filenames keep the strict check, and ordinary sessions that were never reverted were never affected. The stored session id for such files is now the leading (logical thread) id rather than the trailing rollout id — the id the session list is keyed by — while the trailing id remains the request-id prefix that keeps dedup keys from colliding across segments of one thread. +- **Prompt Prefix Cache No Longer Broken on Every Turn** (#6941; fixes #6789): The Anthropic-to-OpenAI conversion merged every system message to the head of the conversation, but Claude Code injects `` metadata as a mid-conversation system message on each turn — so the merge rewrote the prefix every turn and defeated the upstream's radix prefix cache. Top-level system blocks are still merged into one leading system message (byte-stable across turns), while system messages inside the message list now stay at their original position, unmerged and unreordered. The reporter measured cache-hit rates on OpenAI-format endpoints such as DeepSeek, GLM and Kimi falling from 99% to 20% before the fix. +- **Hermes "Latest Version" Reads GitHub Releases** (refs #6475, #6618, #7033; supersedes #6621): The tools panel asked PyPI, but upstream stopped publishing there after 0.19.0 (2026-07-20) and ships only through GitHub Releases — so users saw "latest 0.19.0" forever, often below their installed version, and the upgrade button never appeared. PyPI was never the channel cc-switch installs or upgrades Hermes through (the official install script and `hermes update` both use git), so the probe now queries GitHub Releases first and falls back to PyPI only when GitHub is unreachable or rate-limited. The semver is parsed from the release name (`Hermes Agent v0.21.0 (v2026.8.31)`) because the tag is calendar-versioned, calendar numbers are rejected on both paths so `2026.8.31` can never be reported as a permanent update, a PyPI fallback value is hidden when the local version already leads it, and both probes get a 15-second timeout instead of the shared client's 600 seconds, which stalled the Hermes card and the refresh/upgrade-all buttons when `api.github.com` hung. +- **Opus 5 and Sonnet 5 Appear in Claude Code's Model Menu Under Takeover** (#5882; fixes #5876): The stable role aliases takeover writes to Claude Code moved from `claude-opus-4-8`/`claude-sonnet-4-6` to `claude-opus-5`/`claude-sonnet-5`, matching the Claude Desktop default routes and preset defaults that had already moved. `opus-5` joins the adaptive-thinking classifier so the Bedrock thinking optimizer, which runs on the client alias before model mapping, keeps sending adaptive thinking instead of the removed `budget_tokens`. Routing is unaffected — the proxy maps client aliases by role keyword — and the aliases are rewritten the next time the proxy starts. +- **"Fetch Models" Works for the PPIO, JieKou and Novita Claude Presets** (#6870 and follow-up): All three serve the Anthropic-compatible API under one path but expose the OpenAI-compatible model list under `/openai/v1`, and every candidate derived from the base URL returned 404, so model discovery could never succeed. Each preset now pins an explicit models URL, which the form looks up by the card's base URL at fetch time — so existing cards still on the preset's default address get it without any change; a test that had locked the broken behavior in for JieKou was dropped. +- **Ghost "journal" Sessions Gone From the Claude Session List** (fixes #6042): Claude Code's workflow feature writes `journal.jsonl` files inside the session directory; the scanner only excluded `agent-*` files, so each journal parsed as an empty session titled "journal". +- **Update-Check Failures Show the Real Reason** (#6482): The updater plugin rejects with a plain string, so the `instanceof Error` check never matched and the actual failure (network error, rate limit, malformed manifest) was replaced by the generic fallback — and stopped in an unread context state. The recovered message now reaches the failure toast. +- **Proxy Address Masking No Longer Panics on Multi-Byte Characters** (#6908): The fallback used when the proxy URL fails to parse sliced the raw string at byte 20 and panicked when a multi-byte UTF-8 character straddled that offset — a CJK string pasted into the global proxy address was enough. The cut now snaps to the nearest character boundary. +- **Pi Duplicate-Key Error and Collapse Label Show Text Instead of Raw Keys** (#6768): The Pi backend's duplicate-key error mapped to a translation key that existed in none of the four locales, and the thinking-map toggle's accessible label was missing the same way; both are added to zh/en/ja/zh-TW and locked by the locale coverage test. +- **Screen Readers Get Names for Icon-Only Controls** (#7049; fixes #7048): Icon-only back buttons, the header local-routing switch, the project switcher popover, the Claude JSON editors and the existing-Skills import checkboxes now carry programmatic names, reusing existing strings where possible plus two short localized labels. +- **Usage Trend Token Axis Uses Compact Locale Formatting** (#7016): Tick labels were a fixed `k`, so a large day read as `1500k`; they now use the locale's compact notation (`1.5M`) with the axis width adjusted to fit. +- **Pricing Source Dropdown Fits Its Localized Labels** (#6980): The pricing model source selector in the usage cost settings left about 70 px for labels that need about 107 px in English and Japanese; it is widened and aligned to the adjacent input's height. + +### Internal + +- **Tests No Longer Write to the Real Claude Desktop Config on Windows** (#6078; fixes #6077): Claude Desktop config paths resolve from `LOCALAPPDATA`, which the test home override did not redirect, so the profile round-trip test wrote its `https://desktop.test` fixture into the developer's real config. `LOCALAPPDATA` now points at the isolated test home alongside `HOME` and `USERPROFILE`. +- **README Directory Trees Show the Real Locales Path** (#6100): All four READMEs listed `locales/` as a direct child of `src/`; it lives at `src/i18n/locales/`. Also fixes a "CLaude" typo in the Chinese README. +- **Housekeeping Around the xAI Series**: The namespace SSE restore helpers that lost their last caller when the xAI response path moved to the sanitize stream are deleted rather than allowed as dead code, the xAI request gate is thinned to a single forwarder call so upstream rebases conflict in one place, and the grok-4.5 frontend test expectations are aligned with the four-tier presets (the mismatch had left main's frontend checks red and dragged every PR's checks down with the same two failures). + +### Upgrade notes + +- **No database migration**: the schema version stays at 18. +- **Preset changes apply only to newly created providers** — a stored card keeps the settings it was created with. In this release that covers the Zhipu GLM presets (an existing Zhipu Codex card still points at the Chat endpoint and still fails on direct connect: re-import the preset to pick up `/api/v1`), the Tencent Pi presets' thinking control (re-import to get a working "off" and the corrected Kimi levels), the grok-4.5 xhigh tier, and the `minimax-m2.5` removal from the Tencent presets. The pinned models URLs for PPIO, JieKou and Novita are the exception: the form resolves them from the card's base URL, so existing cards on the default address need no change. +- **Codex catalog fixes reach Codex on the next provider switch**, when the catalog file is regenerated: DeepSeek MCP visibility (#6653), the `supports_parallel_tool_calls` backfill (#6666), vision modalities (#6750) and the glm-5.3 text-only entry (#6851). Switch away and back once on an affected card. +- **Codex OAuth via takeover now advertises Codex 0.153.4** to ChatGPT's backend; nothing to configure. If you use the Codex CLI directly rather than through cc-switch, GPT-6 needs Codex ≥ 0.153.0 on your side. +- **Adding a ChatGPT account that is already in the Auth Center** (same user, same workspace) is now refused; use the existing row's re-login instead. Different users in one workspace still coexist. +- **Grok OAuth cards self-heal on their next switch** (the `requires_openai_auth` flag is backfilled to `false`); no re-add needed. +- **Under takeover, `requires_openai_auth` on the active third-party table is now overridden on every takeover write** to match the login state Codex would observe, decided by its credentials store: with the file store (the default) the flag follows whether `auth.json` holds an official login; with the ephemeral store Codex always starts signed out, so the flag is written `false`; with the keyring or auto store the login state cannot be read from disk and the card's stored value is left alone. +- **Usage that a Codex resume had stalled is imported on the next scan** and dated when it happened, so dashboard totals for those days can jump. Session ids for reverted threads are recorded correctly from now on; rows already written under the rollout id are not rewritten. +- **Pricing**: the Sonnet 5 repair only corrects rows still at the seeded 3/15/0.30/3.75; a customized Sonnet 5 row is left alone, and historical Sonnet 5 costs are _not_ re-priced — costs are frozen at log time and the backfill only touches rows recorded at $0 (which is why Fable 5.1, GLM-5.3, GLM-5.3 Flash, GPT-6 Astra and Gemini 3.8 Flash history _is_ re-priced). The MiniMax M2 family gains a cache-write price that was previously zero, so those costs rise going forward. The promotional GPT-5.6 rate (through at least 2026-11-21) and the introductory Gemini 3.6/3.8 Flash rates (through 2026-12-31, then $1.50/$7.50/$0.15) have end dates the pricing table cannot express; a later release will re-seed them. +- **Image generation through Codex routing is counted by tokens but has no built-in price yet**: the image models have no pricing row, so their cost shows as $0 until one is added. +- **Hermes version probing degrades to "unknown"** rather than a misleading "latest 0.19.0" when GitHub is unreachable and the PyPI fallback is older than your installed build. +- **Mid-conversation system messages are now forwarded in place** to OpenAI-format upstreams instead of being merged to the front; this is what restores prefix-cache hits, and it matches what Claude Code sends natively. Two consequences: the first request after upgrading changes the prefix bytes, so the cache goes cold once and then recovers; and strict backends that require every system message at the head (the Nvidia/Qwen-style endpoints behind #1881, which answer `System message must be at the beginning`) will fail again on such turns — the removed merge had been introduced for them, and prefix stability and strict-backend compatibility cannot both hold in one global behavior. Report your upstream if it is one of those. + ## [3.20.1] - 2026-08-28 This release is dominated by two Codex storylines. The first is an urgent compatibility break: Codex CLI 0.149 stopped letting custom providers inherit ambient credentials from `auth.json`, turning third-party switches made in the old default mode into 401 errors (#6744). Rather than patching around it, cc-switch now switches Codex providers config-only — the key travels in the provider's own `config.toml` table, `auth.json` returns to being purely the official ChatGPT login file — and a whole family of legacy config shapes 0.149 refuses to load is repaired on every switch, with a new preflight refusing unloadable shapes instead of reporting a "successful" switch Codex cannot start from. The second is account safety: two members of the same ChatGPT Team workspace no longer overwrite each other in the Auth Center (#6780, fixes #2245) — existing managed accounts need one re-login (see upgrade notes). Around them: provider edits now always reach the live config file (#6779), the Codex edit dialog no longer shows another provider's key (#6534), restores no longer wipe hand-written prompt files (#6810), the usage dashboard gains an auto/manual session-scan toggle plus an incremental byte-cursor scanner (a 12 MB active session file: 6.04 s → 9.3 ms) behind this release's schema migration (v17 → v18), and Otty joins the macOS terminal picker (#6620). diff --git a/package.json b/package.json index cf1b0a247..104db1dde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cc-switch", - "version": "3.20.1", + "version": "3.20.2", "description": "All-in-One Assistant for Claude Code, Codex & Gemini CLI", "type": "module", "scripts": { diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index d8d992df3..9e2919251 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -758,7 +758,7 @@ dependencies = [ [[package]] name = "cc-switch" -version = "3.20.1" +version = "3.20.2" dependencies = [ "anyhow", "arboard", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index f567bfa46..e7652bf8f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cc-switch" -version = "3.20.1" +version = "3.20.2" description = "All-in-One Assistant for Claude Code, Codex & Gemini CLI" authors = ["Jason Young"] license = "MIT" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 50aa7a79d..5a8d818c8 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "CC Switch", - "version": "3.20.1", + "version": "3.20.2", "identifier": "com.ccswitch.desktop", "build": { "frontendDist": "../dist",