The shadow-turn matcher used a three-branch `||` chain (id / full name /
normalized name). When two tools share a suffix (e.g. `server_a:search`
and `server_b:search`), the normalized-name clause could short-circuit
on an earlier turn whose id is actually wrong for the incoming tool_use,
mis-routing replay state (functionCall id / thoughtSignature) for later
tool_result resolution.
Split matching into two layers: when the incoming message carries any
tool_use ids, run id-based lookup first and return on the earliest hit.
Only fall back to full-name / normalized-name matching when the incoming
ids are absent or none of them resolve.
Add two regressions:
- shadow_replay_prefers_exact_id_match_over_normalized_name_collision
Two shadow turns with colliding normalized names and two assistant
messages whose ids cross the positional order; asserts each message
replays the id-correct shadow turn (including thoughtSignature).
- shadow_replay_falls_back_to_name_when_ids_absent
Shadow turn with no id and incoming tool_use with an empty id;
asserts the name fallback still populates the replayed part.
Three related findings on `streaming_gemini.rs` for Gemini's cumulative
`streamGenerateContent` stream, all centered on `merge_tool_call_snapshots`:
1. (P1) Match upgraded tool-call IDs by position.
When Gemini delivers a `functionCall` without an id on chunk 1
(cc-switch synthesizes `gemini_synth_*`) and then upgrades it to a
real id on chunk 2, the `Some(incoming_id)` branch only matched by
id and missed the existing synthesized snapshot. A second entry
would be pushed, yielding duplicate `tool_use` content blocks at
stream end — one with the synthesized id, one with the real id —
which could trigger duplicate tool execution and break tool_result
correlation. Add a positional fallback: when no id match exists but
the same-position slot holds a synthesized id, merge into it.
`or(preserved_id)` already lets the real id win the merge.
2. (P2) Preserve prior thoughtSignature when merging snapshots.
`tool_call_snapshots[index] = tool_call` overwrote the slot
entirely, dropping any `thoughtSignature` captured on an earlier
chunk if the current cumulative snapshot omitted it. Since
`build_shadow_assistant_parts` writes `thoughtSignature` into the
shadow turn from `tool_call.thought_signature`, a dropped signature
would cause later replay requests to Gemini to be rejected with
invalid-signature errors. Preserve the existing signature when the
incoming chunk does not carry one.
3. (P2) Document the part-order streaming trade-off.
All `tool_use` content blocks are emitted after the final text
`content_block_stop`, so interleaved [text, functionCall, text,
functionCall] parts arrive at the Anthropic client as [text(concat),
tool_use, tool_use] — different from the non-streaming transformer,
which preserves part order. This is intentional given the cumulative
snapshot model and the consumers we target (claude-code-like clients
don't depend on strict interleaving for tool execution correctness).
Add a block comment at the flush site describing the trade-off and
what a strict-order fix would entail, so this isn't rediscovered as
a bug later.
Regression tests:
- upgraded_real_id_merges_into_existing_synthesized_snapshot
- thought_signature_preserved_when_later_chunk_omits_it
Test count: 868 -> 870. clippy 1.95 clean. fmt clean.
CI upgraded to Rust 1.95 and flagged ten pre-existing warnings that
older toolchains did not enforce. None relate to the Gemini proxy
integration PR itself but they block CI on the feature branch, so
clean them up here as a separate commit for easy review:
collapsible_match:
- proxy/providers/gemini_schema.rs: `"items" if value.is_object()`
match guard instead of nested if.
- proxy/providers/transform_responses.rs: fold
`map_responses_stop_reason`'s `"completed"` / `"incomplete"` arms
into match guards, relying on the existing `_ => "end_turn"` fall-
through for non-matching guard conditions (semantics preserved).
- services/session_usage_codex.rs: fold
`"session_meta" if state.session_id.is_none()` guard, relying on
the existing `_ => {}` fall-through.
unnecessary_sort_by:
- services/provider/endpoints.rs: `sort_by_key(|ep| Reverse(ep.added_at))`.
- services/skill.rs (backup list): same Reverse idiom on `created_at`.
- services/skill.rs (skill listings x2): `sort_by_key(|s| s.name.to_lowercase())`.
useless_conversion:
- services/skill.rs: drop the explicit `.into_iter()` on `zip`'s argument.
while_let_loop:
- services/webdav_auto_sync.rs: `while let Some(wait_for) = ...`
instead of `loop { let Some(...) = ... else { break }; ... }`.
All changes are mechanical and preserve behavior. `cargo test --lib`
remains green (868 passed).
Adds two regression tests that lock in the intentional asymmetry
between full-URL and non-full-URL modes:
- Full-URL mode: opaque base path (e.g. `https://relay.example/custom/v1beta`)
is preserved verbatim. Already covered by
`preserves_opaque_full_url_with_bare_v1beta_suffix`.
- Non-full-URL mode: base path MUST strip `/v1`, `/v1beta`, etc. so the
standard `/v1beta/models/{model}:method` endpoint can be appended
without producing a doubled `/v1beta/v1beta/models/...` path.
The non-full-URL contract is "base URL + cc-switch appends the
canonical Gemini endpoint". A user who needs a relay's custom
namespace (e.g. `/v1/models/...`) must use full-URL mode and paste
the complete method path. This commit adds regression coverage so a
future attempt to mirror full-URL's host-whitelist gating into
`normalize_gemini_base_path` will fail the test suite immediately.
`build_gemini_native_url` unconditionally stripped `/v1`, `/v1beta`,
`/models`, and `/openai` suffixes from the base path regardless of
host. This worked for Google's own endpoints but silently rewrote
third-party relay URLs like `https://relay.example/custom/v1` to
`.../custom/v1beta/models/...`, breaking any relay that mounts its
Gemini-compatible namespace under a versioned prefix.
The result was also asymmetric with the previously-fixed full-URL
branch: toggling the "full URL" switch changed the outbound URL for
the same base_url, which is exactly the kind of invisible behavior
that makes debugging proxy deployments painful.
Align `normalize_gemini_base_path` with
`should_normalize_gemini_full_url`'s layered model:
- Unconditional: `/models/...:method` structured paths and deep
OpenAI-compat endpoints (`/openai/chat/completions`,
`/openai/responses` and their versioned variants) — these are
unambiguous Gemini-specific grammar on any host.
- Google-host gated: generic `/v1`, `/v1beta`, `/models`, `/openai`
suffixes only get stripped on `generativelanguage.googleapis.com`,
`aiplatform.googleapis.com`, or `*-aiplatform.googleapis.com`.
Other hosts preserve the prefix verbatim so relays keep their
intended routing.
Adds seven regression tests for the non-full-URL flow: opaque relay
preservation (v1 / v1beta / models / openai suffix variants), Google
host normalization (counter-case), and boundary cases (structured
method path and deep OpenAI-compat endpoint stripped regardless of
host).
Test count: 864 -> 873.
Leading whitespace on a copied oauth_creds.json (e.g. trailing newline
when the user copies the file content as-is) would slip past the
`starts_with("ya29.") || starts_with('{')` prefix check in
`ClaudeAdapter::provider_type`, causing the provider to be misclassified
as raw-API-key Gemini and fall back to `x-goog-api-key` with the raw
JSON as the key — which upstream rejects with 401.
The frontend's `handleApiKeyChange` already trims on keystrokes but
deep-link imports, the JSON editor, and live-config backfill all bypass
that path. Trim at every backend extraction point so the coverage is
uniform:
- `ClaudeAdapter::extract_key` (5 env / fallback branches) gets
`.map(str::trim)` before `.filter(|s| !s.is_empty())` so that
whitespace-only values are also treated as missing.
- `GeminiAdapter::extract_key_raw` gets the same chain (including
the `.filter` it was missing before).
- `GeminiAdapter::parse_oauth_credentials` gets a defensive
`let key = key.trim();` at the entry as a belt-and-suspenders guard.
Adds two regression tests covering JSON and bare `ya29.` keys with
leading newline/space.
Two related P2 corrections to the Gemini Native URL surface, both
folding into the existing Google-host-whitelist architecture.
## P2a — `/v1beta` suffix should not unconditionally trigger rewrite
`should_normalize_gemini_full_url` placed `/v1beta` and `/v1beta/models`
in the unconditional layer on the reasoning that `/v1beta` is
Google-specific. In practice an opaque relay fronting a non-Gemini
service at `https://relay.example/custom/v1beta` would still be
silently rewritten to `/v1beta/models/{model}:generateContent`,
breaking the deployment.
Move `/v1beta`, `/v1beta/models`, and `/v1beta/openai` into the
Google-host gated layer alongside `/v1`, `/models`, and friends. The
unconditional layer now only accepts paths whose grammar is
intrinsically Gemini — `/models/...:generateContent` method calls and
the deep OpenAI-compat endpoints like `/openai/chat/completions` and
`/openai/responses`. Pasted AI-Studio URLs such as
`https://generativelanguage.googleapis.com/v1beta` still normalize
because the host matches the whitelist.
## P2b — `model: "models/gemini-2.5-pro"` produced doubled path prefix
Gemini SDKs (and the official `list_models` response) commonly surface
model ids in resource-name form `models/gemini-2.5-pro`. Raw
interpolation into `format!("/v1beta/models/{model}:...")` produced
`/v1beta/models/models/gemini-2.5-pro:streamGenerateContent` which
upstream rejects — yielding false-negative health checks for otherwise
valid provider configs.
Introduce `normalize_gemini_model_id(&str) -> &str` in `gemini_url`
as the single source of truth: strips an optional leading `/` then an
optional `models/` prefix, leaving bare ids untouched. Apply in the
three call sites that build a Gemini method URL:
- `services/stream_check.rs::resolve_claude_stream_url` (unified path)
- `services/stream_check.rs::check_gemini_stream` (Gemini-only path)
- `proxy/forwarder.rs::rewrite_claude_transform_endpoint` (production)
Tests (9 new):
- `gemini_url`: 3 regressions for opaque vs Google-host `/v1beta*`
handling + 5 unit tests pinning `normalize_gemini_model_id` behavior
(strip prefix, leave bare id, preserve nested slashes past the one
stripped prefix, tolerate leading slash, pass through empty input).
- `stream_check`: one end-to-end regression confirming
`models/gemini-2.5-pro` collapses to the expected single-prefix URL.
- `forwarder`: one end-to-end regression on the production rewrite
path.
All 864 lib tests pass; cargo fmt + clippy -D warnings clean.
Addresses Codex P2 feedback on #1918.
`streaming_gemini::anthropic_usage_from_gemini` and
`transform_gemini::build_anthropic_usage` were byte-for-byte identical
(32 lines each) — both converting Gemini `usageMetadata` into the
Anthropic `usage` shape including `cache_read_input_tokens` mapping.
Promote the non-streaming version to `pub(crate)` and reuse it from the
streaming SSE converter. Removes ~30 lines of duplication and guarantees
the two paths cannot drift apart.
No behavioral change; all 854 lib tests pass; cargo fmt + clippy -D
warnings clean.
When Gemini returns a `functionCall` without an id (common in 2.x
parallel calls), `gemini_to_anthropic_with_shadow_and_hints` previously
generated TWO independent synthesized UUIDs:
1. Line 186-197 — synthesized id `A` used for the Anthropic-visible
`content[tool_use].id` returned to the client.
2. Line 850-881 — `extract_tool_call_meta` independently synthesized
id `B ≠ A`, which populated `shadow_turn.tool_calls[i].id`.
`shadow_content` (line 225-228, cloned from `rectified_parts`) retained
the original missing/empty id. Result: the client sees id `A`, the
shadow store holds id `B`.
On the next turn, `convert_messages_to_contents` builds
`tool_name_by_id` from `build_tool_name_map_from_shadow_turns`, which
uses `tool_calls[i].id` — so the map contains `B → name` but not
`A → name`. When the client sends back `tool_result(tool_use_id=A)`,
resolution fails with:
Unable to resolve Gemini functionResponse.name for tool_use_id `A`
This affects both truncated histories (client sends only the
tool_result) and full histories (shadow-replay branch at line 342-354
skips `convert_message_content_to_parts`, so the assistant tool_use
block never registers id `A` itself).
Fix: make `rectified_parts` the single source of truth. After
`rectify_tool_call_parts`, run a pre-pass that writes
`synthesize_tool_call_id()` back into any `functionCall` that lacks a
non-empty id. All three readers — the content builder (186-197), the
shadow_content clone (225-228), and `extract_tool_call_meta` — then
observe the same id. `shadow_parts()` already strips synthesized ids on
replay (line 616-628), so the internal identifier never leaks to
Gemini upstream.
This mirrors the streaming path, which already has single-source-of-
truth semantics via `tool_call_snapshots` in `streaming_gemini.rs` —
no change needed there.
Tests (5 new in `transform_gemini::tests`):
- `non_stream_shadow_id_matches_client_visible_id`: asserts
`response.content[0].id == shadow.tool_calls[0].id ==
shadow.assistant_content.parts[0].functionCall.id`.
- `non_stream_missing_id_scenario_a_truncated_history_resolves`: turn 2
sends only `[tool_result(id=A)]`; resolution must succeed.
- `non_stream_missing_id_scenario_b_full_history_replay_resolves`: turn 2
sends `[assistant(tool_use=A), tool_result(A)]`; shadow-replay branch
strips the synth id from outgoing `functionCall` while still
resolving the subsequent `tool_result`.
- `non_stream_preserves_original_gemini_id_when_present`: regression —
genuine Gemini ids flow through unchanged.
- `non_stream_synthesized_id_not_leaked_to_gemini_via_shadow_replay`:
defensive — shadow-replay path must strip synth ids from both
`functionCall.id` and `functionResponse.id`.
All 854 lib tests pass; cargo fmt + clippy -D warnings clean.
Addresses Codex follow-up P1 on #1918.
`should_normalize_gemini_full_url` previously treated any full URL whose
path ends with `/v1`, `/v1/models`, `/models`, `/v1/openai`, or `/openai`
as a structured Gemini endpoint and rewrote it to
`/v1beta/models/{model}:generateContent`. These are ubiquitous REST
conventions — opaque relays such as `https://relay.example/custom/v1`
legitimately use them for fixed endpoints — so the rewrite silently
routed traffic to the wrong upstream path.
Split the predicate into two layers:
- **Unconditional**: `matches_structured_gemini_models_path` (i.e. a
`/models/...:generateContent` method call anywhere in the path), the
Google-specific `/v1beta*` family, and the deep OpenAI-compat paths
(`/v1beta/openai/chat/completions`, `/openai/chat/completions`, and
their `responses` siblings). These remain host-agnostic because the
path grammar itself is Gemini-specific.
- **Google-host gated**: `/v1`, `/v1/models`, `/models`, `/v1/openai`,
`/openai`. Only normalized when the host is one of
`generativelanguage.googleapis.com`, `aiplatform.googleapis.com`, or a
real `*-aiplatform.googleapis.com` Vertex regional endpoint. The match
is exact/suffix (not `contains`), so lookalike hosts like
`aiplatform.example.com` are correctly treated as opaque relays.
Tests (8 new in `gemini_url::tests`):
- Four opaque-relay cases: `/custom/v1`, `/custom/models`,
`/custom/v1/models`, `/custom/openai` — all preserved as-is.
- Three Google-host counter-cases: `/v1`, `/models`, and
`us-central1-aiplatform.googleapis.com/v1` still normalize.
- One lookalike safety case: `aiplatform.example.com/v1` is NOT
treated as Google.
All 849 lib tests pass; cargo fmt + clippy -D warnings clean.
Addresses Codex review P2 on #1918.
Follow-up to the earlier P1 fix: some Gemini relays serialize an absent
functionCall id as `"id": ""` instead of omitting the field. The
non-streaming `extract_tool_call_meta` already filters these via
`.filter(|s| !s.is_empty())`, but the streaming counterpart
`extract_tool_calls` passed the empty string straight through
`function_call.get("id").and_then(|v| v.as_str())` into
`GeminiToolCallMeta::new`, producing a `Some("")` id.
Downstream, `merge_tool_call_snapshots` would then match two parallel
no-id calls against each other on their shared empty-string id,
collapsing them into a single snapshot (silent data loss for the first
call) and emitting an Anthropic `tool_use.id: ""` that breaks tool_result
correlation on the Claude Code client.
Fix:
- `extract_tool_calls`: apply the same `filter(|s| !s.is_empty())` guard
used in the non-streaming path so empty strings become `None` before
reaching the shadow meta.
- `merge_tool_call_snapshots`: defensively collapse any incoming
`Some("")` to `None` up front — keeps the "missing vs present" invariant
local to the merge step for future callers that might build
`GeminiToolCallMeta` by hand.
Tests (2 new, both in streaming_gemini):
- `parallel_empty_string_id_calls_are_treated_as_missing_and_preserved`
covers two parallel calls with explicit `"id": ""` — asserts both
surface, no empty tool_use id leaks, and each gets a unique
`gemini_synth_` id.
- `single_empty_string_id_tool_call_gets_synthesized_id` covers the
non-parallel degraded-relay case.
All 841 lib tests pass; cargo fmt + clippy -D warnings clean.
Addresses Codex follow-up P1 on #1918.
P2a — Preserve opaque relay URLs that contain `/v1/models/` prefixes.
`should_normalize_gemini_full_url` previously flagged any full URL whose
path merely contained `/v1beta/models/` or `/v1/models/` as a structured
Gemini endpoint, forcing rewrite to `.../v1beta/models/{model}:method`.
This silently dropped legitimate relay route segments (e.g.
`https://relay.example/v1/models/invoke` → `.../v1beta/models/...:generateContent`,
losing `/invoke`) and sent traffic to the wrong upstream path.
Replace the bare `contains(...)` checks with
`matches_structured_gemini_models_path`, which requires the
`/models/` segment to be followed by a canonical Gemini method call
(`*:generateContent` or `*:streamGenerateContent`). The
`matches_bare_gemini_models_path` helper is generalized (and renamed) to
handle both `/v1beta/models/` and `/v1/models/` alongside the original
bare `/models/` shape.
P2b — Reject empty Gemini OAuth access_tokens before they reach the
bearer header.
`GeminiAdapter::parse_oauth_credentials` accepts refresh-token-only JSON
(and surfaces `{"access_token": "", ...}` for expired credentials) with
`access_token` defaulting to `""`. The Claude adapter's GeminiCli branch
then called `AuthInfo::with_access_token(key, creds.access_token)`
unconditionally, so the bearer-header builder at
`AuthStrategy::GoogleOAuth` resolved to `Authorization: Bearer ` — a
deterministic 401 from upstream.
CC Switch does not currently exchange the refresh_token for a fresh
access_token (`OAuthCredentials::needs_refresh` / `can_refresh` are
annotated `#[allow(dead_code)]`). Until that exists, only attach
`access_token` when it is non-empty; fall back to plain GoogleOAuth
strategy with the raw key and log a warn pointing users at
`~/.gemini/oauth_creds.json` so the failure mode is observable.
Tests:
- gemini_url.rs: three new regressions — opaque `/v1/models/invoke`,
opaque `/v1beta/models/route`, and the positive counter-case where a
structured `/v1/models/...:generateContent` path still normalizes.
- claude.rs: three new `test_extract_auth_gemini_cli_*` tests covering
refresh-only JSON, empty-string access_token JSON, and the valid-JSON
pass-through.
All 839 lib tests pass; cargo fmt + clippy -D warnings clean.
Addresses Codex review P2 findings on #1918.
P1 — Parallel tool calls without Gemini-assigned ids no longer collapse.
Gemini 2.x native parallel `functionCall` entries may omit the `id` field.
The previous `merge_tool_call_snapshots` fell back to matching by `name`,
which silently merged two parallel calls to the same function into one
entry — dropping the first call's args. The non-streaming path and shadow
store further bottlenecked on empty-string ids: multiple `tool_use` blocks
shared the same id, and `tool_name_by_id.get("")` could only return one
mapping, causing later `tool_result` round-trips to fail with
`Unable to resolve Gemini functionResponse.name` or bind to the wrong tool.
Fix: introduce `synthesize_tool_call_id()` producing `gemini_synth_<uuid>`.
Both streaming and non-streaming response paths now guarantee every
Anthropic-visible tool_use carries a unique id. `merge_tool_call_snapshots`
matches by id first, falling back to the `parts` array position (for the
cumulative-streaming case) while preserving the synthesized id across
chunks. `convert_message_content_to_parts` detects the synthetic prefix
and strips the id from outbound `functionCall`/`functionResponse` so the
internal identifier never leaks upstream. `shadow_parts` performs the
same strip when replaying a recorded assistant turn.
P2 — Vertex AI rejects empty `parameters` schemas. When an Anthropic tool
arrives with missing or empty `input_schema`, the proxy used to emit
`"parameters": {}` (no `type`), which fails Vertex AI validation with
`functionDeclaration parameters schema should be of type OBJECT`.
Contrary to the automated-review suggestion, the fix is not to omit
`parameters` (that too is rejected) but to normalize to the canonical
empty-object form `{type: "object", properties: {}}`.
Refs: google-gemini/generative-ai-python#423, BerriAI/litellm#5055.
Fix: new `ensure_object_schema` helper in `gemini_schema` promotes
missing `type` to `"object"` and adds empty `properties` when absent,
while leaving atomic (non-object) schemas untouched.
Tests: seven new regressions covering parallel no-id calls, cumulative
chunk id reuse, synthetic-id round-trip both directions, shadow replay
id stripping, and the three Vertex-AI schema shapes.
The two existing wrapper functions (`gemini_to_anthropic` and
`gemini_to_anthropic_with_shadow`) gain `#[allow(dead_code)]` to clear
a pre-existing clippy -D warnings failure — they are part of the public
transform API surface and intentionally kept for future callers.
Addresses Codex review P1/P2 on #1918.
Claude Code follow-up requests were still falling back to locally reconstructed functionCall parts, which dropped Gemini thought signatures and triggered INVALID_ARGUMENT errors from the official Gemini API. The replay path needed to survive real Claude request boundaries, not just idealized in-process test flows.
This change makes Claude requests reuse X-Claude-Code-Session-Id as the shadow session key, records streamed Gemini tool turns before tool_use events are fully drained, and matches assistant tool_use turns to shadow state by tool_use id and normalized tool name before positional fallback. Together these fixes keep thoughtSignature-bearing Gemini tool calls available for the next request in the loop.
Constraint: Claude Code sends a stable X-Claude-Code-Session-Id header while metadata.session_id may be absent on follow-up requests
Rejected: Rely on metadata-only Claude session extraction | generated fresh session ids and broke cross-request shadow replay
Rejected: Record Gemini shadow only after streaming completes | loses the race when the client sends the next request immediately after tool_use
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Preserve Gemini shadow continuity across requests by keying Claude sessions from the header first and persisting tool-call shadow before yielding tool_use events downstream
Tested: cargo fmt --manifest-path src-tauri/Cargo.toml --all; cargo test --manifest-path src-tauri/Cargo.toml test_extract_session_from_claude_header; cargo test --manifest-path src-tauri/Cargo.toml test_extract_session_from_claude_header_precedes_metadata; cargo test --manifest-path src-tauri/Cargo.toml stores_tool_shadow_before_tool_use_events_are_fully_drained; cargo test --manifest-path src-tauri/Cargo.toml shadow_replay_matches_tool_use_turn_by_id_when_position_drifts; cargo test --manifest-path src-tauri/Cargo.toml shadow_replay_aligns_to_latest_turns_after_client_truncation
Not-tested: Full src-tauri test suite without test filters; live end-to-end Gemini relay after this exact commit hash
PR #1918 review feedback exposed two correctness issues in the Gemini Native adapter path. Gemini SSE buffering was still using lossy UTF-8 decoding, which could corrupt split multibyte payloads and drop streamed output. Tool arg rectification also removed top-level parameters eagerly, which broke tools that legitimately define a parameters field.
This change moves Gemini SSE buffering onto the existing append_utf8_safe path and makes parameters flattening conditional on the schema actually expecting nested extraction. The old Skill rectification path stays intact, and new regression tests cover both the preserved parameters case and UTF-8-split JSON payloads.
Constraint: Existing PR #1918 review feedback must be fixed without staging unrelated local docs and artifact files
Rejected: Keep String::from_utf8_lossy in Gemini SSE buffering | corrupts split multibyte payloads and can drop JSON chunks
Rejected: Always preserve the parameters wrapper | regresses the existing nested-parameters rectification path for Skill-style tools
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep Gemini SSE buffering on the UTF-8-safe accumulator path and only unwrap parameters when the target schema does not declare it as a legitimate field
Tested: cargo fmt --manifest-path src-tauri/Cargo.toml --all; cargo test --manifest-path src-tauri/Cargo.toml preserves_utf8_boundaries_when_json_payload_spans_chunks; cargo test --manifest-path src-tauri/Cargo.toml gemini_to_anthropic_rectifies_tool_args_from_schema_hints; cargo test --manifest-path src-tauri/Cargo.toml rectifies_streamed_skill_args_from_nested_parameters; cargo test --manifest-path src-tauri/Cargo.toml gemini_to_anthropic_preserves_legitimate_parameters_arg
Not-tested: Full src-tauri test suite; live end-to-end Gemini relay traffic against upstream services
* chore(stream-check): update default health check models to latest
Replaces deprecated gpt-5.1-codex@low with gpt-5.4@low and switches
the Gemini default from gemini-3-pro-preview to gemini-3-flash-preview
to pick the lightest variant of the latest series for fast, low-cost
health checks.
https://claude.ai/code/session_01NGWLchcTP76rJHjiP5Ehte
* feat(stream-check): detect model-not-found errors with dedicated toast
Health check previously classified failures purely by HTTP status code,
which meant deprecated/invalid models showed up as a generic "Not found
(404)" error pointing users to check the Base URL — misleading when the
URL is fine and only the test model is wrong (e.g. gpt-5.1-codex after
it was retired).
Backend: add detect_error_category() that inspects 4xx response bodies
for model-not-found indicators (model_not_found, does not exist,
invalid model, not_found_error, etc.) and returns a "modelNotFound"
category. Thread the resolved test model through build_stream_check_result
so the failed result carries it in model_used. Add StreamCheckResult
.error_category field (serde-skipped when None).
Frontend: useStreamCheck branches on errorCategory === "modelNotFound"
before the HTTP-status fallback and renders a toast.error with the model
name and a description pointing to Model Test Config. Add i18n keys
(modelNotFound / modelNotFoundHint) for zh/en/ja.
Tests: unit-test detect_error_category against real OpenAI/Anthropic
error shapes, 5xx false-positive avoidance, and plain 401 auth errors.
https://claude.ai/code/session_01NGWLchcTP76rJHjiP5Ehte
* fix(stream-check): add missing error_category field in fallback
The error_category field was added to StreamCheckResult in this branch
but the fallback constructor in stream_check_all_providers was not
updated, which broke cargo build.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(opencode): use json5 parser for trailing comma tolerance
OpenCode CLI writes opencode.json with trailing commas (valid JSONC),
but CC Switch parsed it with serde_json (strict JSON), causing errors
like 'trailing comma at line 35 column 3'.
Switch to json5::from_str which accepts both JSON and JSONC. The json5
crate is already a project dependency. Change error type from
AppError::json() to AppError::Config() since json5::Error differs from
serde_json::Error.
* style(opencode): apply rustfmt to satisfy cargo fmt --check
The previous commit's .map_err(...) chain exceeded rustfmt's default
100-char max_width, breaking CI's `cargo fmt --check`. Let rustfmt
wrap the closure body as a multi-line block. No behavior change.
---------
Co-authored-by: 18067889926 <ming.flute@outlook.com>
Co-authored-by: Jason <farion1231@gmail.com>
write_gemini_live() unconditionally cleared env_map for GoogleOfficial
auth type, discarding user-configured env vars (e.g. GEMINI_MODEL).
Remove the env_map.clear() call so the user's settings_config.env is
written as-is, and merge identical Packycode/Generic match arms.
Distinguish between "provider rejects probe" (yellow warning) and
"genuinely broken" (red error) in health check results.
Backend: add AppError::HttpStatus variant to carry structured HTTP
status codes, populate http_status on error results, classify codes
into short labels (e.g. "Auth rejected (401)"), and truncate overly
long response bodies.
Frontend: route 401/403/400/429/5xx to toast.warning with localized
hints explaining the error may not indicate actual unusability; route
404/402/connection errors to toast.error. Add i18n keys for all three
locales (zh/en/ja).
Also deduplicate check_once by reusing build_stream_check_result.
When a search query matches text beyond the collapse point, the message
automatically expands to show the highlighted match. Also adds
aria-expanded for accessibility.
Messages over 3000 characters are now truncated to 1500 characters by
default, with an expand/collapse toggle. This avoids expensive browser
text layout for large AI responses containing code or tool output.
Replace full DOM rendering with @tanstack/react-virtual to only render
visible messages (~25 DOM nodes instead of N). Wrap SessionMessageItem
in React.memo to prevent unnecessary re-renders on state changes.
When a repo itself is a single skill (SKILL.md at repo root), the
discovery phase sets directory to the repo name, but after ZIP
extraction (which strips the root folder), no matching subdirectory
exists. Add a fallback to check if SKILL.md exists directly in the
extracted temp directory before reporting SKILL_DIR_NOT_FOUND.
Fixes installation of repos like zlbigger/Google-SEOs.skill.
The request count and total cost were displayed both in the app filter
bar and in the UsageSummaryCards below it. Remove the redundant inline
summary and its unused imports.
Replace all remaining "代理服务/Proxy Service/プロキシサービス" references
in the local routing feature context with "路由服务/Routing Service/
ルーティングサービス". This covers service settings, status messages,
tooltips, field descriptions, and tab labels.
Global Proxy, HTTP proxy hints, and AI Agent references are unchanged.
Rename 4.2-takeover.md to 4.2-routing.md in zh/en/ja user manuals,
replacing all "接管/takeover" terminology with "路由/routing" to match
the rebranded feature name. Update README index links accordingly.
Replace all user-facing references to "本地代理接管/Local Proxy/Takeover"
with "本地路由/Local Routing/ローカルルーティング" across zh/en/ja to
eliminate naming confusion with the separate "Global Proxy" feature.
Only i18n string values are changed; keys, code identifiers, and
database schema remain untouched.
The per-provider proxy configuration (meta.proxyConfig) is removed
because its scope is too narrow and covered by global proxy settings
and proxy takeover mode. Users can achieve the same result via the
global proxy panel.
Changes:
- Remove ProviderProxyConfig type (frontend TS + backend Rust)
- Remove ProviderAdvancedConfig proxy UI block, keep testConfig/pricingConfig
- Simplify http_client: delete build_proxy_url_from_config,
build_client_for_provider, get_for_provider
- Simplify forwarder/stream_check/model_fetch to use global client
- Remove i18n keys (en/zh/ja)
- Fix pre-existing test bug in transform.rs (extra None arg)
- Fix request classification: treat messages containing tool_result as
agent continuation instead of user-initiated, preventing false premium
charges on every tool call
- Add subagent detection via __SUBAGENT_MARKER__ and metadata._agent_
fallback, setting x-interaction-type=conversation-subagent
- Add deterministic x-interaction-id derived from session ID to group
requests into a single billing interaction
- Add orphan tool_result sanitization to prevent upstream API errors
that could cause retries and duplicate billing
- Reorder pipeline: classify (on original body) → sanitize → merge →
warmup, ensuring classification sees raw tool_result semantics
- Enable warmup downgrade by default with gpt-5-mini model
- Enhance session ID extraction priority chain for Copilot cache keys
- Detect infinite whitespace bug in streaming tool call arguments
SSRF protection (private IP blocking, suspicious hostname detection) was
originally added for web-server threat models but is unnecessary for a
local desktop app where the user already has full network access. This
removal unblocks legitimate use cases like enterprise intranet APIs,
Docker container addresses, and self-hosted services.
Retained: HTTPS enforcement and same-origin checks which still provide
meaningful security (protecting API keys in transit and preventing
scripts from leaking keys to unrelated domains).
The RequestLogTable had a hardcoded 24-hour rolling window, ignoring the
dashboard's time range selector. Now it accepts a timeRange prop and
dynamically adjusts the query window, so users can view logs beyond just
the last day.
Show first 3 and last 3 page buttons instead of just first/last, with
Set-based deduplication for clean edge merging. Add a page number input
field with Go button for direct page navigation.
OpenClaw gateway injects `[message_id: UUID]` metadata at the end of
every message, wasting display space. Strip this suffix from both title
and summary fields.
Also change session title display from single-line truncate to
line-clamp-2, so longer titles (e.g. OpenClaw's timestamp-prefixed
messages) can show more meaningful content across two lines.
Previously Codex and OpenClaw sessions only showed the working directory
basename as the title, making it hard to distinguish sessions in the same
project. Now both providers extract the first real user message as the
session title, matching the existing Claude Code behavior.
- Codex: first user message → dir basename (skips AGENTS.md injection)
- OpenClaw: displayName (sessions.json) → first user message → dir basename
- Move TITLE_MAX_CHARS constant to shared utils.rs
- Use Option<&HashMap> for OpenClaw parse_session to avoid leaky abstraction
Extract message_id from Claude API responses (msg_xxx) and use it to
generate a shared request_id format (session:{msg_xxx}) between the
proxy logger and session log sync. When session sync encounters the
same request_id via INSERT OR IGNORE, it skips the duplicate.
- Add message_id field to TokenUsage, extracted from Claude responses
- Add TokenUsage::dedup_request_id() to generate shared request IDs
- Define SESSION_REQUEST_ID_PREFIX constant to eliminate magic strings
- Change proxy logger to INSERT OR REPLACE for richer-data-wins semantics
Add pricing data for 4 new providers (Qwen, xAI Grok, Mistral, Cohere)
and supplement existing providers (MiniMax M2.5/M2.7, GLM-5/5.1,
Doubao Seed 2.0, MiMo V2 Pro, OpenAI o1/o3/codex-mini/gpt-5-mini/nano).
Fix outdated prices for deepseek-chat, deepseek-reasoner, and kimi-k2.5.
Fix display_name casing "Mimo" → "MiMo" for consistency.
Use prepared statement in seed_model_pricing() to avoid recompiling SQL
on each of ~130 INSERT iterations.
Schema migration v8→v9: DELETE + re-seed model_pricing for existing users.
Prevent users from switching to official providers (Anthropic/OpenAI/Google)
when proxy takeover is active, as using a proxy with official APIs may cause
account bans.
Defense-in-depth across 4 layers:
- Backend: ProviderService::switch(), hot_switch_provider(), switch_proxy_provider command
- Frontend: useProviderActions soft guard with error toast
- UI: ProviderActions button disabled with ShieldAlert icon
- Tray menu: official provider items disabled with ⛔ indicator
Also warns when enabling proxy takeover while current provider is official.
* Preserve cache hints when collapsing system prompts
Strict OpenAI-compatible chat backends still need fragmented Claude\nsystem prompts collapsed into one leading system message, but that\nnormalization should not silently drop stable cache hints. Preserve\nmessage-level cache_control when the merged system fragments agree,\nand fall back to omitting it when the fragments conflict.\n\nConstraint: Must keep single-system normalization for Nvidia/Qwen-style chat backends\nRejected: Always copy the first cache_control | could misrepresent conflicting cache boundaries\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: If system prompt merging changes again, preserve cache_control whenever the merged metadata is unambiguous\nTested: cargo test proxy::providers::transform --manifest-path src-tauri/Cargo.toml\nNot-tested: End-to-end prompt caching behavior against cache-aware OpenAI-compatible upstreams\nRelated: #1881
* Tighten cache hint inheritance for merged system prompts
The follow-up cache hint fix still treated mixed present/absent\ncache_control across fragmented system prompts as inheritable, which\nexpanded the cache scope after prompt collapse. Treat that mix as\nambiguous and only preserve cache_control when every merged fragment\nexplicitly agrees on the same value.\n\nConstraint: Must preserve strict-backend system prompt normalization from #1942\nRejected: Inherit first present cache_control | widens cache scope when later fragments were intentionally uncached\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Any future merged-system cache hint logic should treat missing cache_control as semantically significant\nTested: cargo test proxy::providers::transform --manifest-path src-tauri/Cargo.toml\nNot-tested: End-to-end upstream caching behavior against cache-aware relays\nRelated: #1881\nRelated: #1946
* Keep cache-control merge regressions easy to review
Reflow the two long cache-control regression assertions in transform.rs so the neighboring merge cases stay rustfmt-aligned and easier to scan.
This keeps the preserved code change separate from the untracked Markdown design notes the user did not want committed.
Constraint: Exclude Markdown design files from the commit while preserving the local code change
Rejected: Include docs in the same commit | user explicitly asked to leave Markdown files out
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Treat this as a readability-only test change; do not infer runtime behavior changes from it
Tested: cargo test --manifest-path src-tauri/Cargo.toml test_anthropic_to_openai_drops_ --lib
Tested: cargo check --manifest-path src-tauri/Cargo.toml --tests
Tested: pnpm format:check
Tested: pnpm typecheck
Not-tested: Full application integration and manual flows
Responses conversions still use promptCacheKey, but chat completions now stay a pure shape transform. This keeps Claude -> chat requests aligned with providers that do not understand the field and keeps stream checks consistent with production behavior.
Constraint: Issue #1919 requires removing prompt_cache_key from Claude -> OpenAI Chat requests
Rejected: Add a runtime toggle for chat injection | requested behavior is unconditional removal
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep promptCacheKey limited to Claude -> Responses conversions unless a provider-specific contract is proven
Tested: cargo test anthropic_to_openai
Tested: cargo test anthropic_to_responses_with_cache_key
Tested: cargo test transform_claude_request_for_api_format_responses
Not-tested: Full src-tauri test suite
Related: #1919
* feat(window): add app-level window controls with settings toggle
Add a persistent settings toggle to enable app-level minimize/maximize/close controls and hide system decorations when enabled, providing a Wayland-friendly fallback for broken native titlebar interactions.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(window): restrict app-level window controls to Linux only and fix startup flicker
- Guard useAppWindowControls with isLinux() in App.tsx so it's always
false on macOS/Windows even if persisted as true
- Wrap set_decorations call in lib.rs with #[cfg(target_os = "linux")]
- Only show the toggle in WindowSettings on Linux
- Skip setDecorations effect while settingsData is still loading to
prevent the Rust-side decoration state from being overridden by the
undefined->false fallback, which caused a brief title bar flicker
---------
Co-authored-by: wzk <wx13571681304@outlook.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Jason <farion1231@gmail.com>
- Simplify "ChatGPT Plus / Pro" → "ChatGPT" across all three languages
- Clarify Codex OAuth description to highlight Claude Code usage
- Add "requires manual activation" note for Token Plan and third-party balances
- Add Copilot API consumption caveat to the interaction optimizer section
- Update overview with skills.sh search, usage tracking, and onboarding mentions
- Add PR credits for TheRouter (@cmzz), Kaku/OMO Slim/Thinking fallback/auth tab (@yovinchen)
Update base URL to cc-api.pipellm.ai, add complete model definitions
(Opus/Sonnet/Haiku), add Codex preset with custom TOML config, add
pipellm PNG icon, and set apiKeyUrl to referral link.
Multi-protocol provider: Anthropic for Claude, OpenAI Responses for
Codex/OpenClaw, OpenAI for OpenCode, custom Gemini config. Includes
PNG icon via URL import and provider-specific settings like effortLevel,
enabledPlugins, and custom TOML config for Codex.
Add Shengsuanyun (胜算云) as an aggregator partner across all five apps,
positioned right after official providers. Uses anthropic-messages
protocol for OpenCode/OpenClaw. Includes URL-based icon import (217KB
SVG), partner promotion i18n for zh/en/ja, and localized display name.
The icon index (index.ts) is hand-curated with optimized SVG content
and custom name mappings. Running the generation script destroys these
optimizations. Remove the script entirely to eliminate the risk.
Add LionCCAPI as a third-party partner provider across all five apps
(Claude, Codex, Gemini, OpenCode, OpenClaw) with anthropic-messages
protocol for OpenCode and OpenClaw. Include partner promotion i18n
entries for zh/en/ja locales and lioncc icon.
When thinking.type is "adaptive" (Claude's maximum thinking mode) and
output_config.effort is absent, resolve_reasoning_effort() incorrectly
mapped it to "high" instead of "xhigh" in OpenAI format conversions.
Replace the old low-res x-code inline SVG (7.6KB) with a new high-res
xcode.svg (286KB) loaded via Vite URL import. Update all three provider
preset files to reference the new icon name.
Add dual rendering mode to the icon system: small optimized SVGs
continue to be inlined via dangerouslySetInnerHTML, while large SVGs
and raster images (png/jpg/webp/etc) use Vite URL imports rendered
as <img> tags. Added dds.svg (1.4MB) as the first URL-based icon.
Updated generate-icon-index.js to support multi-format icons with
a manual URL_ICONS control list. Updated ProviderIcon to handle
both inline SVG and URL-based rendering paths.
cc-switch could already persist arbitrary OMO Slim agent keys and top-level fields, but the built-in metadata and UI copy still reflected the pre-council agent set. This made the upstream council feature look unsupported and pushed users toward manual JSON-only setup.
Promote council to a built-in OMO Slim agent, add copy that points top-level plugin settings at Other Fields, and lock the behavior with regression tests.
Constraint: oh-my-opencode-slim exposes council through both agents.council and top-level council config
Rejected: Add a dedicated council editor UI now | too much surface area for issue #1981
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep OMO Slim built-in agent metadata aligned with upstream agent additions before shipping UI support
Tested: pnpm exec vitest run tests/utils/omoConfig.test.ts tests/components/OmoFormFields.mergeCustomModelsIntoStore.test.ts
Tested: pnpm typecheck
Not-tested: End-to-end validation against a live oh-my-opencode-slim installation
Related: farion1231/cc-switch#1981
Kaku is a WezTerm-derived macOS terminal, so reusing the existing WezTerm-compatible launch path keeps the change small while making it selectable in settings and session resume flows.
Constraint: Kaku support should stay macOS-only and avoid introducing a separate launcher model
Rejected: Treat Kaku as a silent WezTerm fallback | users could not explicitly choose it in settings
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep Kaku on the shared WezTerm-compatible launch path unless upstream drops the start-compatible CLI
Tested: pnpm typecheck; pnpm format:check; cargo check --manifest-path src-tauri/Cargo.toml; cargo fmt --manifest-path src-tauri/Cargo.toml --check; cargo test --manifest-path src-tauri/Cargo.toml --lib session_manager::terminal::tests
Not-tested: End-to-end launch against a locally installed Kaku.app
Related: #1954
The Claude provider form reopened with an empty Thinking model after users saved only a main model. This updates model-state hydration to mirror the existing Haiku-style fallback semantics: read ANTHROPIC_REASONING_MODEL when present, otherwise display ANTHROPIC_MODEL, without writing a synthetic reasoning field back into config.
Constraint: Existing Haiku, Sonnet, and Opus selectors already rely on read-time fallback behavior
Rejected: Persist ANTHROPIC_REASONING_MODEL from ANTHROPIC_MODEL automatically | would diverge from Haiku behavior and silently rewrite saved config
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep Thinking fallback read-only unless all model-mapping fields are intentionally migrated to write-through semantics
Tested: pnpm typecheck
Tested: pnpm test:unit (1 unrelated pre-existing failure in tests/components/UnifiedSkillsPanel.test.tsx mock setup)
Not-tested: Manual add-provider reopen flow in the desktop UI
The settings page already routes the auth tab label through the shared i18n key, but the locale bundles never defined that key. Adding the missing entries fixes the label with the same simple pattern used by the other tabs.
Constraint: Keep the fix aligned with the existing settings-tab i18n flow
Rejected: Add component-level bilingual rendering | unnecessary for a missing translation key
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When adding settings tabs, define locale keys in every bundled language before relying on fallback text
Tested: pnpm format:check; pnpm typecheck
Not-tested: Manual verification in the desktop UI
- Make migrate_v6_to_v7 check skills table existence before ALTER
- Make migrate_v7_to_v8 check model_pricing table existence before UPDATE
- Fix SessionManagerPage test: use getByRole heading instead of getAllByText
which breaks when highlightText splits text across <mark> elements
- Add content_hash and updated_at fields to 4 InstalledSkill literals in skill_sync.rs
- Add useCheckSkillUpdates and useUpdateSkill to UnifiedSkillsPanel test mock
- Suppress unused import warning in auto_launch.rs test module
- Pre-filter sessions by provider before indexing to prevent result
truncation when FlexSearch limit cuts across providers
- Switch tokenizer from "forward" to "full" for Chinese substring matching
- Preserve FlexSearch relevance ranking when search query is present
Instead of showing directory basenames for all Claude sessions, extract
titles from JSONL content with a priority chain:
1. custom-title metadata (set via /rename in Claude Code)
2. First real user message (skipping /clear, /compact caveats)
3. Directory basename (fallback)
Display a one-time informational dialog explaining the Common Config
Snippet feature when users first open the add/edit provider form.
Uses a derived isOpen state from settings to avoid race conditions.
Adds commonConfigConfirmed flag to both TS and Rust settings types.
Add an informational alert block at the top of the common config snippet
editor modal (Claude/Codex/Gemini) explaining what the feature is, why
it exists, and how to use it. Also add an empty state prompt when no
snippet has been extracted yet, guiding users to click "Extract from
Editor". Includes i18n support for zh/en/ja.
CLI-credential-based subscriptions (Claude/Codex/Gemini) read from a
single global credential file, so the quota always reflects the last
CLI login rather than a specific provider. Showing it on non-current
cards is misleading when multiple official subscriptions exist.
Apply the same isCurrent + autoQuery pattern already used by Copilot
and Codex OAuth: only query and render the quota footer when the
provider is the currently active one.
When switching to Copilot/ChatGPT/OpenAI-format providers with the proxy
not running, two toasts appeared: a "proxy required" warning followed by
a "switch success" toast. Unify the post-switch toast logic so that all
provider types show a single success toast, and skip it entirely when
a proxy-required warning was already shown.
Introduce a one-time welcome dialog that explains CC Switch's workflow
to new users: how their existing config is preserved as a "default"
provider and how the bundled "Official" preset enables one-click revert.
Upgrade users are excluded by checking is_providers_empty() at startup
and never see the dialog.
Persistence follows the existing *_confirmed convention in AppSettings
(proxy/usage/stream_check/failover), stored in settings.json. The field
is only written when the user explicitly clicks the confirm button,
keeping its semantics strictly about user acknowledgement.
Also adds two reusable DAO helpers:
- Database::is_providers_empty for fresh-install detection, using
EXISTS(SELECT 1) for a short-circuit query.
- Database::get_bool_flag accepting "true" | "1", with
init_default_official_providers migrated to use it.
Dialog copy in zh/en/ja uses conditional phrasing so it stays
accurate whether or not existing live config was found.
Refresh the user manual to cover the v3.13.0 feature set so users can
discover and correctly use new functionality without cross-referencing
the release notes. All three language versions are updated
line-by-line symmetric.
Highlights:
- Lightweight Mode: tray-only running state added in 1.5-settings,
with a comparison table against "Minimize to tray" and a new OAuth
Auth Center (Beta) section
- Quota & Balance display restructured in 2.5-usage-query: split into
auto-query (Claude/Codex/Gemini official, Copilot, Codex OAuth) vs
manual-enable (Token Plan, third-party balances). Explains why
manual enabling is required: the same API URL may expose both
plan-quota and balance query modes
- Codex OAuth reverse proxy: full usage guide in 2.1-add with two
entry points (Add Provider panel / OAuth Auth Center), Device Code
login flow, token auto-refresh, multi-account management, quota
display, common failures, and risk notice
- Full URL Endpoint Mode: new advanced option in 2.1-add
- Per-app tray submenus: 2.2-switch refactored to reflect the 5-app
submenu structure and cross-link to Lightweight Mode
- Skills workflow: remove obsolete "automatic update not supported"
section in 3.3-skills, add SHA-256 update detection, single/batch
update, storage location switch, and skills.sh registry search
- Directory picker for Claude terminal resume in 3.4-sessions
- Usage stats in 4.4-usage: document the new CLI session log source
(no proxy required) and per-app filtering for Claude/Codex/Gemini;
note CNY->USD pricing corrections and MiniMax quota fixes
- Stream Check coverage extended to OpenCode/OpenClaw in 4.5-model-test
- New FAQs in 5.2-questions: quota visibility (auto vs manual),
Codex OAuth risks and login flow, deep link wake in Lightweight Mode
- v3.13.0 highlights navigation block added to top-level README and
each per-language README; version bumped to v3.13.0 / 2026-04-08
Drops the friction of clicking the manual "Import current config" button
for OpenCode and OpenClaw — they now match the auto-import behavior the
previous commit added for Claude/Codex/Gemini.
- New "1.6." startup block in lib.rs runs both
import_opencode_providers_from_live and import_openclaw_providers_from_live
on every launch. The functions are id-keyed and idempotent, so re-running
just picks up new providers added externally to the live JSON files.
- Both functions now use a new Database::get_provider_ids() helper
(HashSet<String> from a single SELECT id-only query) instead of
get_all_providers(), avoiding the N+1 endpoint sub-queries that would
otherwise hit the startup hot path on every launch.
New and existing users now see a built-in "Claude Official" / "OpenAI
Official" / "Google Official" entry in their provider list, so switching
back to the official endpoint is one click away instead of buried in the
README.
- New providers_seed.rs holds the three seeds (id, name, settings_config,
icon) keyed by AppType, with a single is_official_seed_id() helper that
scans OFFICIAL_SEEDS so the id list has one source of truth.
- Database::init_default_official_providers() runs once per database
(gated by an official_providers_seeded setting flag), appends each seed
to the end of the sort order, and never touches is_current.
- Startup also auto-imports the live config (settings.json / auth.json /
.env) as a "default" provider before seeding, so users with an existing
manual config don't lose it when they click the official preset.
- Database::has_non_official_seed_provider() replaces the get_all_providers
call in import_default_config's gating check with an id-only scan,
dropping the N+1 endpoint sub-queries from every startup.
CopilotQuotaFooter and CodexOauthQuotaFooter called their hooks with a
hardcoded `enabled: true` plus an unconditional 5-minute refetch and
refetchOnWindowFocus, so non-current reverse-proxy cards kept polling
in violation of the project's "only the active provider auto-queries
on cooldown" rule. With multiple Copilot or ChatGPT accounts bound to
different cards, every card kept hitting its own usage endpoint.
Adopt the same pattern as useUsageQuery: keep `enabled` independent of
isCurrent so first-fetch and manual refresh still work, but gate
refetchInterval / refetchIntervalInBackground / refetchOnWindowFocus on
a new `autoQuery` option, and thread `isCurrent` from ProviderCard
through the footers into the hooks.
Draft trilingual release notes for the upcoming v3.13.0 feature release
covering lightweight mode, quota and balance visibility, provider model
auto-fetch, Codex OAuth reverse proxy, tray per-app submenus, the
Hyper-based proxy forwarding stack, Skills discovery and batch updates,
session workflow upgrades, OpenCode/OpenClaw Stream Check coverage, the
full URL endpoint mode, and the Copilot interaction optimizer, plus the
accompanying Copilot auth, UTF-8 streaming boundary, system prompt
normalization, WebDAV password, and Linux startup fixes. Contributor
attribution follows industry convention using ASCII punctuation inside
PR references across all three locales, and the Codex OAuth reverse
proxy carries its own risk notice alongside a backward link to the
v3.12.3 Copilot risk notice.
Document two additional Fixed entries for the Unreleased section after
rebasing onto the latest origin/main: the SSE streaming UTF-8 chunk
boundary fix that prevents U+FFFD replacement characters in multi-byte
output via the Copilot reverse proxy, and the OpenAI-compatible chat
transform fix that normalizes fragmented Claude system prompts into a
single leading system message for strict backends like Nvidia and
Qwen-style providers.
Post-merge cleanup from a simplify review pass on the phase 1-4
OpenCode/OpenClaw changes.
- Rename check_once_opencode_like → check_once_without_adapter. The
new name directly expresses the intent (bypass get_adapter) instead
of suggesting the function is somehow "like" OpenCode.
- Drop two "Phase 4 会美化错误消息" phase-history markers from
docstrings; git history is the right place for them.
- Document in resolve_opencode_base_url why its default endpoints
cannot be merged with ProviderType::default_endpoint(): the former
encode AI SDK package defaults (e.g. @ai-sdk/openai ships with the
/v1 suffix) while the latter encode proxy upstream hosts. They
happen to overlap but are two independent truth sources.
Phase 4: polish the four remaining edge cases uncovered by Phase 1-3.
Custom headers passthrough
- check_claude_stream and check_gemini_stream now accept an optional
extra_headers map which is appended after all built-in headers so it
can override defaults (e.g. a custom User-Agent).
- OpenClaw reads from settings_config.headers.
- OpenCode reads from settings_config.options.headers.
- All pre-existing Claude/Codex/Gemini call sites pass None.
OpenClaw custom auth header (Longcat-style)
- When settings_config.authHeader is true, the provider expects a
custom auth header whose name is only known to the OpenClaw gateway
itself. Return a dedicated openclaw_auth_header_not_supported error
so the user sees a meaningful explanation instead of a 401.
Bedrock error polish
- The bedrock-converse-stream (OpenClaw) and @ai-sdk/amazon-bedrock
(OpenCode) branches now explain why (SigV4 signing) and point to
the official consoles as an alternative test path.
OpenCode baseURL fallback
- resolve_opencode_base_url: when options.baseURL is empty and the
npm package has a canonical default endpoint (@ai-sdk/openai,
@ai-sdk/anthropic, @ai-sdk/google), fall back to that endpoint.
@ai-sdk/openai-compatible still requires an explicit baseURL
because its whole purpose is to point at a custom OpenAI clone.
Tests
- 8 new unit tests covering authHeader detection, baseURL resolution
(explicit / fallback / error), and header map extraction on both
apps. Total stream_check tests: 18 → 26.
Phase 3: implement stream check for OpenCode providers by mapping the
`settings_config.npm` (AI SDK package name) to the corresponding API
protocol and delegating to the existing stream checkers.
Package mapping:
- @ai-sdk/openai-compatible → openai_chat
- @ai-sdk/openai → openai_responses
- @ai-sdk/anthropic → anthropic (ClaudeAuth strategy)
- @ai-sdk/google → gemini (Google strategy)
- @ai-sdk/amazon-bedrock → not supported (phase 4 message polish)
Note: OpenCode nests baseURL/apiKey under `settings_config.options`
(different from OpenClaw's root-level fields) and uses `baseURL` with
a capital L. Three new extractors (base_url / api_key / npm) encode
these shape differences so check_opencode_stream stays symmetric with
check_openclaw_stream.
Frontend: drop the remaining `appId !== "opencode"` filter in
ProviderList.tsx — both apps can now test providers.
Phase 2: extend check_openclaw_stream to cover the full non-Bedrock
protocol set declared by openclawApiProtocols.
- openai-responses → check_claude_stream(api_format="openai_responses")
- anthropic-messages → check_claude_stream(api_format="anthropic"),
using AuthStrategy::ClaudeAuth (Bearer-only) so Claude relay
services that reject a simultaneous x-api-key still work. Official
Anthropic also accepts pure Bearer on /v1/messages.
- google-generative-ai → check_gemini_stream with AuthStrategy::Google.
bedrock-converse-stream still errors out but with a dedicated
openclaw_bedrock_not_supported key; its user-facing message will be
polished in phase 4.
Each protocol now builds its own AuthInfo inside the match arm because
the auth strategy is protocol-specific.
Phase 1 of extending stream health check to OpenCode/OpenClaw apps.
- Add early-dispatch path for OpenCode/OpenClaw in check_once so they
bypass the adapter layer (which only knows Claude/Codex/Gemini
settings_config shapes).
- Introduce check_openclaw_stream dispatcher that reads the `api` field
from settings_config and routes to the existing check_claude_stream
with api_format="openai_chat" for "openai-completions". Other
protocols return localized errors to be lit up in phases 2 and 4.
- Extract build_stream_check_result helper to avoid duplicating the
StreamCheckResult construction logic between the two code paths.
- Unblock the test button for OpenClaw providers in ProviderList.tsx.
OpenCode still returns the "not yet supported" error; it will be
enabled in phase 3.
These OAuth providers ship with non-empty ANTHROPIC_BASE_URL, so the
isOfficialProvider() heuristic (which checks for a missing base URL)
returned false and left the health-check and usage-config buttons
enabled — inconsistent with other official OAuth cards. Extend the
button disabling logic at the call site with isCopilot / isCodexOauth,
matching the pattern already used for the quota footer branch above.
Update the "Codex (ChatGPT Plus/Pro)" entry in Claude Code presets to
the new GPT-5.4 naming, which drops the legacy `-codex` suffix. Map the
Haiku tier to `gpt-5.4-mini` for lower-cost lightweight calls while
keeping Sonnet/Opus on the standard `gpt-5.4`.
Linux users reported the window UI (including native title bar buttons)
couldn't receive clicks until manually maximizing and restoring the
window. Root causes: (1) Tauri webview did not acquire focus on startup
so first clicks were consumed by X11/Wayland click-to-activate
(Tauri #10746, wry #637); (2) GTK surface input region failed to
renegotiate on the visible:false + show() path under some
WebKitGTK/compositor combinations.
- Add linux_fix::nudge_main_window helper that performs set_focus plus
a ±1px no-op resize after window show, with a 500ms reconciliation
readback to compensate for dropped resize requests on slow
compositors.
- Wire the helper into every window re-show path: normal startup,
deeplink, single_instance, tray show_main, and lightweight exit.
- Set WEBKIT_DISABLE_COMPOSITING_MODE=1 at startup to avoid resize
crashes and Wayland surface negotiation issues.
- Remove data-tauri-drag-region on Linux from App.tsx header and the
shared FullScreenPanel (used by all provider/MCP/workspace forms)
to avoid Tauri #13440 in Wayland sessions. Extract drag-region
constants to src/lib/platform.ts for reuse.
All Rust changes are gated by #[cfg(target_os = "linux")]; frontend
changes preserve macOS/Windows behavior via runtime isLinux() checks.
Known limitation: tiling Wayland compositors ignore set_size, so
GDK_BACKEND=x11 remains the user-side workaround.
Use "Skills" consistently in skillStorage title/description and
skillSync title to match the upstream Agent Skills wording and the
existing English label style used elsewhere on the settings page.
- Trim Auth Center section descriptions to focus on user intent
- Remove duplicate outer heading on the auth settings tab
- Swap Sparkles glyph for CodexIcon on the ChatGPT card
- Generalize codexOauth.authStatus to a neutral "Auth status"
- Register settings.authCenter.* keys across zh/en/ja locales
Codex OAuth (ChatGPT Plus/Pro) providers previously fell through to the
default UsageFooter branch and showed no quota at all, while Copilot and
official Codex providers already had a wham/usage-backed quota footer.
This wires up the same five-hour / seven-day tier badges for codex_oauth
provider cards by reusing the existing query_codex_quota function and
SubscriptionQuotaFooter rendering, parameterized to keep both the CLI
credential path ("codex") and the cc-switch managed OAuth path
("codex_oauth") working from a single source of truth.
- Parameterize services::subscription::query_codex_quota with tool_label
and expired_message; promote SubscriptionQuota constructors to
pub(crate). The CLI path keeps its existing "codex" label and the
"re-login with Codex CLI" message; the new path passes "codex_oauth"
and a cc-switch-specific re-login hint.
- Add a new get_codex_oauth_quota Tauri command in commands/codex_oauth.rs
that resolves the ChatGPT account (explicit binding > default account
> not_found), pulls a valid access_token from CodexOAuthManager
(auto-refresh handled), and delegates to query_codex_quota.
- Extract SubscriptionQuotaFooter's render body into a pure
SubscriptionQuotaView component (props: quota / loading / refetch /
appIdForExpiredHint / inline). The existing SubscriptionQuotaFooter
becomes a thin wrapper with identical props and behavior, so
CopilotQuotaFooter and the official Claude/Codex/Gemini paths are
untouched. This avoids duplicating ~280 lines of five-state rendering.
- Add CodexOauthQuotaFooter, a 38-line wrapper that calls the new
useCodexOauthQuota hook and forwards to SubscriptionQuotaView.
- ProviderCard inserts an isCodexOauth branch between isCopilot and
isOfficial, keyed off PROVIDER_TYPES.CODEX_OAUTH (newly added to
config/constants.ts to centralize the previously scattered string).
- Frontend hook caches per (codex_oauth, accountId) so multiple cards
bound to the same ChatGPT account share one fetch via react-query
dedup; cards bound to different accounts get independent fetches.
- No new i18n keys: existing subscription.fiveHour / sevenDay / expired /
refresh / queryFailed / expiredHint are reused.
Adds a new managed OAuth provider that lets Claude Code route requests
through a user's ChatGPT Plus/Pro subscription via the chatgpt.com
backend-api/codex endpoint.
- CodexOAuthManager: OpenAI Device Code flow with multi-account support,
JWT-based account identification, and automatic access_token refresh.
- Reuses the generic managed-auth command surface (auth_start_login,
auth_poll_for_account, etc.) via provider dispatch in commands/auth.rs.
- ClaudeAdapter detects codex_oauth providers, forces the base URL to
the ChatGPT backend, pins api_format to openai_responses, and emits
Authorization + originator headers; the forwarder injects the dynamic
access_token and ChatGPT-Account-Id per request.
- transform_responses gains an is_codex_oauth path that aligns the body
with OpenAI's codex-rs ResponsesApiRequest contract: sets store:false,
appends reasoning.encrypted_content to include, strips max_output_tokens
/ temperature / top_p, injects default instructions/tools/parallel_tool_calls,
and forces stream:true. Covered by 9 new unit tests plus regression
guards for the non-Codex path.
- Stream check reuses the same transform flag so detection matches the
production request shape.
- Frontend adds CodexOAuthSection + useCodexOauth hook, integrates it
into ClaudeFormFields / ProviderForm / AuthCenterPanel, ships a new
"Codex (ChatGPT Plus/Pro)" preset, and adds zh/en/ja i18n strings.
Copilot usage query API was implemented but never surfaced on the main
provider list. Add CopilotQuotaFooter component that auto-detects
github_copilot providers and displays premium interaction utilization
inline, reusing the existing TierBadge UI from SubscriptionQuotaFooter.
Session logs use placeholder provider_ids (_session, _codex_session,
_gemini_session) that don't exist in the providers table, causing LEFT
JOIN to return NULL and display "Unknown". Add COALESCE fallback in all
4 usage queries to show meaningful names like "Claude (Session)".
Add dashboard-level app type filter to usage statistics, replacing the
DataSourceBar with a more useful segmented control. All components
(summary cards, trend chart, provider stats, model stats, request logs)
now respond to the selected app filter.
Backend: add optional app_type parameter to get_usage_summary,
get_daily_trends, get_provider_stats, and get_model_stats queries.
Frontend: new AppTypeFilter type, updated query keys with appType
dimension for proper cache separation, and RequestLogTable local
filter auto-locks when dashboard filter is active.
- Use UPSERT with WHERE guard instead of INSERT OR IGNORE, so updated
token values on existing messages are properly synced without
unnecessary rewrites of unchanged rows
- Include cached tokens in the skip-zero filter to stop silently
discarding pure cache-hit records
- Restrict file collection to session-*.json to match documented scope
and prevent ingesting non-session JSON files
Parse ~/.gemini/tmp/*/chats/session-*.json for precise per-message
token data (input/output/cached/thoughts). Integrates with existing
background sync and manual sync button alongside Claude and Codex.
Normalize model names from JSONL session logs before storage and pricing
lookup: lowercase, strip provider prefix (openai/), strip date suffixes
(-YYYY-MM-DD, -YYYYMMDD). Also clamp cached tokens to not exceed input.
- Fix 13 Chinese model prices that were stored as CNY values in USD
fields (DeepSeek, Kimi, MiniMax, GLM, Doubao, Mimo)
- Add 12 new models: GPT-5.4/mini/nano, o3, o4-mini, GPT-4.1/mini/nano,
Gemini 3.1 Pro/Flash Lite, Gemini 2.5 Flash Lite, Gemini 2.0 Flash,
DeepSeek Chat/Reasoner, Kimi K2.5
- Merge pricing migration into existing v7→v8 to avoid extra version bump
Parse Claude Code JSONL session files (~/.claude/projects/) and Codex
SQLite database (~/.codex/state_5.sqlite) to track API usage without
requiring proxy interception. This enables usage statistics for users
who don't use the proxy feature.
Key changes:
- Add session_usage.rs: incremental JSONL parser with message.id dedup
- Add session_usage_codex.rs: import thread-level token data from Codex
- Add data_source column to proxy_request_logs (proxy/session_log/codex_db)
- Add session_log_sync table for tracking parse offsets
- Background sync every 60s + manual sync via DataSourceBar UI
- Schema migration v7→v8
- i18n support for zh/en/ja
- Hide "暂无描述" text when skill has no description (skills.sh API
doesn't return descriptions), show empty spacer instead
- Change skills.sh result link from guessed subdirectory path to repo
root URL, since skillId doesn't reflect the actual nested path
Add skills.sh API integration allowing users to search and install from
a catalog of 91K+ agent skills directly within CC Switch. The search
results are converted to DiscoverableSkill objects and reuse the existing
install pipeline. Includes fallback directory search for repos where
skills are nested in subdirectories, and filters out non-GitHub sources.
Allow users to choose between storing skills in CC Switch's managed
directory (~/.cc-switch/skills/) or the Agent Skills open standard
directory (~/.agents/skills/). Includes migration logic that safely
moves files before updating settings, with confirmation dialog for
non-empty installations.
- Add content_hash and updated_at fields to skills table (DB migration v6→v7)
- Compute directory content hash on install/import/restore for version tracking
- Add check_updates command: downloads repos, compares hashes, returns update list
- Add update_skill command: backs up old files, re-downloads and replaces SSOT
- Backfill content_hash for existing skills on first update check
- Add "Check Updates" button and per-skill update badge/button in UnifiedSkillsPanel
- Add i18n keys for zh/en/ja
- Change default autoQueryInterval from 0 (disabled) to 5 minutes for
new usage scripts (Token Plan, Balance, and general templates)
- Fix controlled number inputs (timeout & interval) that couldn't be
cleared: defer validation to onBlur so users can delete and retype
Test and ConfigureUsage buttons are now always rendered instead of
conditionally, with a disabled style for providers that don't support
them (e.g. official subscriptions). This ensures consistent button
container width so the usage display aligns uniformly across all cards.
Add a new "Official" (官方) template type in the usage query panel that
queries account balance via each provider's native API endpoint.
Follows the same zero-script pattern as Token Plan — Rust handles the
HTTP call, frontend auto-detects the provider from base URL.
Supported providers and endpoints:
- DeepSeek: GET /user/balance
- StepFun: GET /v1/accounts
- SiliconFlow: GET /v1/user/info (cn + com)
- OpenRouter: GET /api/v1/credits
- Novita AI: GET /v3/user/balance
* fix: handle UTF-8 multi-byte characters split across stream chunk boundaries
Replace String::from_utf8_lossy with append_utf8_safe in all four SSE
streaming paths. When a multi-byte UTF-8 character (e.g. Chinese, emoji)
is split across TCP chunk boundaries, from_utf8_lossy silently replaces
the incomplete halves with U+FFFD (�). This caused intermittent garbled
output in Claude Code when using the Copilot reverse proxy, because the
format conversion streams reconstruct SSE events from the corrupted buffer.
The new append_utf8_safe function preserves incomplete trailing bytes in
a remainder buffer and merges them with the next chunk before decoding,
ensuring characters are never split during UTF-8 conversion.
Fixes: intermittent U+FFFD replacement characters in Claude Code output
via Copilot proxy (not reproducible with direct Copilot connections like
opencode because they pass through raw bytes without format conversion).
* style: fix cargo fmt formatting in UTF-8 boundary tests
---------
Co-authored-by: Cod1ng <codingts@gmail.com>
Co-authored-by: encodets <encodets@gmail.com>
Some OpenAI-compatible chat providers reject requests when Claude-side\nsystem fragments arrive as multiple system messages. Normalize the\nconverted OpenAI chat payload so system content becomes a single\nleading system message while leaving the rest of the message stream\nunchanged.\n\nConstraint: Nvidia/Qwen-style chat completions require a single leading system prompt\nRejected: Reorder system messages only | still leaves fragmented system prompts for strict backends\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep OpenAI chat system prompts normalized unless a provider explicitly requires fragmented system messages\nTested: cargo test proxy::providers::transform --manifest-path src-tauri/Cargo.toml\nNot-tested: Full end-to-end proxy capture against Nvidia upstream in this session\nRelated: #1881
- Add gemini_native to ClaudeApiFormat type and ProviderMeta.apiFormat
- Add "Gemini Native" provider preset with default Google AI endpoints
- Show Gemini-specific endpoint hints and full-URL mode guidance
- Add gemini_native option to API format selector in ClaudeFormFields
- Add i18n strings for zh/en/ja
Integrate gemini_native api_format throughout the proxy pipeline:
- ClaudeAdapter: detect Gemini provider type, Google/GoogleOAuth auth
strategies, and suppress Anthropic-specific headers for Gemini targets
- Forwarder: Gemini URL resolution, shadow store threading, endpoint
rewriting to models/*:generateContent with stream/non-stream variants
- Handlers: route Gemini streaming through streaming_gemini adapter and
non-streaming through transform_gemini converter
- Server/State: add GeminiShadowStore to shared ProxyState
- StreamCheck: support gemini_native health check with proper auth headers
Introduce gemini_url module that normalizes legacy Gemini/OpenAI-compatible
base URLs into canonical models/*:generateContent endpoints. Supports both
structured Gemini URLs (auto-normalized) and opaque relay URLs (pass-through
with query params only).
Replace inline `buffer.find("\n\n")` SSE splitting logic across streaming,
streaming_responses, response_handler, and response_processor with a shared
`take_sse_block` function that handles both `\n\n` and `\r\n\r\n` delimiters.
The function is only called from read_gemini_credentials_from_keychain
which is already macOS-only. Without the gate, non-macOS CI fails with
dead-code error due to -D warnings.
usage_count is remaining quota (starts at total, decreases to 0),
not used count. Invert calculation so all providers consistently
show 0% when fresh and 100% when exhausted.
Add a new "Token Plan" template type in the usage query panel that
natively queries quota/usage from Chinese coding plan providers
(Kimi For Coding, Zhipu GLM, MiniMax) without requiring custom scripts.
- Rust backend: new coding_plan service with provider-specific API
queries (Kimi /v1/usages, Zhipu /api/monitor/usage/quota/limit,
MiniMax /coding_plan/remains) normalized into UsageResult
- Frontend: Token Plan template in UsageScriptModal with auto-detection
of provider based on ANTHROPIC_BASE_URL pattern matching
- Follows the same pattern as GitHub Copilot template (dedicated API
path in queryProviderUsage, no JS script needed)
Remove the hard block that prevented switching to providers requiring
proxy (OpenAI format, Copilot, full URL mode) when the proxy is not
running. Now the switch proceeds with a warning toast. Also deduplicate
the proxy hint info toast so it doesn't appear alongside the warning.
Re-enable GitHub Copilot provider preset and the OAuth auth center tab
that were temporarily hidden due to abnormal consumption rates. The
Copilot optimizer introduced in the previous commit addresses the
underlying issue.
Implement request classification, tool result merging, compact detection,
deterministic request IDs, and warmup downgrade for Copilot proxy.
The root cause was x-initiator being hardcoded to "user", making Copilot
count every API request (including tool callbacks and agent continuations)
as a separate premium interaction. The optimizer dynamically classifies
requests as "user" or "agent" based on message content analysis.
Closes#1813
Official providers use built-in subscription quota display instead of
custom usage scripts, and stream check is not applicable. Hide both
action buttons when isOfficialProvider is true.
- Read Gemini OAuth credentials from macOS Keychain (gemini-cli-oauth)
or legacy file (~/.gemini/oauth_creds.json)
- Auto-refresh expired access tokens using refresh_token (Google OAuth
tokens expire in ~1h, unlike Claude/Codex)
- Two-step API: loadCodeAssist for project ID, then retrieveUserQuota
for per-model quota buckets
- Classify models into Pro/Flash/Flash Lite categories, show min
remaining fraction as utilization percentage
- Extend isOfficialProvider() for Gemini (no API key + no base URL)
- Parameterize expiredHint i18n key with tool name for all three apps
Read Codex OAuth credentials from ~/.codex/auth.json (with macOS
Keychain fallback) and query chatgpt.com/backend-api/wham/usage to
show rate limit utilization on official Codex provider cards. Reuses
the same tier naming (five_hour, seven_day) for frontend i18n compat.
Read Claude OAuth credentials from macOS Keychain (with file fallback)
and query the Anthropic usage API to show quota utilization inline on
official provider cards. Includes compact countdown timer for reset
windows and hides the rarely-used seven_day_sonnet tier in inline mode.
Each app type (Claude/Codex/Gemini) now renders as a submenu instead
of flat items, keeping the top-level tray menu compact regardless of
provider count. The submenu label shows the current provider name
(e.g. "Claude · OpenRouter") for at-a-glance visibility.
Distinguish between missing API key, missing endpoint, auth failure,
unsupported provider (404/405), and timeout errors instead of showing
a generic failure toast for all cases.
Add ability to fetch available models from third-party aggregation
providers (SiliconFlow, OpenRouter, etc.) via OpenAI-compatible
GET /v1/models endpoint. Users can click "Fetch Models" button in
the provider form, then select models from a dropdown on each
model input field.
- Backend: new model_fetch service + Tauri command (Rust)
- Frontend: ModelInputWithFetch shared component
- Integrated into all 5 app forms (Claude/Codex/Gemini/OpenCode/OpenClaw)
- i18n support for zh/en/ja
* fix(copilot): 修复 GitHub Copilot 400 认证错误
问题:使用 GitHub Copilot provider 时报错 400 bad request
根因:与 copilot-api 项目对比发现多处差异
修复内容:
- 更新版本号 0.26.7 到 0.38.2
- 更新 API 版本 2025-04-01 到 2025-10-01
- 添加缺失的关键 headers
- 修正 openai-intent 值
- 添加动态 API endpoint 支持
- 同步更新 stream_check.rs headers
Closes#1777
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: flush stream after write_all in hyper_client proxy
Add explicit flush() calls after write_all() for TLS stream, plain TCP
stream, and CONNECT tunnel requests to ensure buffered data is sent
immediately, preventing connection hangs in Copilot auth header flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* 修复登录时的剪切板在mac与linux端可能没复制验证码
* fix: flush stream after write_all in hyper_client proxy
Add explicit flush() calls after write_all() for TLS stream, plain TCP
stream, and CONNECT tunnel requests to ensure buffered data is sent
immediately, preventing connection hangs in Copilot auth header flow.
* 修复登录时的剪切板在mac与linux端可能没复制验证码
* 1、修复不同类型的个人商业等不同类型的copilot账号问题
2、将验证码复制改为异步操作
* fix: address PR review comments for Copilot auth │
│ │
│ - Fix clipboard blocking by using spawn_blocking for arboard ops │
│ - Implement dynamic endpoint routing for enterprise Copilot users │
│ - Add api_endpoints cache cleanup in remove_account() and clear_auth() │
│ - Change API endpoint log level from info to debug │
│ - Fix clear_auth() to continue cleanup even if file deletion fails │
│ - Add 9 unit tests for Copilot detection and api_endpoints cachin
* style: fix cargo fmt formatting
* Fix Copilot dynamic endpoint handling
* fix: restore clear_auth() memory-first cleanup order and fix cache leaks
- Restore clear_auth() to clean memory state before deleting the storage
file. The previous order (file deletion first) caused a regression where
users could get stuck in a "cannot log out" state if file removal failed.
- Add missing copilot_models.clear() in clear_auth() — this cache was
cleaned in remove_account() but never in the full clear path.
- Add endpoint_locks cleanup in both remove_account() and clear_auth()
to prevent minor in-process memory leaks.
- Update test to assert the correct behavior: memory should be cleaned
even when file deletion fails.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: 周梦泽 <mengze.zhou@dafeng-tech.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
- Mark issues as stale after 60 days of inactivity
- Auto-close after 14 more days without response
- Bilingual (zh/en) stale and close messages
- Exempt security and performance labeled issues
- Runs daily at UTC 00:00, processes up to 100 issues per run
- Only affects issues, not pull requests
- Fix JA README macOS FAQ still claiming app is unsigned (now code-signed & notarized)
- Update SessionManager description from "Claude Code only" to "all supported apps" (EN/ZH/JA)
- Replace non-existent Flatpak download entry with self-build reference (EN/ZH/JA)
- Add OpenCode and OpenClaw filesystem paths to Flatpak minimal permissions
- Bump user manual version to v3.12.3
- Use get_home_dir() instead of dirs::home_dir() in get_opencode_dir()
and get_openclaw_dir() to respect CC_SWITCH_TEST_HOME override
- Add CC_SWITCH_TEST_HOME to all TempHome implementations
- Add #[serial] to all with_test_home tests to share serialization
with other env-mutating tests
- Remove --test-threads=1 workaround from CI
Users reported that Copilot support causes excessively fast token
consumption. Temporarily hide the feature by adding a `hidden` field
to ProviderPreset interface and commenting out the auth center tab
in settings. Existing Copilot providers in DB still work via proxy.
Add three community health files with bilingual (EN/ZH) support:
- CODE_OF_CONDUCT.md: Contributor Covenant v2.1 with official Chinese translation
- SECURITY.md: security policy pointing to GitHub Security Advisories
- CONTRIBUTING.md: contribution guide with dev setup, code style, PR guidelines,
i18n rules, and AI-assisted contribution policy
Add GitHub issue templates (bug report, feature request, documentation
issue, question) and PR template. All templates use bilingual format
(English + Chinese) to support the international community.
Keep Claude's live settings aligned with the latest provider state while proxy takeover is active, without breaking takeover fields or restore behavior.
Co-authored-by: Jason <farion1231@gmail.com>
* feat(provider): support additive provider key lifecycle management
Add `addToLive` parameter to add_provider so callers can opt out of
writing to the live config (e.g. when duplicating an inactive provider).
Add `originalId` parameter to update_provider to support provider key
renames — the old key is removed from live config before the new one
is written.
Frontend: ProviderForm now exposes provider-key input for openclaw app
type, and EditProviderDialog forwards originalId on save. Deep-link
import passes addToLive=true to preserve existing behavior.
* test(provider): add integration tests for additive provider key flows
Cover openclaw provider duplication scenario to verify that a generated
provider key is assigned automatically. Add MSW handlers for
get_openclaw_live_provider_ids, get_openclaw_default_model,
scan_openclaw_config_health, and check_env_conflicts endpoints.
Update EditProviderDialog mock to pass originalId alongside provider.
* fix(openclaw): replace json-five serializer to prevent panic on empty collections
json-five 0.3.1 panics when pretty-printing nested empty maps/arrays.
Switch value_to_rt_value() to serde_json::to_string_pretty() which
produces valid JSON5 output without the panic. Add regression test for
removing the last provider (empty providers map).
* style: apply rustfmt formatting to proxy and provider modules
Reformat chained .header() calls in ClaudeAdapter and StreamCheckService
for consistent alignment. Reorder imports alphabetically in stream_check.
Fix trailing whitespace in transform.rs and merge import lines in
provider/mod.rs.
* style: fix clippy warnings in live.rs and tray.rs
* refactor(provider): simplify live_config_managed and deduplicate tolerant live config checks
- Change live_config_managed from Option<bool> to bool with #[serde(default)]
- Extract repeated tolerant live config query into check_live_config_exists helper
- Fix duplicate key generation to also check live-only provider IDs
- Fix updateProvider test to match new { provider, originalId } call signature
- Add streaming_responses test type annotation for compiler inference
* fix(provider): distinguish legacy providers from db-only when tolerating live config errors
Change `ProviderMeta.live_config_managed` from `bool` to `Option<bool>`
to introduce a three-state semantic:
- `Some(true)`: provider has been written to live config
- `Some(false)`: explicitly db-only, never written to live config
- `None`: legacy data or unknown state (pre-existing providers)
Previously, legacy providers defaulted to `live_config_managed = false`
via `#[serde(default)]`, which silently swallowed live config parse
errors. This could mask genuine configuration issues for providers that
had actually been synced to live config before the field was introduced.
Now, only providers with an explicit `Some(false)` marker tolerate parse
errors; legacy `None` providers surface errors as before, preserving
safety for already-managed configurations.
Also wrap the `ensureQueryData` call for live provider IDs during
duplication in a try/catch so that a malformed config file shows a
user-facing toast instead of silently failing.
Add tests for both the legacy error propagation path and the frontend
duplication failure scenario.
* refactor(provider): unify OMO variant updates with atomic file-then-db writes and rollback
Consolidate the duplicated omo/omo-slim update branches into a single
match on the variant. Write the OMO config file from the in-memory
provider state *before* persisting to the database, so a file-write or
plugin-sync failure leaves the database unchanged. If `add_plugin`
fails after the config file is already written, roll back to the
previous on-disk contents via snapshot/restore.
Also:
- `sync_all_providers_to_live` now skips db-only providers
(`live_config_managed == Some(false)`) instead of attempting to write
them to live config.
- `import_{opencode,openclaw}_providers_from_live` mark imported
providers as `live_config_managed: Some(true)` so they are correctly
recognized during subsequent syncs.
- Extract OmoService helpers: `profile_data_from_provider`,
`snapshot_config_file`, `restore_config_file`, `write_profile_config`,
and the new public `write_provider_config_to_file`.
- Add 9 new tests covering sync skip, legacy restore, import marking,
OMO persistence, file-write failure, and plugin-sync rollback.
* fix(provider): fix additive provider delete/switch regressions and redundancy
- fix(delete): replace stale live_config_managed flag check with
check_live_config_exists so providers written to live before the
flag-flip logic was introduced are still cleaned up on delete
- fix(switch): make write_live_with_common_config return Err instead of
silently returning Ok when config structure is invalid, preventing
live_config_managed from being incorrectly flipped to true
- fix(update): block provider key rename for OMO/OMO Slim categories to
prevent orphaned current-state markers breaking OMO file syncs
- fix(switch): flip live_config_managed to true after successful live
write for DB-only additive providers so sync_all_providers_to_live
includes them on future syncs; roll back live write if DB update fails
- refactor(delete): merge symmetric OMO/OMO-Slim blocks into single
match-on-variant path; hoist DB read to top of additive branch
- refactor(remove_from_live_config): merge OMO/OMO-Slim if/else-if
into single match-on-variant path
- refactor(switch_normal): merge two OMO/OMO-Slim if blocks into one
OpenCode guard with (enable, disable) variant pair
- fix(update): remove redundant duplicate return Ok(true) after OMO
current-state write
* fix(test): use preferred_filename after OMO field rename
The merge from main brought in #1746 which renamed
OmoVariant.filename → preferred_filename, but the test helper
omo_config_path() was not updated, breaking compilation of all
new provider tests.
---------
Co-authored-by: Jason <farion1231@gmail.com>
Concurrent failover switches for the same app could cause is_current,
local settings, and Live backup to point at different providers.
- Add SwitchLockManager with per-app mutexes (different apps still parallel)
- Unify scattered switch logic into ProxyService::hot_switch_provider
- Fix TOCTOU in set_current_provider via mutate_settings
- Add logical_target_changed to skip redundant UI refreshes
- Add tests for serialization and restore-waits-for-switch scenarios
* fix(provider): show persistent config highlight for additive-mode providers
Closes https://github.com/farion1231/cc-switch/issues/1692
* fix(provider): limit persistent config highlight to opencode only
* Add directory picker before launching Claude terminal
* fix(terminal): preserve cwd path and strip Windows verbatim prefix
- Stop trimming non-empty paths so directories with leading/trailing
spaces on Unix are handled correctly
- Strip \\?\ extended-length prefix from canonicalized paths on Windows
to prevent batch script cd failures
* fix(terminal): restore UNC paths when stripping Windows verbatim prefix
Handle \\?\UNC\server\share form separately from regular \\?\ prefix,
converting it back to \\server\share so network/WSL directory paths
remain valid in batch cd commands.
* fix(terminal): use pushd for UNC paths in Windows batch launcher
`cmd.exe` cannot set a UNC path (e.g. `\\wsl$\...`) as the current
directory via `cd /d`; it errors with "CMD does not support UNC paths
as current directories". Switch to `pushd` which temporarily maps the
UNC share to a drive letter.
Rename `build_windows_cd_command` → `build_windows_cwd_command` to
reflect the broader semantics. Extract `build_windows_cwd_command_str`
and `is_windows_unc_path` helpers for testability, and add unit tests
covering drive paths, UNC paths, and batch metacharacter escaping.
Also fix minor style issues: sort mod declarations alphabetically,
add missing EOF newline in lightweight.rs, add explicit type annotation
in streaming_responses test, and reformat tray menu builder chain.
* style(frontend): reformat provider forms, constants and hooks
Apply prettier formatting across 5 frontend files. No logic changes.
Changed files:
- AddProviderDialog.tsx: reformat generic type annotation and callback
- ClaudeFormFields.tsx: consolidate multi-line useState and Collapsible props
- CodexConfigSections.tsx: expand single-line React imports to multi-line,
collapse removeCodexTopLevelField() call
- constants.ts: merge TemplateType into single line
- useSkills.ts: expand single-line TanStack Query imports to multi-line,
reformat uninstallSkill mutationFn chain
* deps(proxy): add hyper ecosystem crates and manual decompression libs
reqwest internally normalizes all header names to lowercase and does not
preserve insertion order, causing proxied requests to differ from the
original client requests. To achieve transparent header forwarding with
original casing and order, introduce lower-level hyper HTTP client libs.
New dependencies:
- hyper-util 0.1: TokioExecutor + legacy Client with
preserve_header_case support for HTTP/1.1
- hyper-rustls 0.27: rustls-based TLS connector for hyper
- http 1 / http-body 1 / http-body-util 0.1: HTTP type crates for
hyper 1.x request/response construction
- flate2 1: manual gzip/deflate decompression (replaces reqwest auto)
- brotli 7: manual brotli decompression
Changed dependencies:
- serde_json: enable preserve_order feature to keep JSON field order
- reqwest: drop gzip feature to prevent reqwest from overriding the
client's original accept-encoding header
* refactor(proxy): use hyper client for header-case preserving forwarding
Previously the proxy used reqwest for all upstream requests. reqwest
normalizes header names to lowercase and reorders them internally,
making proxied requests distinguishable from direct CLI requests.
Some upstream providers are sensitive to these differences.
This commit replaces reqwest with a hyper-based HTTP client on the
default (non-proxy) path, achieving wire-level header fidelity:
Server layer (server.rs):
- Replace axum::serve with a manual hyper HTTP/1.1 accept loop
- Enable preserve_header_case(true) so incoming header casing is
captured in a HeaderCaseMap extension on each request
- Bridge hyper requests to axum Router via tower::Service
New hyper client module (hyper_client.rs):
- Lazy-initialized hyper-util Client with preserve_header_case
- ProxyResponse enum wrapping both hyper::Response and reqwest::Response
behind a unified interface (status, headers, bytes, bytes_stream)
- send_request() builds requests with ordered HeaderMap + case map
Request handlers (handlers.rs):
- Switch from (HeaderMap, Json<Value>) extractors to raw
axum::extract::Request to preserve Extensions (containing the
HeaderCaseMap from the accept loop)
- Pass extensions through the forwarding chain
Forwarder (forwarder.rs):
- Remove HEADER_BLACKLIST array; replace with ordered header iteration
that preserves original header sequence and casing
- Build ordered_headers by iterating client headers, skipping only
auth/host/content-length, and inserting auth headers at the original
authorization position to maintain order
- Handle anthropic-beta (ensure claude-code-20250219 tag) and
anthropic-version (passthrough or default) inline during iteration
- Remove should_force_identity_encoding() — accept-encoding is now
transparently forwarded to upstream
- Use hyper client by default; fall back to reqwest only when an
HTTP/SOCKS5 proxy tunnel is configured
Provider adapters (adapter.rs, claude.rs, codex.rs, gemini.rs):
- Replace add_auth_headers(RequestBuilder) -> RequestBuilder with
get_auth_headers(AuthInfo) -> Vec<(HeaderName, HeaderValue)>
- Adapters now return header pairs instead of mutating a reqwest builder
- Claude adapter: merge Anthropic/ClaudeAuth/Bearer into single branch;
move Copilot fingerprint headers into get_auth_headers
Response processing (response_processor.rs):
- Add manual decompression (gzip/deflate/brotli via flate2 + brotli)
for non-streaming responses, since reqwest auto-decompression is now
disabled to allow accept-encoding passthrough
- Add compressed-SSE warning log for streaming responses
- Accept ProxyResponse instead of reqwest::Response
HTTP client (http_client.rs):
- Disable reqwest auto-decompression (.no_gzip/.no_brotli/.no_deflate)
on both global and per-provider clients
Streaming adapters (streaming.rs, streaming_responses.rs):
- Generalize stream error type from reqwest::Error to generic E: Error
Misc:
- log_codes.rs: add SRV-005 (ACCEPT_ERR) and SRV-006 (CONN_ERR)
- stream_check.rs: reformat copilot header lines
- transform.rs: fix trailing whitespace alignment
* fix(lint): resolve 35 clippy warnings across Rust codebase
Fix all clippy warnings reported by `cargo clippy --lib`:
- codex_config.rs: fix doc_overindented_list_items (3 spaces -> 2)
- commands/copilot.rs: inline format args in 2 log::error! calls
- commands/provider.rs: inline format args in 3 map_err closures
- proxy/hyper_client.rs: inline format arg in log::debug! call
- proxy/providers/copilot_auth.rs: inline format args in 16 locations
(log macros, format! in headers, error constructors)
- proxy/thinking_optimizer.rs: inline format args in 2 log::info! calls
- services/skill.rs: inline format args in log::debug! call
- services/webdav_sync.rs: inline format args in 6 format! calls
(version compat messages, download limit messages)
- services/webdav_sync/archive.rs: inline format args in 2 format! calls
- session_manager/providers/opencode.rs: inline format args in
source_path format!
All fixes use the clippy::uninlined_format_args suggestion pattern:
format!("msg: {}", var) -> format!("msg: {var}")
* deps(proxy): add raw HTTP write and native TLS cert dependencies
Add crates required for the raw TCP/TLS write path that bypasses
hyper's header encoder to preserve original header name casing:
- httparse: parse raw TCP peek bytes to capture header casings
- tokio-rustls + rustls: direct TLS connections for raw write path
- webpki-roots: Mozilla CA bundle baseline
- rustls-native-certs: load system keychain CAs (trusts proxy MITM
certificates from Clash, mitmproxy, etc.)
* fix(proxy): address code review feedback on response handling
Fixes from PR #1714 code review:
- Extract `read_decoded_body()` and `strip_entity_headers_for_rebuilt_body()`
in response_processor to properly clean content-encoding/content-length
headers after decompression
- Reuse `read_decoded_body()` in handlers.rs for Claude transform path,
ensuring compressed responses are decoded before format conversion
- Make `build_proxy_url_from_config()` public so forwarder can pass proxy
URL to the hyper raw write path
- Add `has_system_proxy_env()` utility with test coverage
- Add 50ms backoff after accept() failures in server.rs to prevent
tight-loop CPU spin on transient socket errors
* feat(proxy): implement raw TCP/TLS write with HTTP CONNECT tunnel
Rewrite hyper_client with a two-tier strategy for header case preservation:
Primary path (raw write):
- Peek raw TCP bytes in server.rs to capture OriginalHeaderCases before
hyper lowercases them
- Build raw HTTP/1.1 request bytes with exact original header name casing
- Write directly to TLS stream, then use WriteFilter to let hyper parse
the response while discarding its duplicate request writes
- Support HTTP CONNECT tunneling through upstream proxies, so header case
is preserved even when a proxy (Clash, V2Ray) is configured
Fallback path (hyper-util Client):
- Used when OriginalHeaderCases is empty or raw write fails
- Configured with title_case_headers(true) for best-effort casing
TLS improvements:
- Load native system certificates alongside webpki roots so proxy MITM
CAs (installed in system keychain) are trusted through CONNECT tunnels
Key types added:
- OriginalHeaderCases: maps lowercase name → original wire-casing bytes
- WriteFilter<S>: AsyncRead+AsyncWrite wrapper that discards writes
- connect_via_proxy(): HTTP CONNECT tunnel establishment
- ExtensionDebugMarker: diagnostic marker for extension chain debugging
* refactor(proxy): route requests through hyper with proxy-aware forwarding
Rework forwarder request dispatch to always prefer the hyper raw write
path (header case preservation) over reqwest:
Request routing:
- HTTP/HTTPS proxy: hyper raw write through CONNECT tunnel (case preserved)
- SOCKS5 proxy: reqwest fallback (CONNECT not supported for SOCKS5)
- No proxy: hyper raw write direct connection
Header handling improvements:
- Replace host header in-place at original position instead of
skip-and-append, preserving client's header ordering
- Preserve client's original accept-encoding for transparent passthrough;
only force identity encoding when transform path needs decompression
- Add should_force_identity_encoding() to centralize the decision
- Remove hardcoded 'br, gzip, deflate' override that masked client values
Proxy URL resolution (priority order):
1. Provider-specific proxy config (if enabled)
2. Global proxy URL configured in CC Switch
3. Direct connection (no proxy)
* chore(proxy): remove dead code, redundant tests and debug scaffolding
- Inline should_force_identity_encoding() (was just `needs_transform`)
and delete its 5 test cases
- Remove ExtensionDebugMarker diagnostic type
- Remove unused has_system_proxy_env() and its test
- Remove strip_entity_headers test
- Simplify hyper path: remove redundant is_socks_proxy ternary
- Update hyper_client module doc to reflect CONNECT tunnel support
* fix(proxy): block direct-connect fallback and complete CONNECT tunnel support
* feat(hooks): improve proxy requirement warnings with specific reasons
- Remove redundant OpenAI format hint toast messages
- Add detailed reason detection for proxy requirements (OpenAI Chat, OpenAI Responses, full URL mode)
- Update i18n files with new reason-specific keys
* style(*): format code with prettier
- Remove extra whitespace in http_client.rs
- Fix formatting issues in useProviderActions.ts
* fix(proxy): post-merge fixes for forward return type and clippy warnings
- Restore forward() return type to (ProxyResponse, Option<String>)
to pass claude_api_format through to callers
- Inline format args in log::warn! macro (clippy::uninlined_format_args)
- Suppress too_many_arguments for check_claude_stream
* refactor(proxy): preserve original header wire order and add non-streaming body timeout
- Rewrite build_raw_request to emit headers in original
client-sent sequence instead of hash-map order
- Remove unused OriginalHeaderCases::get_all method
- Add body_timeout to read_decoded_body to prevent
requests hanging when upstream stalls after headers
* fix: route copilot claude openai models to responses
* fix(i18n): add copilotProxyHint translation key for all locales
The copilotProxyHint message was using inline defaultValue with Chinese
text, which would show Chinese to English and Japanese users. Added
proper translation keys in zh/en/ja locale files and removed the
hardcoded defaultValue fallback.
---------
Co-authored-by: Jason <farion1231@gmail.com>
* feat(proxy): add full URL mode and refactor endpoint rewriting
- Add `isFullUrl` provider meta to treat base_url as complete API endpoint
- Remove hardcoded `?beta=true` from Claude adapter, pass through from client
- Refactor forwarder endpoint rewriting with proper query string handling
- Block provider switching when proxy is required but not running
- Add full URL toggle UI in endpoint field with i18n (zh/en/ja)
* refactor(proxy): remove beta query handling
* fix(proxy): strip beta query when rewriting Claude endpoints
* feat(codex): complete full URL support
* refactor(ui): refine full URL endpoint hint
Add StepFun Step Plan (阶跃星辰编程计划) as an OpenCode provider preset.
StepFun Step Plan is a subscription-based coding AI service that uses a
dedicated API endpoint separate from the standard StepFun provider.
- Base URL: https://api.stepfun.com/step_plan/v1
- Model: step-3.5-flash (196B MoE, optimized for agent and coding tasks)
- Category: cn_official
- Supports tool_call, reasoning, temperature control
Ref: https://platform.stepfun.com/docs/zh/step-plan/overview
Made-with: Cursor
Co-authored-by: sky-wang-salvation <sky-wang-salvation@users.noreply.github.com>
Add risk disclaimer section in all three languages (EN/ZH/JA) warning
users about potential GitHub ToS violations, account suspension risks,
and no long-term availability guarantee for the Copilot reverse proxy.
Tauri's built-in DMG styling relies on AppleScript/Finder access which
silently fails on CI (tauri-apps/tauri#1731). Switch to create-dmg tool
which works on GitHub Actions macOS runners.
- Replace Tauri DMG with create-dmg: background image, icon positions,
app-drop-link, codesign, hide-extension
- Regenerate background image at 2x Retina resolution (1320x800)
- Revert tauri.conf.json dmg config (ineffective on CI)
- Reorder steps: Prepare → Notarize DMG → Verify
- Notarize and Verify now use release-assets/ path for DMG
- Add DMG background image with drag-to-install arrow guide
- Configure window size (660x400), app and Applications icon positions
- Center icons horizontally with visual arrow between them
Tauri only notarizes the .app bundle, not the DMG container. This caused
stapler staple to fail with "Record not found" for the DMG.
- Add "Notarize macOS DMG" step using xcrun notarytool with retry logic
- Add retry logic (3 attempts) to macOS build step for transient network failures
- Add hdiutil verify before DMG notarization submission
- Import Developer ID Application certificate into temporary keychain
- Inject APPLE_SIGNING_IDENTITY/APPLE_ID/APPLE_PASSWORD/APPLE_TEAM_ID
into Tauri build step for automatic signing and notarization
- Staple notarization tickets to both .app and .dmg (hard-fail)
- Add verification step: codesign --verify + spctl -a + stapler validate
for both .app and .dmg, gating the release on success
- Collect .dmg alongside .tar.gz and .zip in release assets
- Clean up temporary keychain with original default restored
- Update release notes to recommend .dmg and note Apple notarization
- Remove all xattr workarounds and "unidentified developer" warnings
from README, README_ZH, installation guides, and FAQ (EN/ZH/JA)
Two components (ProviderList, UsageScriptModal) directly spread the full
settings object from the query into settingsApi.save(), which includes
webdavSync with an empty password (cleared by get_settings_for_frontend
for security). The backend merge_settings_for_save only preserved
existing WebDAV config when the incoming field was None, not when it was
present with an empty password.
Frontend fix: strip webdavSync before saving in both components, matching
the pattern already used by useSettings hook.
Backend defense-in-depth: merge_settings_for_save now backfills the
existing password when the incoming one is empty, preventing future
regressions from similar oversights.
Replace map_thinking_to_reasoning_effort() with resolve_reasoning_effort()
that uses a two-tier priority system:
1. Explicit output_config.effort: low/medium/high map 1:1, max → xhigh
2. Fallback: thinking.type + budget_tokens thresholds (<4k → low,
4k-16k → medium, ≥16k → high, adaptive → high)
Both Chat Completions and Responses API paths share the same helper,
ensuring consistent mapping across all OpenAI-compatible endpoints.
Claude Opus 4.6 and Sonnet 4.6 1M context window is now GA and no
longer requires a beta header. Update contextWindow from 200k to 1M
for all OpenClaw/OpenCode presets (27 entries in OpenClaw, 1 in
OpenCode Bedrock). Also add claude-sonnet-4-6 model pricing seed.
- Remove AuthCenterPanel import and OAuth TabsContent
- Narrow activeTab type from three values to "app-specific" | "universal"
- Simplify footer by removing oauth branch, reducing to two-way conditional
- Change TabsList from grid-cols-3 to grid-cols-2
- OAuth authentication remains available in settings page and CopilotAuthSection
- Make header constants in copilot_auth.rs public, add COPILOT_INTEGRATION_ID
- Unify User-Agent across 4 internal methods (eliminate "CC-Switch" leakage) and version string
- claude.rs add_auth_headers now references shared constants, adds user-agent / api-version / openai-intent
- forwarder.rs filters all 6 fixed fingerprint headers for Copilot requests to prevent reqwest append duplication
- stream_check.rs health check pipeline aligned with new fingerprint
* refactor(toolsearch): replace binary patch with ENABLE_TOOL_SEARCH env var toggle
- Remove toolsearch_patch.rs binary patching mechanism (~590 lines)
- Delete `toolsearch_patch.rs` and `commands/toolsearch.rs`
- Remove auto-patch startup logic and command registration from lib.rs
- Remove `tool_search_bypass` field from settings.rs
- Remove frontend settings ToggleRow, useSettings hook sync logic, and API methods
- Clean up zh/en/ja i18n keys (notifications + settings)
- Add ENABLE_TOOL_SEARCH toggle to Claude provider form
- Add checkbox in CommonConfigEditor.tsx (alongside teammates toggle)
- When enabled, writes `"env": { "ENABLE_TOOL_SEARCH": "true" }`
- When disabled, removes the key; takes effect on provider switch
- Add zh/en/ja i18n key: `claudeConfig.enableToolSearch`
Claude Code 2.1.76+ natively supports this env var, eliminating the need for binary patching.
* feat(claude): add effortLevel high toggle to provider form
- Add "high-effort thinking" checkbox to Claude provider config form
- When checked, writes `"effortLevel": "high"`; when unchecked, removes the field
- Add zh/en/ja i18n translations
* refactor(claude): remove deprecated alwaysThinking toggle
- Claude Code now enables extended thinking by default; alwaysThinkingEnabled is a no-op
- Thinking control is now handled via effortLevel (added in prior commit)
- Remove state, switch case, and checkbox UI from CommonConfigEditor
- Clean up alwaysThinking i18n keys across zh/en/ja locales
* feat(opencode): add setCacheKey: true to all provider presets
- Add setCacheKey: true to options in all 33 regular presets
- Add setCacheKey: true to OPENCODE_DEFAULT_CONFIG for custom providers
- Exclude 2 OMO presets (Oh My OpenCode / Slim) which have their own config mechanism
Closes#1523
* fix(codex): resolve 1M context window toggle causing MCP editor flicker
- Add localValueRef to short-circuit duplicate CodeMirror updateListener callbacks,
breaking the React state → CodeMirror → stale onChange → React state feedback loop
- Use localValueRef.current in handleContextWindowToggle and handleCompactLimitChange
to avoid stale closure reads
- Change compact limit input from type="number" to type="text" with inputMode="numeric"
to remove unnecessary spinner buttons
* feat(codex): add 1M context window toggle utilities and i18n keys
- Add extractCodexTopLevelInt, setCodexTopLevelInt, removeCodexTopLevelField
TOML helpers in providerConfigUtils.ts
- Add i18n keys for contextWindow1M, autoCompactLimit in zh/en/ja locales
* feat(claude): collapse model mapping fields by default
- Wrap 5 model mapping inputs in a Collapsible, collapsed by default
- Auto-expand when any model value is present (including preset-filled)
- Show hint text when collapsed explaining most users need no config
- Add zh/en/ja i18n keys for toggle label and collapsed hint
- Use variant={null} to avoid ghost button hover style clash in dark mode
* feat(claude): merge advanced fields into single collapsible section
- Merge API format, auth field, and model mapping into a unified "Advanced Options" collapsible
- Extend smart-expand logic to detect non-default values across all advanced fields
- Preserve model mapping sub-header and hint with a separator line
- Update zh/en/ja i18n keys (advancedOptionsToggle, advancedOptionsHint, modelMappingLabel, modelMappingHint)
* feat(copilot): add GitHub Copilot reverse proxy support
Add GitHub Copilot as a Claude provider variant with OAuth device code
authentication and Anthropic ↔ OpenAI format transformation.
Backend:
- Add CopilotAuthManager for GitHub OAuth device code flow
- Implement Copilot token auto-refresh (60s before expiry)
- Persist GitHub token to ~/.cc-switch/copilot_auth.json
- Add ProviderType::GitHubCopilot and AuthStrategy::GitHubCopilot
- Modify forwarder to use /chat/completions for Copilot
- Add Copilot-specific headers (Editor-Version, Editor-Plugin-Version)
Frontend:
- Add CopilotAuthSection component for OAuth UI
- Add useCopilotAuth hook for OAuth state management
- Auto-copy user code to clipboard and open browser
- Use 8-second polling interval to avoid GitHub rate limits
- Skip API Key validation for Copilot providers
- Add GitHub Copilot preset with claude-sonnet-4 model
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* fix(copilot): remove is_expired() calls from tests
Remove references to deleted is_expired() method in test code.
Only is_expiring_soon() is needed for token refresh logic.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* feat(copilot): add real-time model listing from Copilot API
- Add fetch_models() to CopilotAuthManager calling GET /models endpoint
- Add copilot_get_models Tauri command
- Add copilotGetModels() frontend API wrapper
- Modify ClaudeFormFields to show model dropdown for Copilot providers
- Fetches available models on component mount when isCopilotPreset
- Groups models by vendor (Anthropic, OpenAI, Google, etc.)
- Input + dropdown button combo allows both manual entry and selection
- Non-Copilot providers keep original plain Input behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(copilot): add usage query integration
- Add Copilot usage API integration (fetch_usage method)
- Add copilot_get_usage Tauri command
- Add GitHub Copilot template in usage query modal
- Unify naming: copilot → github_copilot
- Add constants management (TEMPLATE_TYPES, PROVIDER_TYPES)
- Improve error handling with detailed error messages
- Add database migration (v5 → v6) for template type update
- Add i18n translations (zh, en, ja)
- Improve type safety with TemplateType
- Apply code formatting (cargo fmt, prettier)
* 修复github 登录和注销问题 ,模型选择问题
* feat(copilot): add multi-account support for GitHub Copilot
- Add multi-account storage structure with v1 to v2 migration
- Add per-account token caching and auto-refresh
- Add new Tauri commands for account management
- Integrate account selection in Proxy forwarder
- Add account selection UI in CopilotAuthSection
- Save githubAccountId to ProviderMeta
- Add i18n translations for multi-account features (zh/en/ja)
* 修复用量查询Reset字段出现多余字符
* refactor(auth-binding): introduce generic provider auth binding primitives
- add shared authBinding types in Rust and TypeScript while keeping githubAccountId as a compatibility field\n- resolve Copilot token, models, and usage through provider-bound account lookup instead of only the implicit default account\n- fix the Unix build regression in settings.rs by restoring std::io::Write for write_all()\n- remove the accidental .github ignore entry and drop leftover Copilot form debug logs\n- keep the first migration step non-breaking by writing both authBinding and the legacy githubAccountId field from the form
* refactor(auth-service): add managed auth command surface and explicit default account state
- introduce generic managed auth commands and frontend auth API wrappers for provider-scoped login, status, account listing, removal, logout, and default-account selection\n- store an explicit Copilot default_account_id instead of relying on HashMap iteration order, and use it consistently for fallback token/model/usage resolution\n- sort managed accounts deterministically and surface default-account state to the UI\n- refactor the Copilot form hook to wrap a generic useManagedAuth implementation while preserving the existing component contract\n- add default-account controls to the Copilot auth section and extend Copilot auth status serialization/tests for the new state
* feat(auth-center): add a dedicated settings entrypoint for managed OAuth accounts
- add an Auth Center tab to Settings so managed OAuth accounts are no longer hidden inside individual provider forms\n- introduce a first AuthCenterPanel that hosts GitHub Copilot account management as the initial managed auth provider\n- keep the provider form experience intact while establishing a global account-management surface for future providers such as OpenAI\n- validate that the new settings tab works cleanly with the generic managed auth hook and existing Copilot account controls
* feat(add-provider): expose managed OAuth sources alongside universal providers
- add an OAuth tab to the Add Provider flow so managed auth sources sit beside app-specific and universal providers\n- reuse the new Auth Center panel inside the dialog, keeping account management discoverable during provider creation\n- make the dialog footer adapt to the OAuth tab so account setup does not pretend to create a provider directly\n- align the add-provider UX with the new architecture where OAuth accounts are global assets and providers bind to them later
* fix(auth-reliability): harden managed auth persistence and refresh behavior
- replace direct Copilot auth store writes with private temp-file writes and atomic rename semantics, and document the local token storage limitation\n- add per-account refresh locks plus a double-check path so concurrent requests do not stampede GitHub token refresh\n- surface legacy migration failures through auth status, expose them in the UI, and add translated copy for the new account-state labels\n- stop writing the legacy githubAccountId field from the provider form while keeping compatibility reads in place\n- add logout error recovery and Copilot model-load toasts so auth failures are no longer silently swallowed
* refactor(copilot-detection): prefer provider type before URL fallbacks
- update forwarder endpoint rewriting to treat providerType as the primary GitHub Copilot signal\n- keep githubcopilot.com string matching only as a compatibility fallback for older provider records without providerType\n- reduce one more path where Copilot behavior depended purely on URL heuristics
* fix(copilot-auth): add cancel button to error state in CopilotAuthSection
- 错误状态下仅有"重试"按钮,用户无法退出(如不可恢复的 403 未订阅错误)
- 新增"取消"按钮,复用已有的 cancelAuth 逻辑重置为 idle 状态
* 修复打包后github账号头像显示异常
* 修复github copilot 来源的模型测试报错
* feat(copilot-preset): add default model presets for GitHub Copilot
- 补充 Copilot 预设的默认模型配置,用户选完预设即可直接使用
- ANTHROPIC_MODEL: claude-opus-4.6
- ANTHROPIC_DEFAULT_HAIKU_MODEL: claude-haiku-4.5
- ANTHROPIC_DEFAULT_SONNET_MODEL: claude-sonnet-4.6
- ANTHROPIC_DEFAULT_OPUS_MODEL: claude-opus-4.6
---------
Co-authored-by: Jason <farion1231@gmail.com>
Co-authored-by: 周梦泽 <mengze.zhou@dafeng-tech.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Update CHANGELOG.md with full v3.12.3 entry, create release notes in
three languages (en/zh/ja), bump macOS minimumSystemVersion from 10.15
to 12.0 (Monterey) to match actual runtime requirements, and update
README version badges and links.
All content panels used h-[calc(100vh-8rem)] which didn't match the
actual available space (CONTENT_TOP_OFFSET is 92px on Mac, 64px on
Win/Linux, not 128px), causing a visible gap at the bottom.
Replace with flex-1 min-h-0 to let panels fill the remaining space
after <main> and any sibling elements (e.g. OpenClaw health banner).
Introduce list/restore/delete commands for skill backups created during
uninstall. Restore copies files back to SSOT, saves the DB record, and
syncs to the current app with rollback on failure. Delete removes the
backup directory after a confirmation dialog. ConfirmDialog gains a
configurable zIndex prop to support nested dialog stacking.
Create a local backup under ~/.cc-switch/skill-backups/ before removing
skill directories. The backup includes all skill files and a meta.json
with original skill metadata. Old backups are pruned to keep at most 20.
The backup path is returned to the frontend and shown in the success
toast. Bump version to 3.12.3.
The AppToggleGroup component added in 7097a0d7 uses Radix UI Tooltip
which requires a TooltipProvider context. Without it, opening the
import dialog crashes with a runtime error and renders a blank page.
Non-streaming requests were forced to use `Accept-Encoding: identity`,
preventing upstream response compression and increasing bandwidth usage.
Now only streaming requests conservatively keep `identity` to avoid
decompression errors on interrupted SSE streams. Non-streaming requests
let reqwest auto-negotiate gzip and transparently decompress responses.
Responses API uses max_output_tokens for all models including o-series.
The o-series max_completion_tokens fix should only apply to Chat Completions API.
Split the expanded model panel into two editing areas:
- "Model Properties" for top-level fields (variants, cost, etc.)
- "SDK Options" for model.options fields (provider routing, etc.)
Also guard against renaming extra fields to reserved keys (name, limit,
options) or duplicate names, and fix ModelOptionKeyInput blur desync when
a rename is rejected by the parent handler.
* fix(proxy): use max_completion_tokens for o1/o3 series models
When converting Anthropic requests to OpenAI format for o1/o3 series
models (like o1-mini, o3-mini), use max_completion_tokens instead of
max_tokens to avoid unsupported_parameter errors.
Fixes#1448
* fix: revert incorrect o-series max_completion_tokens in Responses API path
Responses API uses max_output_tokens for all models including o-series.
The o-series max_completion_tokens fix should only apply to Chat Completions API.
---------
Co-authored-by: Hajen Teowideo <hajen.teowideo@example.com>
Co-authored-by: Jason Young <44939412+farion1231@users.noreply.github.com>
Co-authored-by: Jason <farion1231@gmail.com>
Make ProviderForm.handleSubmit async and await onSubmit so react-hook-form's
isSubmitting state is tracked. Disable submit buttons in AddProviderDialog and
EditProviderDialog while submission is in flight via onSubmittingChange callback.
Resolve the active `claude` command from PATH and apply an equal-length
byte patch to remove the domain whitelist check. Backups are stored in
~/.cc-switch/toolsearch-backups/ (SHA-256 of path) so they survive
Claude Code version upgrades. The patch auto-reapplies on app startup
when the setting is enabled.
Frontend checks PatchResult.success and rolls back the setting on failure.
Skills import previously inferred app enablement from filesystem presence,
causing incorrect multi-app activation when the same skill directory existed
under multiple app paths. Now the frontend submits explicit app selections
via ImportSkillSelection, and schema migration preserves a snapshot of
legacy app mappings to avoid lossy reconstruction.
Also adds reconciliation to sync_to_app (removes disabled/orphaned symlinks)
and MCP sync_all_enabled (removes disabled servers from live config).
When proxy takeover is active, update_live_backup_from_provider rebuilds the Codex restore snapshot from the current provider and common-config state. We were then replacing the new mcp_servers table with the previous backup's table wholesale, which meant stopping takeover could restore stale MCP entries and silently discard MCP changes made through provider/common-config updates.
Change the backup preservation step to merge MCP entries by server id instead of replacing the entire table. New provider/common-config MCP definitions now win on conflict, while backup-only servers are retained so live-only MCP state still survives a hot-switch.
Add regression coverage for the existing preservation case and for the conflict case where both the old backup and the new provider define the same MCP server.
Rewrite setCodexBaseUrl/extractCodexBaseUrl to understand TOML section
boundaries, ensuring base_url is written into the correct
[model_providers.<name>] section instead of being appended to file end.
- Add section-aware TOML helpers in providerConfigUtils.ts
- Extract shared update_codex_toml_field/remove_codex_toml_base_url_if
in codex_config.rs, deduplicate proxy.rs TOML editing logic
- Replace scattered inline base_url regexes with extractCodexBaseUrl()
- Add comprehensive tests for both Rust and TypeScript implementations
- Make sync_current_provider_for_app takeover-aware: update restore
backup instead of overwriting live config when proxy is active
- Introduce explicit "cleared" flag for common config snippets to
prevent auto-extraction from resurrecting user-cleared snippets
- Reorder startup: extract snippets from clean live files before
restoring proxy takeover state
- Add one-time migration flag to skip legacy commonConfigEnabled
migration on subsequent startups
- Add regression tests for takeover backup preservation, explicit
clear semantics, and migration flag roundtrip
Update takeover backup generation to rebuild effective provider settings with common config applied before saving restore snapshots.
Keep Codex mcp_servers entries when hot-switching providers under takeover so restore does not drop live-only MCP config.
Migrate legacy providers with inferred common-config usage to explicit commonConfigEnabled=true markers during startup and default imports, and cover the new behavior with proxy and provider regression tests.
Add optional `authHeader` boolean to support vendor-specific auth headers
(e.g. Longcat). Refactor `resetOpenclawState` to use the shared
`OpenClawProviderConfig` type instead of an inline duplicate definition.
Replace SDS logos with SiliconFlow logos, add SiliconFlow sponsor entries
to all three README files (en/zh/ja), fix incorrect alt attribute, and
update all SiliconFlow provider preset apiKeyUrl to affiliate link.
The auto-open useEffect in CodexConfigEditor and GeminiConfigEditor
created an inescapable loop: commonConfigError triggered modal open,
closing the modal didn't clear the error, so the effect immediately
reopened it — locking the entire UI.
- Remove auto-open useEffect from both Codex and Gemini config editors
- Convert common config modals to draft editing (edit locally, validate
before save) instead of persisting on every keystroke
- Add TOML/JSON pre-validation via parseCommonConfigSnippet before any
merge operation to prevent invalid content from being persisted
- Expose clearCommonConfigError so editors can clear stale errors on
modal close
- Add XCodeAPI sponsor entry to all three READMEs (zh, en, ja)
- Fix XCodeAPI logo alt from "Micu" to "XCodeAPI" in README_ZH.md
- Fix Crazyrouter logo alt from "AICoding" to "Crazyrouter" in all READMEs
Add Micu (米醋API) sponsor entry to all three README files (EN/ZH/JA)
with logo and description. Update apiKeyUrl for Micu provider presets
across claude, codex, opencode, and openclaw to use affiliate
registration link.
Add optional `nameKey` field to all preset interfaces for localized
display names. The preset selector and form now resolve `nameKey` via
i18next, falling back to `name` when unset.
- zh: 优云智算 / en+ja: Compshare
- Update model ID prefix ucloud/ → compshare/ in OpenClaw presets
- Update partner promotion copy and README sponsor descriptions
Replace useRef+useEffect async index rebuild with useMemo so the
FlexSearch index and the sessions array always reference the same data.
This ensures filtered search results update immediately when a session
is deleted via TanStack Query setQueryData.
Split LOCAL_ONLY_TABLES into SYNC_SKIP_TABLES (export) and
SYNC_PRESERVE_TABLES (import). provider_health is skipped on export
but no longer restored on import, since it has a foreign key on
providers(id, app_type) that may not match the remote dataset.
Health data is ephemeral and rebuilds automatically at runtime.
* feat(openClaw form): add input type selection for models Advanced Options / 为模型高级选项添加输入类型选择
* fix(i18n): add missing openclaw.inputTypes key to all locales
The new inputTypes field in OpenClawFormFields used defaultValue fallback,
causing English and Japanese users to see Chinese text.
---------
Co-authored-by: xu.liu2 <xu.liu2@brgroup.com>
Co-authored-by: Jason <farion1231@gmail.com>
Fixes issue where Longcat models were failing with 404 error due to missing
authHeader configuration. According to Longcat API documentation, this
setting is required for proper authentication.
Closes: #1376
The toolbar container used `justify-end` which caused content to overflow
to the left side. Browser `scrollWidth` does not account for left-side
overflow, so `useAutoCompact` could never detect it and compact mode
never activated — resulting in clipped tab labels (e.g. "aude" instead
of "Claude") at minimum window width.
Fix: remove `justify-end` from the toolbar container and use `ml-auto`
on the child element instead. This keeps the right-aligned appearance
but makes overflow go rightward, where `scrollWidth` correctly detects
it and triggers compact mode.
Co-authored-by: zuolan <zuolan1102@qq.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Update Ucloud links to coding-plan page across READMEs
- Remove hardcoded model overrides from Claude preset
- Switch Codex model from zai-org/glm-5 to gpt-5.4
- Replace GLM-5/MiniMax models with claude-opus-4-6 in OpenClaw preset
- Add templateValues and suggestedDefaults for Ucloud and Micu OpenClaw presets
Add a switch in the OpenClaw provider form to optionally send a browser
User-Agent header. The toggle defaults to off — only providers that
explicitly include headers in their preset or config will have it enabled.
Remove the previous auto-injection logic that force-added User-Agent on
every preset load and new provider creation.
- Add X-Code provider presets with x-code.cn endpoint
- Fix ANTHROPIC_API_KEY to ANTHROPIC_AUTH_TOKEN in Claude preset
- Register x-code icon SVG in icon index
- Add partnerPromotion.x-code i18n keys for zh, en, ja locales
- Add Micu provider presets with openclaudecode.cn endpoint
- Register micu icon SVG in icon index with namespaced CSS classes
- Rename miku.svg to micu.svg to match icon key
- Add partnerPromotion.micu i18n keys for zh, en, ja locales
- Add Ucloud provider presets with modelverse.cn API endpoint
- Register ucloud icon SVG in icon index with namespaced gradient IDs
- Add partnerPromotion.ucloud i18n keys for zh, en, ja locales
Add enableFailoverToggle setting to control failover toggle visibility
on the main page, decoupled from proxy takeover state. First-time
enable shows a ConfirmDialog (same pattern as proxy toggle). The toggle
row is placed in the Auto Failover accordion section in settings.
Common config snippets are now dynamically overlaid when writing live
files, rather than being pre-merged into provider snapshots at edit time.
This ensures that updating a snippet immediately takes effect for the
current provider and automatically propagates to other providers on
their next switch.
Key changes:
- Add write_live_with_common_config() overlay pipeline
- Strip common config from live before backfilling provider snapshots
- Normalize provider snapshots on save to keep them snippet-free
- Add explicit commonConfigEnabled flag in ProviderMeta (Option<bool>)
- Migrate legacy providers on snippet save (infer flag from subset check)
- Add Codex TOML snippet validation in set_common_config_snippet
- Stabilize onConfigChange callbacks with useCallback in ProviderForm
- Add 69 missing translation keys to zh/en/ja (usage, proxy, sessionManager,
deeplink, codexConfig, openclaw, circuitBreaker, streamCheck, etc.)
- Replace 15 hardcoded Chinese strings in CircuitBreakerConfigPanel with t() calls
- Fix ColorPicker component to use i18n for default label
- Add i18n interpolation params to ProxyToggle tooltip translations
- All three language files synchronized at 1838 keys
Separate protocol version from database compatibility version in WebDAV
sync paths. Upload writes to v2/db-v6/<profile>, download falls back to
legacy v2/<profile> when current path has no data. Extend manifest with
optional dbCompatVersion field and add legacy layout detection to UI.
- Add usage_daily_rollups table (schema v6) to aggregate proxy request
logs into daily summaries, reducing query overhead for statistics
- Add rollup_and_prune DAO that aggregates old detail logs (>N days)
into rollup rows and deletes the originals
- Update all usage stats queries to UNION detail logs with rollup data
- Introduce incremental auto-vacuum for SQLite, with startup and
periodic cleanup of old stream_check_logs and request log rollups
- Split backup export/import into full vs sync variants: WebDAV sync
now skips local-only table data (proxy_request_logs,
stream_check_logs, provider_health, proxy_live_backup,
usage_daily_rollups) while preserving them on import
- Add enable_logging guard to skip request log writes when disabled
- Apply cargo fmt formatting fixes across multiple modules
Rewrite tool call handling in streaming format conversion to properly
track multiple concurrent tool blocks with independent Anthropic content
indices. Fix block interleaving (thinking/text/tool_use) with correct
content_block_start/stop events, buffer tool arguments until both id and
name are available, and add tool result message conversion in transform.
- Extract shared map_responses_stop_reason and build_anthropic_usage_from_responses into transform_responses.rs as pub(crate)
- Align cache token extraction priority: OpenAI nested details as fallback, direct Anthropic fields as override
- Extract resolve_content_index helper to eliminate 3x copy-paste in streaming_responses.rs
- Add streaming reasoning/thinking event handlers (response.reasoning.delta/done)
- Add explanatory comment to transform_response heuristic detection
- Add openai_responses to api_format doc comment and needs_transform test
- Add explicit no-op match arms for lifecycle events
- Add promptCacheKey to TS ProviderMeta type
- Update toast i18n key to be generic for both OpenAI formats (zh/en/ja)
Support Anthropic ↔ OpenAI Responses API format conversion alongside existing
Chat Completions conversion. The Responses API uses a flat input/output structure
with lifted function_call/function_call_output items and named SSE lifecycle events.
* fix:Add a new vendor page, API endpoint, and model name. Fix the bug where, after entering characters, line breaks cannot be fully deleted.
* fix: add missing i18n key codexConfig.modelNameHint for zh/en/ja
---------
Co-authored-by: Jason <farion1231@gmail.com>
* fix: skills count not displaying when adding
* fix: get real skill count by awaiting discovery after adding repo
The previous approach computed count before discovery, so it was always 0.
Now we await refetchDiscoverable() after the mutation, then filter the
fresh skills list to get the actual count for the toast message.
Also reverts the SkillRepo.count field — keep the interface clean since
count is a transient UI concern, not a data model property.
---------
Co-authored-by: Jason <farion1231@gmail.com>
The text-based approach (string append + substring matching) failed to
detect already-merged snippets when config.toml was reformatted by
external tools (MCP sync, Codex CLI). Replace with smol-toml parse/
stringify + existing deepMerge/isSubset/deepRemove for correct
structural operations. Falls back to text matching on parse failure.
- Add useOpenClawModelOptions hook to aggregate models from all configured OpenClaw providers
- Replace read-only primary model display with a searchable Select dropdown
- Replace comma-separated fallback text input with add/remove Select rows
- Filter out already-selected models from fallback options
- Show "(not configured)" marker for values whose provider has been deleted
- Unify terminology: rename "主模型/Primary Model" to "默认模型/Default Model"
- Add Primary/Fallback badge to each model card in OpenClaw form
- Update modelsHint to explain model ordering semantics
- Reorder 11 aggregator/third-party presets to put Opus first
The status code from a simple GET request reflects route matching,
not actual endpoint availability. Users only need latency and
reachability info, which the latency number already conveys.
Show an informational dialog when users first click the health check
button, explaining its limitations (OAuth providers, relay services,
Bedrock). The dialog persists the confirmation in settings so it only
appears once per device.
Stream Check always used Anthropic Messages API format, causing false
failures for providers with api_format="openai_chat" (e.g. NVIDIA).
Now detects api_format from provider meta/settings_config and uses
the correct endpoint (/v1/chat/completions) and headers accordingly.
Re-enable the stream check feature that was hidden in v3.11.0.
All backend code, database schema, and i18n keys were preserved;
only the frontend UI needed uncommenting across 4 files.
OpenCode and OpenClaw are excluded as the backend does not support them.
Reorganize docs/user-manual/ from flat structure to language subdirectories
(zh/, en/, ja/) with shared assets/. Move existing Chinese docs into zh/,
fix image paths, add multilingual navigation README, and translate all 23
markdown files (~4500 lines each) to English and Japanese.
During app startup, iterate all app types and extract non-provider-specific
config fields from live configuration files into the database. This runs
only when no snippet exists yet for a given app type, enabling incremental
extraction as new apps are configured.
The i18next t() calls for proxy.takeover.enabled/disabled were missing
the `app` interpolation parameter, causing {{app}} placeholders in
translation strings to render literally instead of showing the app name.
After moving ProxyToggle/FailoverToggle outside toolbarRef, the flex-1
class was accidentally left only on the outer wrapper. Without flex-1,
toolbarRef.clientWidth reflects content width instead of available space,
causing useAutoCompact's exit condition to never trigger.
Pass "system" to set_window_theme instead of explicitly detecting dark/light,
so Tauri uses window.set_theme(None) and the WebView's prefers-color-scheme
media query stays in sync with the real OS theme.
Move the proxy on/off switch from the accordion header into the panel
content area, placing it right above the app takeover section. This
ensures users see the takeover options immediately after enabling the
proxy, preventing the common pitfall of running the proxy without
actually taking over any app.
- Simplify accordion trigger to standard style with Badge only
- Add AnimatePresence animation for takeover section reveal
- Remove duplicate takeover switches from running info card
- Update stoppedDescription i18n to reference "above toggle"
- Add proxy.takeover.hint key in zh/en/ja
Revert the partial key-field merging refactoring introduced in 992dda5c,
along with two dependent commits (24fa8a18, 87604b18) that referenced
the now-removed ClaudeQuickToggles component.
The whitelist-based partial merge approach had critical issues:
- Non-whitelisted custom fields were lost during provider switching
- Backfill permanently stripped non-key fields from the database
- Whitelist required constant maintenance to track upstream changes
This restores the proven "full config overwrite + Common Config Snippet"
architecture where each provider stores its complete configuration and
shared settings are managed via a separate snippet mechanism.
Reverted commits:
- 24fa8a18: context-aware JSON editor hint + hide quick toggles
- 87604b18: hide ClaudeQuickToggles when creating
- 992dda5c: partial key-field merging refactoring
Restored:
- Full config snapshot write (write_live_snapshot) for Claude/Codex/Gemini
- Full config backfill (settings_config = live_config)
- Common Config Snippet UI and backend commands
- 6 frontend components/hooks for common config editing
- configApi barrel export and DB snippet methods
Removed:
- ClaudeQuickToggles component
- write_live_partial / backfill_key_fields / patch_claude_live
- All KEY_FIELDS constants
Previously OpenCode and OpenClaw auto-imported providers from live config
on app startup, which could confuse users. Now they follow the same
pattern as Claude/Codex/Gemini: manual import via the empty state button.
Expand the partial key-field merging section with Before/After explanation
and migration guide. Mark it as a breaking change in Highlights and Notes
sections across all three languages (zh/en/ja) and CHANGELOG.md.
- Update version numbers in package.json, Cargo.toml, tauri.conf.json
- Add CHANGELOG.md entry for v3.11.0
- Add trilingual release notes (zh/en/ja)
- Update user manual version info
backup_database_file() returning Ok(None) was silently resolved as null
on the frontend, bypassing try/catch and showing a success toast without
actually creating a backup file. Now None is converted to an explicit
Err so the frontend correctly displays an error toast.
The hasApiKeyField() gate added for Bedrock AKSK/API Key distinction
was incorrectly hiding the API Key input for all new providers with
empty env config. Scope the gate to cloud_provider category only.
JSON does not support duplicate keys — the second `openclaw` object was
silently overwriting the first, causing all provider form field translations
(providerKey, apiProtocol, baseUrl, models, etc.) to be lost at runtime.
OMO and OMO Slim are OpenCode plugins, not standalone apps — users
should be able to fully remove them. Remove the count-based guard that
prevented deleting the last active provider, and clean up the now-unused
provider-count API surface across the full stack.
Each OMO provider now stores its complete configuration directly in
settings_config.otherFields instead of relying on a shared OmoGlobalConfig
merged at write time. This simplifies the data flow from a 4-tuple
(agents, categories, otherFields, useCommonConfig) to a 3-tuple and
eliminates an entire DB table, two Tauri commands, and ~1700 lines of
merge/sync code across frontend and backend.
Backend:
- Delete database/dao/omo.rs (OmoGlobalConfig struct + get/save methods)
- Remove get/set_config_snippet from settings DAO
- Remove get/set_common_config_snippet Tauri commands
- Replace merge_config() with build_config() in services/omo.rs
- Simplify OmoVariant (remove config_key, known_keys)
- Simplify import_from_local and build_local_file_data
- Rewrite all OMO service tests
Frontend:
- Delete OmoCommonConfigEditor.tsx and OmoGlobalConfigFields.tsx
- Delete src/lib/api/config.ts
- Remove OmoGlobalConfig type and merge preview functions
- Remove useGlobalConfig/useSaveGlobalConfig query hooks
- Simplify useOmoDraftState (remove all common config state)
- Replace OmoCommonConfigEditor with read-only JsonEditor preview
- Clean i18n keys (zh/en/ja)
When activating an OMO provider, deactivate all OMO Slim providers
in the same transaction and delete the Slim config file, and vice
versa. This prevents both plugin variants from being active
simultaneously.
OMO Slim queries (["omo-slim", ...]) were not invalidated alongside
OMO queries, causing stale UI state when switching/adding/deleting
OMO Slim providers.
Regular agents & categories: align with oh-my-opencode model-requirements.ts
fallback chains (oracle→gpt-5.2, librarian→gemini-3-flash, etc.)
Slim agents: derive from Regular's design philosophy — match each agent
to its functional counterpart's first-choice model instead of using
the outdated Slim defaults. Also fix provider/model format to pure
model IDs for suffix matching compatibility.
- Parallelize 5 provider scans using std::thread::scope
- Add read_head_tail_lines() to read only first 10 + last 30 lines from JSONL files, skipping potentially large middle sections
- Cache Codex UUID regex with LazyLock to avoid repeated compilation
- Skip expensive I/O in OpenCode when session title is already available
The hint text and ClaudeQuickToggles were misleading when editing
non-current providers or creating new ones, since the editor only
contains a config snippet rather than the full live settings.json.
The quick toggles (hide AI attribution, extended thinking, teammates
mode) patch the live config of the currently active provider, which
is incorrect during provider creation. Only show them in edit mode.
Update Sonnet and Opus model IDs/names to 4.6 across Claude, OpenClaw,
and OpenCode provider preset configurations. OPENCODE_PRESET_MODEL_VARIANTS
(SDK model catalog) is intentionally left unchanged.
Add SSAI Code as a partner provider across all five apps with endpoint,
API key URL, and partner promotion config. Rename brand from SSSAiCode
to SSAI Code. Rename sssaicoding.svg to sssaicode.svg and register icon.
Add trilingual promotion text for $10 bonus credit. Add missing models
arrays in OpenClaw presets for CrazyRouter and SSAI Code.
Add CrazyRouter as a partner provider across all five apps with endpoint,
API key URL, and partner promotion config. Add trilingual promotion text
for the 30% bonus credit offer. Register aicoding and crazyrouter icons
in the icon index. Fix indentation in openclawProviderPresets.
Add AICoding as a partner provider across all five apps (Claude, Codex,
Gemini, OpenClaw, OpenCode) with endpoint, API key URL, and partner
promotion configuration. Add trilingual (zh/en/ja) promotion text for
the first top-up discount.
Several code paths only checked for "omo" category but missed "omo-slim",
causing OMO Slim providers to be treated as regular OpenCode providers
(triggering invalid write_live_snapshot, requiring manual provider key,
and showing wrong form fields).
* Add AWS Bedrock provider integration design document
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add AWS Bedrock provider implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update implementation plan: add OpenCode Bedrock support
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add cloud_provider category to ProviderCategory type
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add AWS Bedrock (AKSK) Claude Code provider preset with tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add AWS Bedrock (API Key) Claude Code provider preset with tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add AWS Bedrock OpenCode provider preset with @ai-sdk/amazon-bedrock
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add AWS Bedrock provider feature summary for PR
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove internal planning documents
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add AWS Bedrock support to README (EN/ZH/JA)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add AWS Bedrock UI merge design document
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add AWS Bedrock UI merge implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: skip optional template values in validation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: support isSecret template fields and hide base URL for Bedrock
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Bedrock validation, cleanup, and isBedrock prop in ProviderForm
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: extend TemplateValueConfig and merge Bedrock presets
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: mask Bedrock API Key as secret and support GovCloud regions
- Add isSecret: true to BEDROCK_API_KEY template value
- Update region regex to support multi-segment regions (us-gov-west-1)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style: replace AWS icon with updated logo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style: replace AWS icon with updated logo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style: replace AWS icon with new PNG image
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address code review findings
- Fix AWS icon: use SVG with embedded <image> instead of raw <img> tag
- Hide duplicate ApiKeySection for Bedrock (auth via template fields only)
- Guard settingsConfig cleanup against unresolved template placeholders
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove planning documents
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: address PR review - split Bedrock into two presets, restore SVG icon
Based on maintainer review feedback on PR #1047:
1. Split merged "AWS Bedrock" back into two separate presets:
- "AWS Bedrock (AKSK)": uses AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY
- "AWS Bedrock (API Key)": uses top-level apiKey field via standard UI input
2. Restore aws.svg to pure vector SVG (was PNG-in-SVG)
3. Remove all Bedrock-specific logic from shared components:
- Remove isBedrock prop from ClaudeFormFields
- Remove Bedrock validation/cleanup blocks from ProviderForm
- Remove optional/isSecret from TemplateValueConfig
- Remove optional skip from useTemplateValues
4. Add cloud_provider category handling:
- Skip API Key/Base URL required validation
- Hide Speed Test and Base URL for cloud_provider
- Hide API format selector for cloud_provider (always Anthropic)
- Show API Key input only when config has apiKey field
5. Fix providerConfigUtils to support top-level apiKey:
- getApiKeyFromConfig: check config.apiKey before env fields
- setApiKeyInConfig: write to config.apiKey when present
- hasApiKeyField: detect top-level apiKey property
6. Add OpenClaw Bedrock preset (bedrock-converse-stream protocol)
7. Update model IDs:
- Sonnet: global.anthropic.claude-sonnet-4-6
- Opus: global.anthropic.claude-opus-4-6-v1
- Haiku: global.anthropic.claude-haiku-4-5-20251001-v1:0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(test): align Bedrock API Key test assertions with preset implementation
The API Key preset was refactored to use standard UI input (apiKey: "")
instead of template variables, but the tests were not updated accordingly.
---------
Co-authored-by: root <root@ip-10-0-11-189.ap-northeast-1.compute.internal>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
Add open_workspace_directory Tauri command to open workspace/memory dirs
in the system file manager. Rename dailyMemory.createToday across all locales.
Add backend search command that performs case-insensitive matching
across all daily memory files, supporting both date and content queries.
Frontend includes animated search bar (⌘F), debounced input, snippet
display with match count badge, and search state preservation across
edits.
* refactor(provider): switch from full config overwrite to partial key-field merging
Replace the provider switching mechanism for Claude/Codex/Gemini from
full settings_config overwrite to partial key-field replacement, preserving
user's non-provider settings (plugins, MCP, permissions, etc.) across switches.
- Add write_live_partial() with per-app implementations for Claude (JSON env
merge), Codex (auth replace + TOML partial merge), and Gemini (env merge)
- Add backfill_key_fields() to extract only provider-specific fields when
saving live config back to provider entries
- Update switch_normal, sync_current_to_live, add, update to use partial merge
- Remove common config snippet feature for Claude/Codex/Gemini (no longer
needed with partial merging); preserve OMO common config
- Delete 6 frontend files (3 components + 3 hooks), clean up 11 modified files
- Remove backend extract_common_config_* methods, 3 Tauri commands,
CommonConfigSnippets struct, and related migration code
- Update integration tests to validate key-field-only backfill behavior
* refactor(cleanup): remove dead code and redundant MCP sync after partial-merge refactor
- Remove ConfigService legacy full-overwrite sync methods (~150 lines)
- Remove redundant McpService::sync_all_enabled from switch_normal
- Switch proxy fallback recovery from write_live_snapshot to write_live_partial
- Remove dead ProviderService::write_gemini_live wrapper
- Update tests to reflect partial-merge behavior (MCP preserved, not re-synced)
* feat(claude): add Quick Toggles for common Claude Code preferences
Add checkbox toggles for hideAttribution, alwaysThinking, and
enableTeammates that write directly to the live settings file via
RFC 7396 JSON Merge Patch. Mirror changes to the form editor using
form.watch for reactive updates.
* fix(provider): add missing key fields to partial-merge constants
Add provider-specific fields verified against official docs to prevent
key residue or loss during provider switching:
- Claude: CLAUDE_CODE_SUBAGENT_MODEL (env), model (top-level)
- Codex: review_model, plan_mode_reasoning_effort
- Gemini: GOOGLE_API_KEY (official alternative to GEMINI_API_KEY)
* fix(provider): expand partial-merge key fields for Bedrock, Vertex, Foundry and behavior settings
Add missing env/top-level fields to CLAUDE_KEY_ENV_FIELDS and
CLAUDE_KEY_TOP_LEVEL so that provider switching correctly replaces
(and clears) credentials and flags for AWS Bedrock, Google Vertex AI,
Microsoft Foundry, and provider behavior overrides like max output
tokens and prompt caching.
* feat(provider): add auth field selector for Claude providers (AUTH_TOKEN / API_KEY)
Allow users to choose between ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY
when creating or editing custom Claude providers, persisted in meta.apiKeyField.
* refactor(preset): remove AiHubMix hardcoded API_KEY in favor of generic auth selector
AiHubMix was the only preset that hardcoded ANTHROPIC_API_KEY before the
generic auth field selector was introduced. Now that users can freely
choose between AUTH_TOKEN and API_KEY via the UI, remove the special-case
and default AiHubMix to the standard ANTHROPIC_AUTH_TOKEN.
Extract backup & restore into a standalone AccordionItem in Advanced settings.
Add configurable auto-backup interval (disabled/6h/12h/24h/48h/7d) and retention
count (3-50) via settings. Add per-backup rename with inline editing UI.
Four improvements to the database backup mechanism:
1. Auto backup before schema migration - creates a snapshot when
upgrading from an older database version, providing a safety net
beyond the existing SAVEPOINT rollback mechanism.
2. Periodic startup backup - checks on app launch whether the latest
backup is older than 24 hours and creates a new one if needed,
ensuring all users have recent backups regardless of usage patterns.
3. Backfill failure notification - switch now returns SwitchResult with
warnings instead of silently ignoring backfill errors, so users are
informed when their manual config changes may not have been saved.
4. Backup management UI - new BackupListSection in Settings > Data
Management showing all backup snapshots with restore capability,
including a confirmation dialog and automatic safety backup before
restore.
Prevent accidental activation of advanced features by showing a one-time
info dialog. Once confirmed, the flag is persisted in settings.json and
the dialog never appears again.
- Proxy: confirmation when toggling proxy server ON for the first time
- Usage: confirmation when enabling usage query inside UsageScriptModal
- Enhanced ConfirmDialog with "info" variant (blue icon + default button)
- Added i18n translations for zh, en, ja
Replace conditional rendering with always-rendered span driven by CSS
max-width + opacity animation. Add time-lock in useAutoCompact to prevent
ResizeObserver flicker during expand animation.
The toolbar wrapper's fixed h-[32px] was smaller than AppSwitcher's
natural 40px height (32px buttons + 8px padding), causing visual
clipping. Removed the constraint and let flex layout handle sizing
within the 64px header.
Extract proxy-related accordion items (Local Proxy, Failover, Rectifier,
Global Outbound Proxy) into a dedicated Proxy tab via ProxyTabContent
component. Move Pricing config panel to UsageDashboard as a collapsible
accordion. This reduces SettingsPage from ~716 to ~426 lines and improves
settings discoverability with a 5-tab layout: General | Proxy | Advanced |
Usage | About.
* feat: more granular local environment checks
* refactor: improve PR #870 with i18n, shadcn Select, and testable helpers
- Extract is_valid_shell, is_valid_shell_flag, default_flag_for_shell
to module-level #[cfg(windows)] functions for testability
- Add unit tests for extracted helper functions
- Replace native <select> with shadcn/ui Select components
- Extract env badge ternary to ENV_BADGE_CONFIG Record lookup
- Add i18n keys for env badges and WSL selectors (zh/en/ja)
- Unify initial useEffect load path with loadAllToolVersions()
* fix: prevent useEffect re-firing on wslShellByTool changes
The useEffect that loads initial tool versions depended on
loadAllToolVersions, which in turn depended on wslShellByTool.
This caused a full re-fetch of all 4 tools every time the user
changed a WSL shell or flag, racing with the single-tool refresh.
Fix: use empty deps [] since this is a mount-only effect. The
refresh button and shell/flag handlers cover subsequent updates.
---------
Co-authored-by: Jason <farion1231@gmail.com>
Remove the startup loop in lib.rs that auto-imported default providers
for Claude/Codex/Gemini. Move config snippet extraction logic into the
import_default_config command so it works when triggered manually.
Add an "Import Current Config" button to ProviderEmptyState, wired via
useMutation in ProviderList (shown only for standard apps). Update i18n
keys (zh/en/ja) with new button labels and revised empty state text.
The Auto (Failover) toggle in the system tray is no longer shown.
The feature remains fully functional via the Settings page.
All related backend code (handle_auto_click, AUTO_SUFFIX, etc.)
is preserved for easy re-enablement.
The primary model field in the Agents defaults panel now displays as
read-only, eliminating the duplicate edit entry with the "Set as Default
Model" button on provider cards. Fallback models and runtime parameters
remain editable.
- Sort daily memory list by filename (YYYY-MM-DD.md) instead of mtime
so editing an older file no longer bumps it to the top
- Move daily memory card inline with workspace MD file buttons
- Shorten card description across all locales
- Defer file creation until user actually saves (no empty file on create)
The stream check feature is unreliable due to diverse provider request
formats. Comment out the model test config UI in settings page, provider
advanced config, and the test button in provider actions. Backend code
and i18n keys are preserved for future restoration.
New users often accidentally trigger ProxyToggle/FailoverToggle on the
main page. Add a settings toggle (default off) so the proxy controls
only appear when explicitly enabled. The proxy service start/stop in
settings remains independent of this visibility flag.
Introduce OmoVariant struct with STANDARD/SLIM constants to eliminate
~250 lines of copy-pasted code across DAO, service, commands, and
frontend layers. Adding a new OMO variant now requires only a single
const declaration instead of duplicating ~400 lines.
Implement full OMO Slim profile management to align with ai-toolbox:
- Backend: Slim service methods, DAO, Tauri commands, plugin conflict handling
- Frontend: types, API, query hooks, form integration with isSlim parameterization
- Slim variant: 6 agents (no categories), separate config file and plugin name
- Mutual exclusion: standard OMO and Slim cannot coexist as plugins
- i18n: zh/en/ja translations for all Slim agent descriptions
Split ProviderForm.tsx (2227 → 1526 lines) by extracting:
- opencodeFormUtils.ts: pure functions and default config constants
- useOmoModelSource: OMO model source collection from OpenCode providers
- useOpencodeFormState: OpenCode provider form state and handlers
- useOmoDraftState: OMO profile draft editing state
- useOpenclawFormState: OpenClaw provider form state and handlers
Replace React Fragment with a div using space-y-6 to add proper
vertical spacing between the app config directory and directory
override sections in Settings > Advanced > Directory Settings.
Fixes Nvidia provider and other providers using apiFormat="openai_chat".
The ClaudeAdapter::build_url() method was incorrectly adding ?beta=true
to both /v1/messages and /v1/chat/completions endpoints. This caused
the Nvidia provider to fail because:
1. Nvidia uses apiFormat="openai_chat"
2. Requests are transformed to OpenAI format and sent to /v1/chat/completions
3. The URL gets ?beta=true appended (Anthropic-specific parameter)
4. Nvidia's API rejects requests with this parameter
Fix:
- Only add ?beta=true to /v1/messages endpoint
- Exclude /v1/chat/completions from getting this parameter
Tested:
- Anthropic /v1/messages still gets ?beta=true ✓
- OpenAI Chat Completions /v1/chat/completions does NOT get ?beta=true ✓
- All 13 Claude adapter tests pass ✓
Co-authored-by: jnorthrup <jnorthrup@example.com>
Add 3 quick-toggle checkboxes above the JSON editor in Claude provider settings:
- Hide AI Attribution (sets attribution.commit/pr to empty string)
- Extended Thinking (sets alwaysThinkingEnabled to true)
- Teammates Mode (sets env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS to "1")
Uses local state to keep toggles and JsonEditor in sync without
triggering ProviderForm re-renders. Includes i18n for zh/en/ja.
Co-authored-by: Jason <farion1231@gmail.com>
* fix(skill): resolve symlinks in ZIP extraction for GitHub repos (#1001)
- detect symlink entries via is_symlink() during ZIP extraction and collect target paths
- add resolve_symlinks_in_dir() to copy symlink target content into link location
- canonicalize base_dir to fix macOS /tmp → /private/tmp path comparison issue
- add path traversal safety check to block symlinks pointing outside repo boundary
- apply symlink resolution to both download_and_extract and extract_local_zip paths
Closes https://github.com/farion1231/cc-switch/issues/1001
* fix(skill): change search to match name and repo instead of description
* feat(skill): support importing skills from ~/.agents/skills/ directory
- Scan ~/.agents/skills/ in scan_unmanaged() for skill discovery
- Parse ~/.agents/.skill-lock.json to extract repo owner/name metadata
- Auto-add discovered repos to skill_repos management on import
- Add path field to UnmanagedSkill to show discovered location in UI
Closes#980
* fix(skill): use metadata name or ZIP filename for root-level SKILL.md imports (#1000)
When a ZIP contains SKILL.md at the root without a wrapper directory,
the install name was derived from the temp directory name (e.g. .tmpDZKGpF).
Now falls back to SKILL.md frontmatter name, then ZIP filename stem.
* feat(skill): scan ~/.cc-switch/skills/ for unmanaged skill discovery and import
* refactor(skill): unify scan/import logic with lock file skillPath and repo saving
- Deduplicate scan_unmanaged and import_from_apps using shared source list
- Replace hand-written AppType match with as_str() and AppType::all()
- Extract read_skill_name_desc, build_repo_info_from_lock, save_repos_from_lock helpers
- Add SkillApps::from_labels for building enable state from source labels
- Parse skillPath from .skill-lock.json for correct readme URLs
- Save skill repos to skill_repos table in both import and migration paths
* fix(skill): resolve symlink and path traversal issues in ZIP skill import
* fix(skill): separate source path validation and add canonicalization for symlink safety
Anthropic SDK auto-appends /v1 to baseUrl, so including it in the
preset causes double-path (/v1/v1/messages). Affects AiHubMix, DMXAPI,
PackyCode, Cubence, and AIGoCode.
Keep only model ID and display name visible by default,
collapse context window, max tokens, reasoning, and cost
fields into the advanced options section.
- Add 25 missing i18n keys for OpenClawFormFields in all 3 locales (P0)
- Replace key={index} with stable crypto.randomUUID() keys in EnvPanel,
ToolsPanel, and OpenClawFormFields to prevent list state bugs (P1)
- Exclude openclaw from ProxyToggle/FailoverToggle in App.tsx (P1)
- Add merge_additive_config() for openclaw/opencode deep link imports (P1)
- Normalize serde(flatten) field naming to `extra` + HashMap (P2)
- Add directory existence check in remove_openclaw_provider_from_live (P2)
- Remove dead code in import_default_config and openclaw API methods (P2)
- Add duplicate key validation in EnvPanel before save (P2)
- Add openclawConfigDir to Settings type (P2)
- Add staleTime to OpenClaw query hooks (P3)
- Fix type-unsafe delete via destructuring in mutations.ts (P3)
Centralize query keys and extract reusable hooks (useOpenClaw.ts),
replacing manual useState/useEffect load/save patterns in Env, Tools,
and AgentsDefaults panels for consistency with MCP/Skills modules.
- Fix EnvPanel visibleKeys using entry key name instead of array index
to prevent visibility state corruption after deletion
- Add NaN guard in AgentsDefaultsPanel numeric field parsing
- Validate provider id and models before importing from live config
- Upgrade import failure log level from debug to warn for OpenCode/OpenClaw
Add a dedicated panel to read/write OpenClaw's 6 workspace bootstrap files
(AGENTS.md, SOUL.md, USER.md, IDENTITY.md, TOOLS.md, MEMORY.md) directly
from ~/.openclaw/workspace/, with a whitelist-secured backend and Markdown
editor UI. Also fix prompt auto-import missing OpenCode/OpenClaw and the
PromptFormPanel filenameMap type exclusion.
Expand McpApps interface, APP_IDS, APP_ICON_MAP, enabledCounts
initializers, and test mock data to include the openclaw key,
resolving TypeScript errors after AppId union was extended.
Tauri IPC calls are in-process (microsecond latency), so the 5-minute
staleTime and disabled refetchOnWindowFocus from web app templates are
counterproductive. Set staleTime to 0 and enable refetchOnWindowFocus
so external config changes are reflected immediately.
- Add "Enable as Default" button to OpenClaw provider cards
- Place enable button before add/remove button for better UX
- Disable remove button when provider is set as default
- Add sessionsApi re-export from api barrel file to fix white screen
- Add i18n keys for default model feature (zh/en/ja)
- Fix Opus pricing from $15/$75 (Opus 4 price) to $5/$25 in openclaw presets
- Upgrade model ID from claude-opus-4-5-20251101 to claude-opus-4-6
- Update all suggestedDefaults references (fallbacks + modelCatalog)
- Apply same model upgrade in opencode presets (7 providers)
When adding an OpenClaw provider with suggestedDefaults, automatically
merge its model catalog into the allowlist and set the default model
if not already configured.
Add cache invalidation for openclawLiveProviderIds in useSwitchProviderMutation
to ensure button state updates correctly after adding/removing providers.
Also fix toast message to show "已添加到配置" for OpenClaw (same as OpenCode).
- Add providerKey input field in ProviderForm for OpenClaw
- Implement duplicate key detection by querying existing providers
- Add format validation (lowercase letters, numbers, hyphens only)
- Disable field in edit mode (key cannot be changed after creation)
- Update mutations.ts to support OpenClaw providerKey
- Add i18n translations for zh/en/ja
- Add getOpenClawLiveProviderIds() API for querying live config
- Update ProviderList to query OpenClaw live IDs
- Rename isOpenCodeMode to isAdditiveMode (covers OpenCode + OpenClaw)
- Update ProviderCard shouldAutoQuery and isActiveProvider logic
- Update App.tsx onRemoveFromConfig and invalidateQueries for OpenClaw
- Add types for default model config (primary + fallbacks)
- Add types for model catalog/allowlist with aliases
- Extend OpenClawModelEntry with cost and contextWindow fields
- Add Tauri commands: get/set_openclaw_default_model, get/set_openclaw_model_catalog
- Create frontend API (src/lib/api/openclaw.ts)
- Add suggestedDefaults to provider presets with model metadata
- Add i18n translations (zh/en/ja) for openclawConfig.*
OpenClaw only needs provider management functionality, not MCP, Skills,
or Prompts features. This commit removes the incorrectly added support:
- Revert SCHEMA_VERSION from 6 to 5 (remove v5->v6 migration)
- Remove enabled_openclaw field from mcp_servers and skills tables
- Remove openclaw field from McpApps and SkillApps structs
- Update DAO queries to exclude enabled_openclaw column
- Fix frontend components and types to exclude openclaw from MCP/Prompts
- Update all related test files
- Add "openclaw": "OpenClaw" to apps translations in zh.json
- Add "openclaw": "OpenClaw" to apps translations in en.json
- Add "openclaw": "OpenClaw" to apps translations in ja.json
- Update App.tsx with openclaw visibility and skills fallback
- Add OpenClaw to AppSwitcher icon and display name maps
- Update McpFormModal with openclaw in enabled apps
- Update PromptFormModal/Panel with openclaw filename map
- Update EndpointSpeedTest with openclaw timeout
- Update AppVisibilitySettings with openclaw toggle
- Update test state with openclaw defaults
- Create openclawProviderPresets.ts with provider templates
- Include Chinese officials (DeepSeek, Zhipu, Qwen, Kimi, MiniMax)
- Include aggregators (AiHubMix, DMXAPI, OpenRouter, ModelScope)
- Include third party partners (PackyCode, Cubence, AIGoCode)
- Include OpenAI Compatible custom template
- Add OpenClawProviderConfig and OpenClawModel interfaces
- Add openclaw to McpApps, VisibleApps, ProxyTakeoverStatus
- Add "openclaw" to AppId union type
- Add openclaw to SkillApps interface
- Register openclaw_config module in lib.rs
- Add OpenClaw commands and provider import on startup
- Add OpenClaw branches to config and provider commands
- Add build_openclaw_settings() for deeplink imports
- Update MCP handlers with openclaw field in McpApps
- Add OpenClaw prompt file path
- Add OpenClaw branches to proxy service (not supported)
- Add OpenClaw to MCP service (skip sync, MCP still in development)
- Add OpenClaw skills directory path
- Update ProxyTakeoverStatus with openclaw field
- Add OpenClaw to stream check (not supported)
- Add import_openclaw_providers_from_live() function
- Add remove_openclaw_provider_from_live() function
- Update write_live_snapshot() for OpenClaw
- Add openclaw fields to VisibleApps and AppSettings
- Add get_openclaw_override_dir() function
On some Linux systems with AMD GPUs (e.g., AMD Cezanne/Radeon Vega),
WebKitGTK's GPU process fails to initialize EGL, causing the app to
show a white screen on startup.
Root cause: `amdgpu_query_info(ACCEL_WORKING)` returns EACCES (-13),
which causes EGL display creation to fail with EGL_BAD_PARAMETER,
crashing the GPU process.
Fix: Use WebKitGTK's `set_hardware_acceleration_policy(Never)` API to
disable GPU acceleration on Linux, falling back to software rendering.
This is applied at startup via Tauri's `with_webview` API.
Co-authored-by: Naozhong AI <oursnoah@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(omo): use lowercase keys for builtin agent definitions
OMO config schema expects all agent keys to be lowercase.
Updated OMO_BUILTIN_AGENTS keys (Sisyphus → sisyphus, Hephaestus →
hephaestus, etc.) and aligned Rust test fixtures accordingly.
* feat(omo): add i18n support and tooltips for agent/category descriptions
* feat(omo): add preset model variants for thinking level support
Add OPENCODE_PRESET_MODEL_VARIANTS constant with variant definitions
for Google, OpenAI, and Anthropic models. The omoModelVariantsMap
builder now falls back to presets when config-defined variants are
absent, enabling the variant selector for supported models.
* feat(omo): replace model select with searchable combobox and improve fallback handling
* feat(omo): enrich preset model defaults and metadata fallback
* fix(omo): preserve custom fields and align otherFields import/validation
* fix: resolve omo clippy warnings and include app update
Session manager backend only supports Claude and Codex providers.
Hide the nav button for Gemini/OpenCode with animated transition,
and auto-fallback to providers view when switching apps.
Use the actual branch returned by download_repo instead of the
configured branch, fixing 404s when repos default to master but
the URL was hardcoded to main. Also switch URL format from /tree/
to /blob/ and always point to the SKILL.md file.
Closesfarion1231/cc-switch#968
* feat(omo): integrate Oh My OpenCode profile management into Provider system
Adds full-stack OMO support: backend config read/write/import, OMO-specific
provider CRUD with exclusive switching, frontend profile editor with
agent/category/model configuration, global config management, and i18n support.
* feat(omo): add model/variant dropdowns from enabled providers
Replace model text inputs with Select dropdowns sourced from enabled
OpenCode providers, add thinking-level variant selection, and prevent
auto-enabling newly added OMO providers.
* fix(omo): use standard provider action styles for OMO switch button
* fix(omo): replace hardcoded isZh strings with proper i18n t() calls
- replace Qwen Coder preset with Bailian for Claude and OpenCode
- add Bailian icon asset and metadata mapping
- remove Bailian preset default model values
- rename Claude preset Kimi k2 to Kimi
- Add claude-opus-4-6-20260206 pricing (same as opus-4-5)
- Add gpt-5.3-codex series pricing (same as gpt-5.2-codex)
- Change seed_model_pricing to INSERT OR IGNORE for incremental upsert
- Remove count==0 guard in ensure_model_pricing_seeded so new models
are appended on every startup without overwriting user customizations
* style: format code and apply clippy lint fixes
* feat(usage): enhance dashboard with auto-refresh control and robust formatting
- Add configurable auto-refresh interval toggle (off/5s/10s/30s/60s) to usage dashboard
- Extract shared format utilities (fmtUsd, fmtInt, parseFiniteNumber, getLocaleFromLanguage)
- Refactor request log time filtering to rolling vs fixed mode with validation
- Use stable serializable query keys instead of filter objects
- Handle NaN/Infinity safely in number formatting across all usage components
- Use RFC 3339 date format in backend trend data
- Remove terminal selector from Session Manager page
- Backend now reads terminal preference from global settings
- Add terminal name mapping (iterm2 → iterm) for compatibility
- Add WezTerm support to macOS terminal options
- Add WezTerm translations for zh/en/ja
- Add i18n keys for relative time (justNow, minutesAgo, hoursAgo, daysAgo)
- Add i18n keys for role labels (roleUser, roleSystem, roleTool)
- Add i18n keys for UI elements (tocTitle, searchSessions, clickToCopyPath)
- Update formatRelativeTime and getRoleLabel to accept t function
- Add useTranslation hook to SessionToc component
Provider request formats are complex and varied, making it difficult
to create a unified test mechanism. Users may incorrectly assume
request format issues indicate provider unavailability.
Code is commented out (not deleted) for easy restoration if needed.
v3.10.3 introduced HOME env priority on Windows for test isolation,
which caused database path to change when HOME differs from USERPROFILE
(common in Git/MSYS environments), making providers appear to disappear.
Changes:
- Use CC_SWITCH_TEST_HOME for test isolation instead of HOME
- Add legacy fallback to detect v3.10.3 database location on Windows
- Add logging for legacy path detection to aid debugging
* feat: init session manger
* feat: persist selected app to localStorage
- Save app selection when switching providers
- Restore last selected app on page load
* feat: persist current view to localStorage
- Save view selection when switching tabs
- Restore last selected view on page load
* styles: update ui
* feat: Improve macOS Terminal activation and refactor Kitty launch to use command with user's default shell.
* fix: session view
* feat: toc
* feat: Implement FlexSearch for improved session search functionality.
* feat: Redesign session manager search and filter UI for a more compact and dynamic experience.
* refactor: modularize session manager by extracting components and utility functions into dedicated files.
* feat: Enhance session terminal launching with support for iTerm2, Ghostty, WezTerm, and Alacritty, including UI and custom configuration options.
* feat: Conditionally render terminal selection and resume session buttons only on macOS.
Previously, check_claude_stream always added the x-api-key header,
ignoring the provider's auth_mode setting. This caused health check
failures for proxy services that only support Bearer authentication.
Now the function respects the auth.strategy field:
- AuthStrategy::Anthropic: Authorization Bearer + x-api-key
- AuthStrategy::ClaudeAuth: Authorization Bearer only
- AuthStrategy::Bearer: Authorization Bearer only
This aligns with the behavior of ClaudeAdapter::add_auth_headers
and fixes health checks for proxy providers with auth_mode="bearer_only".
Changes:
- Modified check_claude_stream to conditionally add x-api-key header
- Added AuthStrategy import
- Added test_auth_strategy_imports unit test
Tests: All passing (7/7 for stream_check module)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix(skills): handle Windows path separator in installed status matching
Use regex to split directory path by both / and \ to correctly extract
the install name on Windows, fixing the issue where installed skills
were not showing as installed in the discovery page filter.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(skills): add repository filter to skills discovery page
- Add dropdown to filter skills by repository (owner/name)
- Extract unique repos from discoverable skills list
- Add truncate style for long repo names with hover title
- Add i18n translations for zh/en/ja
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add apiHintOAI i18n key for OpenAI Chat Completions format hint
- Update ClaudeFormFields to show format-specific endpoint hints
- When API format is "openai_chat", show OAI-specific hint
- Maintains consistency between hint and selected API format
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add xdg-utils dependency for xdg-mime binary required by AppImage bundler
- Remove unused McpStatus struct from gemini_mcp.rs (duplicate of claude_mcp.rs)
- Add #![allow(dead_code)] to proxy models reserved for future type-safe API
- Add ubuntu-22.04-arm runner to build matrix
- Rename Linux artifacts with architecture suffix (x86_64/arm64)
- Update pnpm cache key with runner.arch to avoid cross-arch pollution
- Add linux-aarch64 platform to latest.json for Tauri updater
Provider add/update/delete mutations were using error.message directly,
which doesn't extract Tauri invoke errors properly. Now using the same
extractErrorMessage pattern as the rest of the codebase.
- Update version in package.json, Cargo.toml, and tauri.conf.json
- Add missing changelog entries for OpenCode API key link and AICodeMirror preset
- Fix Prettier formatting for new hook files
- Add OpenCode version detection with Go path scanning
- Add GitHub Releases API for fetching latest OpenCode version
- Add OpenCode install command to one-click install section
- Update i18n hints to include OpenCode across all locales
- Fix SettingsPage indentation formatting
Display an info toast when switching to a provider that uses OpenAI Chat
format (apiFormat === "openai_chat"), reminding users to enable the proxy
service. Move toast logic from mutation to useProviderActions for better
control over notification content based on provider properties.
The max_tokens restriction was too aggressive and should be handled
upstream or by the provider itself. Simplify anthropic_to_openai by
removing provider parameter since model mapping is already done by
proxy::model_mapper.
- Add NVIDIA NIM provider preset with API configuration
- Add nvidia.svg icon and register in icon system
- Add nvidia metadata with keywords and default color (#74B71B)
- Add model parameter to request logs for better debugging
- Fix duplicate /v1/v1 in URL when both base_url and endpoint have version
- Extend ?beta=true parameter to /v1/chat/completions endpoint
- Remove model mapping from transform layer (now handled by model_mapper)
- Add DeepSeek max_tokens clamping (1-8192 range)
Move api_format storage from settings_config to ProviderMeta to prevent
polluting ~/.claude/settings.json when switching providers.
- Add api_format field to ProviderMeta (Rust + TypeScript)
- Update ProviderForm to read/write apiFormat from meta
- Maintain backward compatibility for legacy settings_config.api_format
and openrouter_compat_mode fields (read-only fallback)
- Strip api_format from settings_config before writing to live config
Extend backward compatibility support for legacy openrouter_compat_mode field:
- Support number type (1 = enabled, 0 = disabled)
- Support string type ("true"/"1" = enabled)
- Add corresponding test cases for number and string types
Replace the OpenRouter-specific compatibility toggle with a generic
API format selector that allows all Claude providers to choose between:
- Anthropic Messages (native): Direct passthrough, no conversion
- OpenAI Chat Completions: Enables Anthropic ↔ OpenAI format conversion
Changes:
- Add ClaudeApiFormat type ("anthropic" | "openai_chat") to types.ts
- Replace openRouterCompatToggle with apiFormat dropdown in ClaudeFormFields
- Update ProviderForm to manage apiFormat state via settingsConfig.api_format
- Refactor claude.rs: add get_api_format() method, update needs_transform()
- Maintain backward compatibility with legacy openrouter_compat_mode field
- Update i18n translations (zh, en, ja)
- Add open_zip_file_dialog command for selecting ZIP files
- Add install_from_zip service method with recursive skill scanning
- Add install_skills_from_zip Tauri command
- Add frontend API methods and useInstallSkillsFromZip hook
- Add "Install from ZIP" button in Skills management page
- Support local skill ID format: local:{directory}
- Add i18n translations for new feature and error messages
- Move ~/.local/bin to first position in version scan search paths
- Update one-click install commands to use official native installation
(curl script) instead of npm for Claude Code
* fix(proxy): fix Codex 404 errors with custom base_url prefixes
- handlers.rs:268: Remove hardcoded /v1 prefix in Codex forwarding
- codex.rs:140: Only add /v1 for origin-only base_urls, dedupe /v1/v1
- stream_check.rs:364: Try /responses first, fallback to /v1/responses
- provider.rs:427: Don't force /v1 for custom prefix base_urls
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(codex): always add /v1 for custom prefix base_urls
Changed logic to always add /v1 prefix unless base_url already ends with /v1.
This fixes 504 timeout errors with relay services that expect /v1 in the path.
- Most relay services follow OpenAI standard format: /v1/responses
- Users can opt-out by adding /v1 to their base_url configuration
- Updated test case to reflect new behavior
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(proxy): allow system proxy on localhost with different ports
- Only bypass system proxy if it points to CC Switch's own port (15721)
- Allow other localhost proxies (e.g., Clash on 7890) to be used
- Add INFO level logging for request URLs to aid debugging
This fixes connection timeout issues when using local proxy tools.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(codex): don't add /v1 for custom prefix base_urls
Reverted logic to not add /v1 for base_urls with custom prefixes.
Many relay services use custom paths without /v1.
- Pure origin (e.g., https://api.openai.com) → adds /v1
- With /v1 (e.g., https://api.openai.com/v1) → no change
- Custom prefix (e.g., https://example.com/openai) → no /v1
This fixes 404 errors with relay services that don't use /v1 in their paths.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(proxy): use dynamic port for system proxy detection
Instead of hardcoding port 15721, now uses the actual configured
listen_port from proxy settings.
- Added set_proxy_port() to update the port when proxy server starts
- Added get_proxy_port() to retrieve current port for detection
- Updated server.rs to call set_proxy_port() on startup
- Updated tests to reflect new behavior
This allows users to change the proxy port in settings without
breaking the system proxy detection logic.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(proxy): change default proxy port from 15721 to 5000
Update the default fallback port in get_proxy_port() from 15721 to 5000
to match the project's standard default port configuration.
Also updated test cases to use port 5000 consistently.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(proxy): revert default port back to 15721
Revert the default fallback port in get_proxy_port() from 5000 back to 15721
to align with the project's updated default port configuration.
Also updated test cases to use port 15721 consistently.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: ozbombor <ozbombor@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Frontend fallback value for visibleApps had gemini: false, which was
inconsistent with backend default (gemini: true). This caused Gemini
to be hidden by default on first install.
Fixes#817
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Update Moonshot preset models from kimi-k2-thinking to kimi-k2.5
- Update OpenCode Kimi preset name and model to k2.5
- Remove explicit model config from Kimi preset (use API defaults)
- Establish proper flexbox height chain from App to SettingsPage
- Move save button to fixed footer outside scrollable area
- Align footer styling with FullScreenPanel for consistency
* feat(db): add pricing config fields to proxy_config table
- Add default_cost_multiplier field per app type
- Add pricing_model_source field (request/response)
- Add request_model field to proxy_request_logs table
- Implement schema migration v5
* feat(api): add pricing config commands and provider meta fields
- Add get/set commands for default cost multiplier
- Add get/set commands for pricing model source
- Extend ProviderMeta with cost_multiplier and pricing_model_source
- Register new commands in Tauri invoke handler
* fix(proxy): apply cost multiplier to total cost only
- Move multiplier calculation from per-item to total cost
- Add resolve_pricing_config for provider-level override
- Include request_model and cost_multiplier in usage logs
- Return new fields in get_request_logs API
* feat(ui): add pricing config UI and usage log enhancements
- Add pricing config section to provider advanced settings
- Refactor PricingConfigPanel to compact table layout
- Display all three apps (Claude/Codex/Gemini) in one view
- Add multiplier column and request model display to logs
- Add frontend API wrappers for pricing config
* feat(i18n): add pricing config translations
- Add zh/en/ja translations for pricing defaults config
- Add translations for multiplier, requestModel, responseModel
- Add provider pricing config translations
* fix(pricing): align backfill cost calculation with real-time logic
- Fix backfill to deduct cache_read_tokens from input (avoid double billing)
- Apply multiplier only to total cost, not to each item
- Add multiplier display in request detail panel with i18n support
- Use AppError::localized for backend error messages
- Fix init_proxy_config_rows to use per-app default values
- Fix silent failure in set_default_cost_multiplier/set_pricing_model_source
- Add clippy allow annotation for test mutex across await
* style: format code with cargo fmt and prettier
* fix(tests): correct error type assertions in proxy DAO tests
The tests expected AppError::InvalidInput but the DAO functions use
AppError::localized() which returns AppError::Localized variant.
Updated assertions to match the correct error type with key validation.
---------
Co-authored-by: Jason <farion1231@gmail.com>
Add additive mode support for OpenCode in sync_current_to_live:
- Add AppType::is_additive_mode() to distinguish switch vs additive mode
- Add AppType::all() iterator to avoid hardcoding app lists
- Add sync_all_providers_to_live() for additive mode apps
- Refactor sync_current_to_live to handle both modes
Frontend changes (directory settings):
- Track opencodeDirChanged in useDirectorySettings
- Trigger syncCurrentProvidersLiveSafe when OpenCode dir changes
- Add i18n strings for OpenCode directory settings
Follow-up to #644: Extract duplicate get_home_dir() implementations
into a single pub fn in config.rs, reducing code duplication across
codex_config.rs, gemini_config.rs, and settings.rs.
Also adds documentation comments to build.rs explaining the Windows
manifest workaround for test binaries.
Merge macOS Alacritty/Kitty/Ghostty launchers into a single generic
`launch_macos_open_app` function with a `use_e_flag` parameter.
Replace Windows cmd/PowerShell/wt launchers with a shared
`run_windows_start_command` helper. Reduces ~98 lines of duplicate code.
- Add directory conflict detection before installation
- Fix installed status check to match repo owner and name
- Add i18n translations for conflict error messages
- Replace blue dot indicator with lucide ArrowUpCircle icon
- Change color scheme from blue to green for better visibility
- Enlarge button (h-8 w-8) and icon (h-5 w-5) for better UX
- Move UpdateBadge from title area to after settings icon
- Add SyncMethod enum (Auto/Symlink/Copy) in Rust backend
- Implement sync_to_app_dir with symlink support (cross-platform)
- Add SkillSyncMethodSettings UI component (simplified 2-button selector)
- Add i18n support for zh/en/ja
- Replace copy_to_app with configurable sync_to_app_dir
- Add skill_sync_method field to AppSettings
User can now choose between symlink (disk space saving) or copy (best compatibility) in Settings > General.
When disabling a prompt, check if any other prompts remain enabled.
If all prompts are disabled, clear the prompt file to ensure UI state
matches the actual configuration that Claude Code reads.
Add `extra` field with serde flatten to OpenCodeModel struct to capture
custom fields like cost, modalities, thinking, and variants that were
previously lost during save operations.
Use lazy initialization in useState to parse model values from config
on first render, matching the pattern used in useApiKeyState. This
fixes an issue where model fields were not populated in edit mode.
- Bump version to 3.10.1 across all config files
- Update CHANGELOG with all fixes since v3.10.0
- Fix Rust Clippy warning by using derive(Default)
- Apply code formatting
Change the default state of the rectifier from enabled to disabled.
This allows users to opt-in to the rectifier feature rather than having it enabled by default.
Changes:
- Set RectifierConfig::default() enabled and request_thinking_signature to false
- Update serde default attributes from default_true to default
- Update unit tests to reflect new default behavior
- Import new detailed RC icon from rc.svg (128x128 viewBox)
- Add icon configuration to Claude provider preset
- Remove duplicate old RC icon definition to fix TS1117 error
Enhance the effectiveColor logic in ProviderIcon to properly validate
the color prop before using it. Now only uses color when it's a valid
non-empty string, otherwise falls back to icon metadata defaultColor.
This fixes the issue where Gemini icons would turn black when selected
in ProviderCard due to null/undefined/empty string color values being
passed through.
Use /K instead of /C flag to prevent cmd window from closing
immediately after batch file execution. Also remove the buggy
errorlevel check that was checking del command's return value
instead of claude's.
Fixes#726
OpenCode uses ~/.config/opencode on all platforms, not %APPDATA%\opencode
on Windows. Remove the platform-specific path handling to use unified
~/.config/opencode path across all operating systems.
Add max-w-[56rem] and mx-auto to Skills, MCP, and Prompts panels
to match the header layout constraints, ensuring the back button
and action buttons align with the content area.
- Add rc.svg for RightCode (optimized from 96KB to 581 bytes)
- Add catcoder.svg for KAT-Coder (快手)
- Add mcp.svg for Model Context Protocol
- Add siliconflow.svg for SiliconFlow
- Register all new icons in index.ts
- Add icon config for RightCode in claude/codex presets
- Add icon config for KAT-Coder in claude/opencode presets
- Fix SiliconFlow iconColor from #000000 to #6E29F6
- Add JimLiu/baoyu-skills to default skill repositories
- Change init_default_skill_repos() from "first-run only" to "supplement missing"
- New preset repos will now auto-appear for existing users on upgrade
When ProviderIcon is used without a color prop, it now automatically
fetches the defaultColor from icon metadata. This fixes the issue where
Gemini app icon turns black when selected in AppSwitcher, because the
component was inheriting the parent's text-foreground color.
Previously, enabling auto failover kept using the current provider until
the first failure, causing inconsistency when the current provider was
not in the failover queue. When stopping proxy, the restored config
would not match user expectations.
New behavior:
- Enable auto failover = immediately switch to queue P1
- Subsequent routing follows queue order (P1→P2→...)
- Auto-add current provider to queue if queue is empty
Changes:
- Add switch_proxy_target() for hot-switching during proxy mode
- Update provider_router to use queue order when failover enabled
- Sync tray menu Auto click with the same logic
- Update UI tooltips to reflect new semantics
- Add tests for queue-only routing scenario
- Format Rust code with rustfmt (misc.rs, types.rs)
- Format TypeScript/React code with Prettier (4 files)
- Fix ProviderList test by wrapping with QueryClientProvider
Allow users to choose which apps (Claude, Codex, Gemini, OpenCode) to display on the homepage.
- Add VisibleApps type and settings field in both frontend and backend
- Refactor AppSwitcher to render apps dynamically based on visibility
- Extract ToggleRow component for reuse
- Add i18n support for app visibility settings
* refactor(ui): simplify UpdateBadge to minimal dot indicator
* feat(provider): add individual test and proxy config for providers
Add support for provider-specific model test and proxy configurations:
- Add ProviderTestConfig and ProviderProxyConfig types in Rust and TypeScript
- Create ProviderAdvancedConfig component with collapsible panels
- Update stream_check service to merge provider config with global config
- Proxy config UI follows global proxy style (single URL input)
Provider-level configs stored in meta field, no database schema changes needed.
* feat(ui): add failover toggle and improve proxy controls
- Add FailoverToggle component with slide animation
- Simplify ProxyToggle style to match FailoverToggle
- Add usage statistics button when proxy is active
- Fix i18n parameter passing for failover messages
- Add missing failover translation keys (inQueue, addQueue, priority)
- Replace AboutSection icon with app logo
* fix(proxy): support system proxy fallback and provider-level proxy config
- Remove no_proxy() calls in http_client.rs to allow system proxy fallback
- Add get_for_provider() to build HTTP client with provider-specific proxy
- Update forwarder.rs and stream_check.rs to use provider proxy config
- Fix EditProviderDialog.tsx to include provider.meta in useMemo deps
- Add useEffect in ProviderAdvancedConfig.tsx to sync expand state
Fixes#636Fixes#583
* fix(ui): sync toast theme with app setting
* feat(settings): add log config management
Fixes#612Fixes#514
* fix(proxy): increase request body size limit to 200MB
Fixes#666
* docs(proxy): update timeout config descriptions and defaults
Fixes#612
* fix(proxy): filter x-goog-api-key header to prevent duplication
* fix(proxy): prevent proxy recursion when system proxy points to localhost
Detect if HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY environment variables
point to loopback addresses (localhost, 127.0.0.1), and bypass system
proxy in such cases to avoid infinite request loops.
* fix(i18n): add providerAdvanced i18n keys and fix failover toast parameter
- Add providerAdvanced.* i18n keys to en.json, zh.json, and ja.json
- Fix failover toggleFailed toast to pass detail parameter
- Remove Chinese fallback text from UI for English/Japanese users
* fix(tray): restore tray-provider events and enable Auto failover properly
- Emit provider-switched event on tray provider click (backward compatibility)
- Auto button now: starts proxy, takes over live config, enables failover
* fix(log): enable dynamic log level and single file mode
- Initialize log at Trace level for dynamic adjustment
- Change rotation strategy to KeepSome(1) for single file
- Set max file size to 1GB
- Delete old log file on startup for clean start
* fix(tray): fix clippy uninlined format args warning
Use inline format arguments: {app_type_str} instead of {}
* fix(provider): allow typing :// in endpoint URL inputs
Change input type from "url" to "text" to prevent browser
URL validation from blocking :// input.
Closes#681
* fix(stream-check): use Gemini native streaming API format
- Change endpoint from OpenAI-compatible to native streamGenerateContent
- Add alt=sse parameter for SSE format response
- Use x-goog-api-key header instead of Bearer token
- Convert request body to Gemini contents/parts format
* feat(proxy): add request logging for debugging
Add debug logs for outgoing requests including URL and body content
with byte size, matching the existing response logging format.
* fix(log): prevent usize underflow in KeepSome rotation strategy
KeepSome(n) internally computes n-2, so n=1 causes underflow.
Use KeepSome(2) as the minimum safe value.
Add support for configuring per-model options like provider routing.
Each model row now has an expand/collapse toggle to show a key-value
editor for model-specific options (e.g., provider order, fallbacks).
- Add options field to OpenCodeModel in Rust and TypeScript
- Add expandable key-value editor UI for each model
- Use local state pattern for option key input to prevent focus loss
- Add i18n translations for zh/en/ja
Add key-value pair editor for configuring additional SDK options like
timeout, setCacheKey, etc. Values are automatically parsed to appropriate
types (number, boolean, object) on save.
- Add `extra` field with serde flatten in Rust backend
- Add index signature to OpenCodeProviderOptions type
- Create ExtraOptionKeyInput component with local state pattern
- Place extra options section above models configuration
Use local state + onBlur pattern for ModelIdInput to keep React key
stable during editing. Previously, each keystroke changed the object
key, causing React to unmount/remount the input and lose focus.
OpenCode lacks a dedicated adapter and falls back to Codex adapter,
which has incompatible config structure. Hide the test button in UI
to prevent users from triggering unsupported operations.
OpenCode uses user-provided provider keys as IDs instead of random UUIDs.
When duplicating a provider, generate a unique key by appending "-copy"
suffix (or "-copy-2", "-copy-3", etc. if already exists).
Add startup import logic for OpenCode providers and MCP servers.
Unlike other apps that use replacement mode, OpenCode uses additive
mode where multiple providers can coexist in the config file.
- Add Provider Key input field for OpenCode providers (between icon and name)
- User must manually enter a unique key instead of auto-generating from name
- Real-time validation: format check and duplicate detection
- Key is immutable after creation (disabled in edit mode)
- Remove slugify auto-generation logic from mutations
- Add beforeNameSlot prop to BasicFormFields for extensibility
- Add i18n translations for zh/en/ja
- Create separate removeFromLiveConfig API for additive mode apps
(remove only removes from live config, not database)
- Fix useSwitchProviderMutation to invalidate opencodeLiveProviderIds
cache so button state updates correctly after add operation
- Show appropriate toast messages:
- Add: "已添加到配置" / "Added to config"
- Remove: "已从配置移除" / "Removed from config"
- Add i18n texts for addToConfigSuccess and removeFromConfigSuccess
Separate the confirmation dialogs for "remove from config" and "delete
provider" operations in OpenCode mode to help users understand the
different impacts of each action.
For OpenCode (additive mode), use isInConfig instead of isCurrent to
determine whether to enable usage auto-query. This allows providers
that have been added to the config to have their usage queried
automatically.
OpenCode uses additive mode where the main "Remove" button removes from
live config, while the delete button should delete from database. The
delete button should always be enabled for OpenCode providers.
OpenCode uses additive mode where all providers coexist in config file,
so there's no "current" provider concept. This commit:
- Skip setting is_current in switch_normal for OpenCode
- Return empty string from ProviderService::current for OpenCode
- Disable active provider highlight in ProviderCard for OpenCode
Previously Base URL was only shown for @ai-sdk/openai-compatible.
Now it's always visible to support proxy scenarios for official SDKs
like DeepSeek, Anthropic, etc.
OpenCode's read_live_settings returns the full opencode.json file
instead of just the provider fragment. This caused the edit dialog
to save the complete config structure as settingsConfig, creating
nested provider configurations.
For OpenCode's additive mode, use DB config directly since each
provider's config is stored independently.
- Skip backfill logic for OpenCode (additive mode doesn't need it)
- Add defensive check in write_live_snapshot to extract provider fragment
- Use slugified name as provider ID for readable config keys
- Add 19 new provider presets for OpenCode (cn_official, aggregator, third_party)
- Add OpenCode handling branch in handlePresetChange to properly populate
form fields (baseURL, apiKey, npm, models) when selecting a preset
- Add OpenCode reset logic in custom mode branch
Add missing OpenCode branch in parse_app_type() and include OpenCode
in all app iteration loops for skills operations (uninstall, scan,
import, migrate).
- Add `enabled` parameter to useCommonConfigSnippet hook
- Skip all loading and auto-merge logic when enabled=false
- Replace CommonConfigEditor with simplified JsonEditor for OpenCode
- Prevent Claude's common config snippet from being injected into OpenCode
- Increase SelectContent z-index from z-50 to z-[100] to appear above FullScreenPanel (z-[60])
- Replace form.watch() with form.getValues() in useCallback handlers for correct react-hook-form usage
- Remove max-w-[56rem] constraints from various panels for consistent full-width layout
Remove dead code that was never called after v3.7.0 architecture change:
- mcp/opencode.rs: sync_enabled_to_opencode, collect_enabled_servers
- opencode_config.rs: 8 unused utility functions
- provider.rs: OpenCodeProviderConfig impl block (4 methods)
These functions were designed for batch operations but McpService uses
per-server sync pattern instead. No functionality affected.
- Add opencode to AppType and SkillApps interfaces in skills.ts
- Add OpenCode Switch component to UnifiedMcpPanel list items
- Add OpenCode Switch component to UnifiedSkillsPanel list items
- Include OpenCode in enabled counts and header statistics for both panels
OpenCode uses additive provider management where providers can exist in
the database but not necessarily in the live opencode.json config. This
commit implements proper isInConfig state:
Backend:
- Add get_opencode_live_provider_ids command to query live config
Frontend:
- Add getOpenCodeLiveProviderIds API method
- ProviderList queries live provider IDs and computes isInConfig
- ProviderCard receives and passes isInConfig to ProviderActions
- ProviderActions already handles the add/remove button logic
OpenCode uses additive provider management (multiple providers coexist),
so proxy/failover features are not applicable. This commit:
- Conditionally renders ProxyToggle only for non-OpenCode apps
- Fixes toast message label to properly handle opencode app type
- Fix MCP server not removed from opencode.json when unchecked in edit modal
- Fix Windows atomic write failure when opencode.json already exists
- Fix i18n keys mismatch in OpenCodeFormFields (use opencode.* namespace)
- Fix unit test missing apps.opencode field assertion
- Add import_opencode_providers_from_live command to provider.rs
- Register new command in lib.rs invoke_handler
- Update commands/mcp.rs: include OpenCode in sync_other_side logic
- Add McpService::import_from_opencode to import_mcp_from_apps
- Implement MCP sync/remove for OpenCode in services/mcp.rs
- sync_server_to_app_no_config now calls sync_single_server_to_opencode
- remove_server_from_app now calls remove_server_from_opencode
Implement OpenCode-specific provider service logic with additive mode:
- add(): Always write to live config (no is_current check needed)
- update(): Always sync changes to live config
- delete(): Remove from both DB and live config (no is_current check)
New helper functions in live.rs:
- write_live_snapshot(): Write provider to opencode.json provider section
- remove_opencode_provider_from_live(): Remove provider from live config
- import_opencode_providers_from_live(): Import existing providers from
~/.config/opencode/opencode.json into CC Switch database
Key design: OpenCode uses additive mode where all providers coexist
in the config file, unlike Claude/Codex/Gemini which use replacement
mode with a single active provider.
Add mcp/opencode.rs with format conversion between CC Switch and OpenCode:
- stdio ↔ local type conversion
- command+args ↔ command array format
- env ↔ environment field mapping
- sse/http ↔ remote type conversion
Public API:
- sync_enabled_to_opencode: Batch sync all enabled servers
- sync_single_server_to_opencode: Sync individual server
- remove_server_from_opencode: Remove from live config
- import_from_opencode: Import servers from OpenCode config
Also fix test files to include new opencode field in McpApps struct.
All 4 unit tests pass for format conversion.
Add OpenCode-specific configuration structures for the AI SDK format:
- OpenCodeProviderConfig: Main config with npm package, options, and models
- OpenCodeProviderOptions: baseURL, apiKey, and headers support
- OpenCodeModel: Model definition with name and token limits
- OpenCodeModelLimit: Context and output token limits
Key features:
- Supports environment variable references (e.g., "{env:API_KEY}")
- Custom headers support for specialized providers
- Model-level token limits for context management
- Helper methods for parsing and validation
Add OpenCode as the 4th supported application with additive provider management:
- Add OpenCode variant to AppType enum with all related match statements
- Add enabled_opencode field to McpApps and SkillApps structures
- Add opencode field to McpRoot and PromptRoot
- Add database schema migration v3→v4 with enabled_opencode columns
- Add settings.rs support for opencode_config_dir and current_provider_opencode
- Create opencode_config.rs module for config file I/O operations
- Update all services (proxy, mcp, skill, provider, stream_check) for OpenCode
- Add OpenCode support to deeplink provider and MCP parsing
- Update commands/config.rs for OpenCode config status and paths
Key design decisions:
- OpenCode uses additive mode (no is_current needed, no proxy support)
- Config path: ~/.config/opencode/opencode.json
- MCP format: stdio→local, sse/http→remote conversion planned
- Stream check returns error (not yet implemented for OpenCode)
* feat(usage): improve custom template with variables display and explicit type detection
Combine two feature improvements:
1. Display supported variables ({{baseUrl}}, {{apiKey}}) with actual values in custom template mode
2. Add explicit templateType field for accurate template mode detection
## Changes
### Frontend
- Display template variables with actual values extracted from provider settings
- Add templateType field to UsageScript for explicit mode detection
- Support template mode persistence across sessions
### Backend
- Add template_type field to UsageScript struct
- Improve validation logic based on explicit template type
- Maintain backward compatibility with type inference
### I18n
- Add "Supported Variables" section translation (zh/en/ja)
### Benefits
- More accurate template mode detection (no more guessing)
- Better user experience with variable hints
- Clearer validation rules per template type
* fix(usage): resolve custom template cache and validation issues
Combine three bug fixes to make custom template mode work correctly:
1. **Update cache after test**: Testing usage script successfully now updates the main list cache immediately
2. **Fix same-origin check**: Custom template mode can now access different domains (SSRF protection still active)
3. **Fix field naming**: Unified to use autoQueryInterval consistently between frontend and backend
## Problems Solved
- Main provider list showing "Query failed" after successful test
- Custom templates blocked by overly strict same-origin validation
- Auto-query intervals not saved correctly due to inconsistent naming
## Changes
### Frontend (UsageScriptModal)
- Import useQueryClient and update cache after successful test
- Invalidate usage cache when saving script configuration
- Use standardized autoQueryInterval field name
### Backend (usage_script.rs)
- Allow custom template mode to bypass same-origin checks
- Maintain SSRF protection for all modes
### Hooks (useProviderActions)
- Invalidate usage query cache when saving script
## Impact
Users can now use custom templates freely while security validations remain intact for general templates.
* fix(usage): correct provider credential field names
- Claude: support both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN
- Gemini: use GEMINI_API_KEY instead of GOOGLE_GEMINI_API_KEY
- Codex: use OPENAI_API_KEY and parse base_url from TOML config string
Addresses review feedback from PR #628
* style: format code
---------
Co-authored-by: Jason <farion1231@gmail.com>
* feat(proxy): add thinking signature rectifier for Claude API
Add automatic request rectification when Anthropic API returns signature
validation errors. This improves compatibility when switching between
different Claude providers or when historical messages contain incompatible
thinking block signatures.
- Add thinking_rectifier.rs module with trigger detection and rectification
- Integrate rectifier into forwarder error handling flow
- Remove thinking/redacted_thinking blocks and signature fields on retry
- Delete top-level thinking field when assistant message lacks thinking prefix
* fix(proxy): complete rectifier retry path with failover switch and chain continuation
- Add failover switch trigger on rectifier retry success when provider differs from start
- Replace direct error return with error categorization on rectifier retry failure
- Continue failover chain for retryable errors instead of terminating early
* feat(proxy): add rectifier config with master switch
- Add RectifierConfig struct with enabled and requestThinkingSignature fields
- Update should_rectify_thinking_signature to check master switch first
- Add tests for master switch functionality
* feat(db): add rectifier config storage in settings table
Store rectifier config as JSON in single key for extensibility
* feat(commands): add get/set rectifier config commands
* feat(ui): add rectifier config panel in advanced settings
- Add RectifierConfigPanel component with master switch and thinking signature toggle
- Add API wrapper for rectifier config
- Add i18n translations for zh/en/ja
* feat(proxy): integrate rectifier config into request forwarding
- Load rectifier config from database in RequestContext
- Pass config to RequestForwarder for runtime checking
- Use should_rectify_thinking_signature with config parameter
* test(proxy): add nested JSON error detection test for thinking rectifier
* fix(proxy): resolve HalfOpen permit leak and RectifierConfig default values
- Fix RectifierConfig::default() to return enabled=true (was false due to derive)
- Add release_permit_neutral() for releasing permits without affecting health stats
- Fix 3 permit leak points in rectifier retry branches
- Add unit tests for default values and permit release
* style(ui): format ProviderCard style attribute
* fix(rectifier): add detection for signature field required error
Add support for detecting "signature: Field required" error pattern
in the thinking signature rectifier. This enables automatic request
rectification when upstream API returns this specific validation error.
Replace Dialog component with FullScreenPanel in PricingEditModal
to match the UI style of other edit dialogs (provider, MCP).
Changes:
- Switch from small centered Dialog to full-screen panel
- Add back button in header and fixed footer for actions
- Add Save/Plus icons to submit button
* feat(misc): add WSL tool version detection with security hardening (#608)
- Add WSL distro detection from UNC path (wsl$/wsl.localhost)
- Add distro name validation to prevent command injection
- Add defensive assertion for tool parameter
- Unify cfg macros to target_os = "windows"
- Standardize error message format to [WSL:{distro}]
Closes#608
* fix(misc): add CREATE_NO_WINDOW flag and unify error messages to English
- Add CREATE_NO_WINDOW flag to wsl.exe command to prevent console window flash
- Standardize error messages from Chinese to English for consistency
---------
Co-authored-by: Jason <farion1231@gmail.com>
- Add configurable test prompt field to StreamCheckConfig
- Implement Claude CLI-compatible request format with proper headers:
- Authorization + x-api-key dual auth
- anthropic-beta, anthropic-version headers
- x-stainless-* SDK headers with dynamic OS/arch detection
- URL with ?beta=true parameter
- Implement Codex CLI-compatible Responses API format:
- /v1/responses endpoint
- input array format with reasoning effort support
- codex_cli_rs user-agent and originator headers
- Add dynamic OS name and CPU architecture detection
- Internationalize error messages (Chinese -> English)
- Add test prompt Textarea UI component with i18n support
- Remove obsolete testPromptDesc translation key
* refactor(proxy): simplify logging for better readability
- Delete 17 verbose debug logs from handlers, streaming, and response_processor
- Convert excessive INFO logs to DEBUG level for internal processing details
- Add 2 critical INFO logs in forwarder.rs for failover scenarios:
- Log when switching to next provider after failure
- Log when all providers have been exhausted
- Fix clippy uninlined_format_args warning
This reduces log noise while maintaining visibility into key user-facing decisions.
* fix: replace unsafe unwrap() calls with proper error handling
- database/dao/mcp.rs: Use map_err for serde_json serialization
- database/dao/providers.rs: Use map_err for settings_config and meta serialization
- commands/misc.rs: Use expect() for compile-time regex pattern
- services/prompt.rs: Use unwrap_or_default() for SystemTime
- deeplink/provider.rs: Replace unwrap() with is_none_or pattern for Option checks
Reduces potential panic points from 26 to 1 (static regex init, safe).
* refactor(proxy): simplify verbose logging output
- Remove response JSON full output logging in response_processor
- Remove per-request INFO logs in provider_router (failover status, provider selection)
- Change model mapping log from INFO to DEBUG
- Change usage logging failure from INFO to WARN
- Remove redundant debug logs for circuit breaker operations
Reduces log noise significantly while preserving important warnings and errors.
* feat(proxy): add structured log codes for i18n support
Add error code system to proxy module logs for multi-language support:
- CB-001~006: Circuit breaker state transitions and triggers
- SRV-001~004: Proxy server lifecycle events
- FWD-001~002: Request forwarding and failover
- FO-001~005: Failover switch operations
- USG-001~002: Usage logging errors
Log format: [CODE] Chinese message
Frontend/log tools can map codes to any language.
New file: src/proxy/log_codes.rs - centralized code definitions
* chore: bump version to 3.9.1
* style: format code with prettier and rustfmt
* fix(ui): allow number inputs to be fully cleared before saving
- Convert numeric state to string type for controlled inputs
- Use isNaN() check instead of || fallback to allow 0 values
- Apply fix to ProxyPanel, CircuitBreakerConfigPanel,
AutoFailoverConfigPanel, and ModelTestConfigPanel
* feat(pricing): support @ separator in model name matching
- Refactor model name cleaning into chained method calls
- Add @ to - replacement (e.g., gpt-5.2-codex@low → gpt-5.2-codex-low)
- Add test case for @ separator matching
* feat(proxy): add global proxy settings support
Add ability to configure a global HTTP/HTTPS proxy for all outbound
requests including provider API calls, speed tests, and stream checks.
* fix(proxy): improve validation and error handling in proxy config panels
- Add StopTimeout/StopFailed error types for proper stop() error reporting
- Replace silent clamp with validation-and-block in config panels
- Add listenAddress format validation in ProxyPanel
- Use log_codes constants instead of hardcoded strings
- Use once_cell::Lazy for regex precompilation
* fix(proxy): harden error handling and input validation
- Handle RwLock poisoning in settings.rs with unwrap_or_else
- Add fallback for dirs::home_dir() in config modules
- Normalize localhost to 127.0.0.1 in ProxyPanel
- Format IPv6 addresses with brackets for valid URLs
- Strict port validation with pure digit regex
- Treat NaN as validation failure in config panels
- Log warning on cost_multiplier parse failure
- Align timeoutSeconds range to [0, 300] across all panels
* feat(proxy): add local proxy auto-scan and fix hot-reload
- Add scan_local_proxies command to detect common proxy ports
- Fix SkillService not using updated proxy after hot-reload
- Move global proxy settings to advanced tab
- Add error handling for scan failures
* fix(proxy): allow localhost input in proxy address field
* fix(proxy): restore request timeout and fix proxy hot-reload issues
- Add URL scheme validation in build_client (http/https/socks5/socks5h)
- Restore per-request timeout for speedtest, stream_check, usage_script, forwarder
- Fix set_global_proxy_url to validate before persisting to DB
- Mask proxy credentials in all log outputs
- Fix forwarder hot-reload by fetching client on each request
* style: format code with prettier
* fix(proxy): improve global proxy stability and error handling
- Fix RwLock silent failures with explicit error propagation
- Handle init() duplicate calls gracefully with warning log
- Align fallback client config with build_client settings
- Make scan_local_proxies async to avoid UI blocking
- Add mixed mode support for Clash 7890 port (http+socks5)
- Use multiple test targets for better proxy connectivity test
- Clear invalid proxy config on init failure
- Restore timeout constraints in usage_script
- Fix mask_url output for URLs without port
- Add structured error codes [GP-001 to GP-009]
* feat(proxy): add username/password authentication support
- Add separate username and password input fields
- Implement password visibility toggle with eye icon
- Add clear button to reset all proxy fields
- Auto-extract auth info from saved URL and merge on save
- Update i18n translations (zh/en/ja)
* fix(proxy): fix double encoding issue in proxy auth and add debug logs
- Remove encodeURIComponent in mergeAuth() since URL object's
username/password setters already do percent-encoding automatically
- Add GP-010 debug log for database read operations
- Add GP-011 debug log to track incoming URL info (length, has_auth)
- Fix username.trim() in fallback branch for consistent behavior
2026-01-13 10:55:53 +08:00
616 changed files with 117517 additions and 13539 deletions
@@ -5,7 +5,683 @@ 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).
## [Unreleased]
## [3.13.0] - 2026-04-10
Development since v3.12.3 focuses on quota visibility, provider workflow upgrades, stronger proxy compatibility, and lower-overhead tray / session workflows.
### Added
- **Lightweight Mode**: Added a tray-only mode that destroys the main window and keeps CC Switch running from the system tray, with the window recreated when users reopen it.
- **Provider Model Auto-Fetch**: Added OpenAI-compatible `/v1/models` discovery for Claude, Codex, Gemini, OpenCode, and OpenClaw provider forms, including grouped dropdown selection and failure-specific error messages.
- **Quota & Balance Visibility**: Added inline quota or balance display for official Claude / Codex / Gemini providers, GitHub Copilot premium interactions, Codex OAuth providers, Token Plan providers (Kimi / Zhipu GLM / MiniMax), and official balance queries for DeepSeek, StepFun, SiliconFlow, OpenRouter, and Novita AI. Copilot / ChatGPT OAuth and CLI subscription quota now only auto-poll for the currently active provider, preventing unnecessary API calls and misleading displays on non-current cards.
- **Skills Discovery & Batch Updates**: Added SHA-256 based skill update detection, per-skill and batch update actions, a storage-location toggle between CC Switch and `~/.agents/skills`, and public `skills.sh` search integration.
- **Session Workflow Upgrades**: Added batch delete in Session Manager, a directory picker before launching Claude terminal restore commands, usage import from Claude / Codex / Gemini session logs without requiring proxy interception, and per-app usage filtering for Claude / Codex / Gemini dashboards.
- **Codex OAuth Reverse Proxy**: Added ChatGPT Plus / Pro based Codex OAuth reverse proxy support for Claude provider cards, including managed OAuth login and inline subscription quota display.
- **OpenCode / OpenClaw Stream Check Coverage**: Added OpenCode npm package mapping plus support for OpenClaw `openai-completions` and the remaining OpenClaw protocol variants in Stream Check.
- **Full URL Endpoint Mode**: Added a provider option that treats `base_url` as a complete upstream endpoint so proxy forwarding and stream checks can work with vendors that require nonstandard URL layouts.
- **OpenCode StepFun Step Plan Preset**: Added a StepFun Step Plan provider preset for OpenCode.
- **Copilot Interaction Optimizer**: Added request classification and routing logic to reduce unnecessary GitHub Copilot premium interaction consumption.
- **First-Run Welcome Dialog**: Added a one-time welcome dialog on fresh installs explaining how existing configuration is preserved as a default provider and how the bundled official preset enables one-click revert. Upgrade users are excluded.
- **Official Provider Seeding**: Added automatic seeding of Claude Official, OpenAI Official, and Google Official provider entries on startup, giving every user a one-click path back to the official endpoint.
- **OpenCode / OpenClaw Auto-Import**: Added automatic startup import of live OpenCode and OpenClaw provider configurations, matching the auto-import behavior already present for Claude, Codex, and Gemini.
- **Common Config Editor Guidance**: Added an informational guide and empty-state prompt to the Common Config snippet editor modal for Claude, Codex, and Gemini, with i18n support.
- **Common Config First-Run Notice**: Added a one-time informational dialog explaining Common Config Snippets when users first open the provider add/edit form.
- **Claude Session Titles**: Added meaningful title extraction for Claude sessions using a priority chain: custom-title metadata, first real user message, then directory basename fallback.
- **Session Search Highlighting**: Added keyword highlighting in session titles and messages during Session Manager search.
- **URL-Based Provider Icons**: Added a dual rendering mode to the icon system supporting Vite URL imports for large SVGs and raster images (PNG, JPG, WebP), keeping small SVGs inlined.
- **Kaku Terminal Support**: Added Kaku as a selectable terminal for session launch on macOS, reusing the WezTerm-compatible launch path.
- **OMO Slim Council Support**: Restored first-class council support as a built-in oh-my-opencode-slim agent with updated metadata and UI copy.
- **TheRouter Provider Preset**: Added TheRouter provider presets across Claude, Codex, Gemini, OpenCode, and OpenClaw.
- **DDSHub Provider Preset**: Added DDSHub as a third-party partner provider for Claude with icon and partner promotion text.
- **LionCCAPI Provider Preset**: Added LionCCAPI as a third-party partner provider across all five apps with anthropic-messages protocol for OpenCode and OpenClaw.
- **Shengsuanyun Provider Preset**: Added Shengsuanyun (胜算云) as an aggregator partner provider across all five apps with URL-based icon and localized display name.
- **PIPELLM Provider Preset**: Added PIPELLM provider preset across Claude, Codex, OpenCode, and OpenClaw with full model definitions and icon.
- **E-FlowCode Provider Preset**: Added E-FlowCode provider preset across all five apps with per-app protocol configuration.
### Changed
- **Tray Menu Organization**: Reworked the tray menu into per-app submenus to prevent overflow and make background provider switching scale better with larger provider lists.
- **Proxy Forwarding Stack**: Refactored proxy forwarding onto a Hyper-based client with transparent header forwarding, improved endpoint rewriting, and better support for dynamic upstream endpoints.
- **OAuth Auth Center UI Polish**: Tightened the Auth Center copy, layout, and icon presentation so the Codex OAuth login flow feels cleaner and less cluttered.
- **Provider Key Lifecycle & Live Sync**: Reworked additive provider create / rename / duplicate flows so live config writes, cleanup, and rollback stay consistent across OpenCode / OpenClaw and takeover scenarios.
- **Codex OAuth Defaults**: Updated the Codex OAuth preset to the GPT-5.4 model family.
### Fixed
- **Copilot Authentication & Proxy Compatibility**: Fixed GitHub Copilot authentication regressions, corrected enterprise / dynamic endpoint handling, repaired clipboard verification-code copying on macOS and Linux, and fixed Responses routing when Copilot-backed Claude providers target OpenAI models.
- **Streaming Parser Compatibility**: Fixed SSE parsing to accept fields with optional spaces, improving compatibility with non-strict streaming implementations.
- **UTF-8 Stream Chunk Boundaries**: Fixed intermittent garbled output (U+FFFD replacement characters) in Claude Code when multi-byte UTF-8 sequences such as Chinese characters or emoji were split across TCP stream chunks via the Copilot reverse proxy, by preserving incomplete trailing bytes across chunks in all four SSE streaming paths instead of lossy decoding.
- **Fragmented System Prompt Normalization**: Fixed strict OpenAI-compatible chat backends (Nvidia, Qwen-style) rejecting requests when converted Claude payloads contained multiple system messages, by merging system content into a single leading system message during the Anthropic → OpenAI chat transformation.
- **Provider Switch State Corruption**: Serialized per-app provider switches to prevent concurrent failover or hot-switch operations from leaving `is_current`, settings state, and live backup state out of sync.
- **Claude Takeover Live Config Drift**: Fixed provider edits while Claude takeover is active so live settings remain aligned with the latest provider state without breaking takeover restore behavior.
- **WebDAV Password Retention & Validation**: Fixed the WebDAV password field so saved credentials remain visible after refresh and treated `MKCOL 405` responses correctly during connection validation.
- **Provider Card Action States**: Fixed additive-mode highlight behavior, aligned usage display layout across provider cards, replaced hard proxy-switch blocking with a warning path, and disabled unsupported test / usage actions for Copilot and Codex OAuth cards.
- **Usage Accuracy & Pricing**: Fixed MiniMax quota math and 0%→100% progression, corrected CNY→USD pricing plus missing model definitions, improved Gemini session-log syncing, and resolved session-based usage entries being shown as unknown providers.
- **Usage Editor & Skills UI Regressions**: Fixed usage query fields being reset while editing extractor code, corrected broken `skills.sh` links and empty descriptions, and fixed auto-query defaults plus number-input clearing in usage configuration.
- **Chinese Skills Terminology**: Unified Skills-related labels across settings panels in the `zh` locale so storage and sync options use consistent wording.
- **Environment & Preset Compatibility**: Added Bun global bin detection in CLI scan, adapted to the oh-my-openagent rename with backward compatibility, corrected the OpenCode `kimi-for-coding` preset, gated Gemini keychain parsing to macOS, and fixed an OpenClaw serializer panic on empty collections.
- **Linux UI Unresponsive on Startup**: Fixed a bug where the window UI (including native title bar buttons) couldn't receive clicks on Linux until the user manually maximized and restored the window. Root causes: (1) Tauri webview did not acquire keyboard focus after `show()` on Linux, so the first click was consumed by X11/Wayland click-to-activate (Tauri #10746, wry #637); (2) GTK surface's input region failed to renegotiate on the `visible:false → show()` path under some WebKitGTK/compositor combinations, leaving the entire window unresponsive. Mitigations: set `WEBKIT_DISABLE_COMPOSITING_MODE=1` at startup, and added a new `linux_fix::nudge_main_window` helper that performs `set_focus` + a ±1px no-op resize ~200ms after show, equivalent to a visually invisible "maximize-and-restore". Wired into all window-re-show paths (normal startup, deeplink, single_instance, tray `show_main`, lightweight exit).
- **Linux Drag Region on Header**: Removed `data-tauri-drag-region` from the top header bar on Linux to avoid triggering `gtk_window_begin_move_drag` paths affected by Tauri #13440 under Wayland. macOS drag behavior is preserved.
- **Duplicate Toast on Provider Switch**: Fixed double toast notifications (proxy-required warning followed by switch-success) when switching to Copilot, ChatGPT, or OpenAI-format providers with the proxy not running.
- **Session Search Accuracy & Chinese Support**: Fixed session search result truncation across providers and switched FlexSearch tokenizer to full mode for proper Chinese substring matching.
- **Adaptive Thinking Reasoning Effort**: Fixed `resolve_reasoning_effort()` mapping adaptive thinking to `xhigh` instead of incorrectly using `high` in OpenAI format conversions.
- **Thinking Model Fallback Display**: Fixed the Claude provider form showing an empty Thinking model field after saving only a main model by applying read-only fallback to ANTHROPIC_MODEL.
- **Auth Tab Localization**: Fixed missing i18n translation keys for the settings auth tab label across all locale bundles.
- **Schema Migration Guard**: Fixed database migrations failing when skills or model_pricing tables did not exist by adding table-existence checks before ALTER and UPDATE operations.
### Docs
- **User Manual Refresh**: Updated the EN / ZH / JA manuals for tray submenus, lightweight mode, provider model fetching, session management, workspace files, WebDAV v2 behavior, OpenCode / OpenClaw activation, and other provider workflow improvements.
- **Community & Contribution Docs**: Added `CONTRIBUTING.md`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, bilingual issue / PR templates, Dependabot config, and CI quality checks.
- **Release Notes Risk Notice**: Added a Copilot reverse proxy risk notice and anchored highlight links in the v3.12.3 release notes across all three languages.
- **Sponsor Partners**: Added Shengsuanyun, LionCC, and DDS as sponsor partners in README across all languages.
---
## [3.12.3] - 2026-03-24
Major release adding GitHub Copilot reverse proxy support, macOS code signing & Apple notarization, intelligent reasoning effort mapping for o-series models, skill backup/restore lifecycle, proxy gzip compression, and critical fixes for WebDAV password safety, tool message parsing, and dark mode.
- **GitHub Copilot Reverse Proxy**: Full GitHub Copilot integration as a Claude Code provider via OAuth Device Code flow; includes multi-account management, automatic token refresh, Anthropic ↔ OpenAI format conversion, real-time model list fetching, and usage statistics (#930)
- **Copilot Auth Center**: New Auth Center panel in Settings for managing GitHub accounts globally, with per-provider account binding via `meta.authBinding`
- **Tool Search Toggle**: Added `ENABLE_TOOL_SEARCH` env var support for Claude 2.1.76+; exposed as a checkbox in the provider Common Config editor (#930)
- **Reasoning Effort Mapping**: Two-tier `resolve_reasoning_effort()` for OpenAI o-series and GPT-5+ models — explicit `output_config.effort` takes priority, falling back to thinking `budget_tokens` thresholds (<4 000→low, 4 000–16 000→medium, ≥16 000→high); covers both Chat Completions and Responses API paths with 17 unit tests
- **OpenCode SQLite Backend**: Added SQLite session storage support for OpenCode alongside existing JSON backend; dual-backend scan with SQLite priority on ID conflicts, atomic session deletion, and path validation (#1401)
- **Skill Auto-Backup**: Skill files are automatically backed up to `~/.cc-switch/skill-backups/` before uninstall, with metadata preserved in `meta.json`; old backups pruned to keep at most 20
- **Skill Backup Restore & Delete**: Added list/restore/delete commands for skill backups; restore copies files back to SSOT, saves the DB record, and syncs to the current app with rollback on failure
- **macOS Code Signing & Notarization**: CI now imports an Apple Developer ID certificate, signs the universal binary, submits for Apple notarization, and staples the ticket to both `.app` and `.dmg`; a hard-fail verification step (`codesign --verify` + `spctl -a` + `stapler validate`) gates the release for both artifacts
- **Codex 1M Context Window Toggle**: One-click checkbox in Codex config editor to set `model_context_window = 1000000` with auto-populated `model_auto_compact_token_limit = 900000`; unchecking removes both fields
- **Disable Auto-Upgrade Toggle**: Added `DISABLE_AUTOUPDATER` env var checkbox in the Claude Common Config editor to prevent Claude Code from auto-upgrading
### Changed
- **Skills Cache Strategy**: Replaced `invalidateQueries` with direct `setQueryData` updates for skill install/uninstall/import operations; added `staleTime: Infinity` with `keepPreviousData` to eliminate loading flicker (#1573)
- **Proxy Gzip Compression**: Non-streaming proxy requests now auto-negotiate gzip compression instead of forcing `identity`; streaming requests conservatively keep `identity` to avoid SSE decompression errors
- **o1/o3 Model Compatibility**: Chat Completions proxy forwarding now correctly uses `max_completion_tokens` instead of `max_tokens` for OpenAI o-series models such as o1/o3/o4-mini (#1451)
- **OpenCode Model Variants**: Placed OpenCode model variants at top level instead of inside options for better discoverability (#1317)
- **Skills Import Flow**: Replaced implicit filesystem-based app inference with explicit `ImportSkillSelection` to prevent incorrect multi-app activation; added reconciliation to remove disabled/orphaned symlinks and MCP servers from live config
- **Claude 4.6 Context Window**: Updated Claude Opus 4.6 and Sonnet 4.6 context window from 200K to 1M across OpenClaw and OpenCode presets (GA release)
- **MiniMax Model Upgrade**: Updated MiniMax presets from M2.5 to M2.7 across Claude, OpenClaw, and OpenCode configurations with updated partner descriptions in all three locales
- **Xiaomi MiMo Model Upgrade**: Updated MiMo presets from mimo-v2-flash to mimo-v2-pro across all supported applications
- **AddProviderDialog Simplification**: Removed redundant OAuth tab, reducing dialog from 3 tabs to 2 (app-specific + universal)
- **Provider Form Advanced Options Collapse**: Model mapping, API format, and other advanced fields in the Claude provider form now auto-collapse when empty; auto-expands when any value is set or when a preset fills them in
### Fixed
- **WebDAV Password Silent Clear**: Fixed WebDAV password being silently wiped when ProviderList or UsageScriptModal saved settings by stripping `webdavSync` from frontend payloads and adding backend backfill logic in `merge_settings_for_save()` to preserve existing passwords
- **Tool Message Parsing**: Fixed tool_use/tool_result message classification across Claude (tool_result content blocks), Codex (function_call/function_call_output payloads), and Gemini (array content + toolCalls extraction) session providers (#1401)
- **Dark Mode Selector**: Changed Tailwind `darkMode` from `["selector", "class"]` to `["selector", ".dark"]` to ensure correct dark mode activation (#1596)
- **Copilot Request Fingerprint**: Unified Copilot request fingerprint headers across all API call sites to prevent User-Agent leakage and stream check mismatches
- **o-series Responses API Tokens**: Kept Responses API on the correct `max_output_tokens` field for o-series models instead of incorrectly injecting `max_completion_tokens`
- **Provider Form Double Submit**: Prevented duplicate submissions on rapid button clicks in provider add/edit forms (#1352)
- **Ghostty Session Restore**: Fixed Claude session restore in Ghostty terminal (#1506)
- **Skill ZIP Import Extension**: Added `.skill` file extension support in ZIP import dialog (#1240, #1455)
- **Skill ZIP Install Target App**: ZIP skill installs now use the currently active app instead of always defaulting to Claude
- **OpenClaw Active Card Highlight**: Fixed active OpenClaw provider card not being highlighted (#1419)
- **Responsive Layout with TOC**: Improved responsive design when TOC title exists (#1491)
- **Import Skills Dialog White Screen**: Added missing TooltipProvider in ImportSkillsDialog to prevent runtime crash when opening the dialog
- **Panel Bottom Blank Area**: Replaced hardcoded `h-[calc(100vh-8rem)]` with `flex-1 min-h-0` across all content panels to eliminate bottom gap caused by mismatched offset values
### Docs
- **Pricing Model ID Normalization**: Added documentation section explaining model ID normalization rules (prefix stripping, suffix trimming, `@`→`-` replacement) in EN/ZH/JA user manuals (#1591)
- **macOS Signed & Notarized**: Removed all `xattr` workaround instructions and "unidentified developer" warnings from README, README_ZH, installation guides (EN/ZH/JA), and FAQ pages (EN/ZH/JA); replaced with "signed and notarized by Apple" messaging
---
## [3.12.2] - 2026-03-12
Post-v3.12.1 work focuses on Common Config safety during proxy takeover and more reliable Codex TOML editing.
- **Empty State Guidance**: Improved first-run experience with detailed import instructions and a conditional Common Config snippet hint for Claude/Codex/Gemini providers
### Changed
- **Proxy Takeover Restore Flow**: Proxy takeover hot-switch and provider sync now refresh the restore backup instead of overwriting live config files, rebuilding effective provider settings with Common Config applied so rollback preserves the real user configuration
- **Codex TOML Editing Engine**: Refactored Codex `config.toml` updates onto shared section-aware TOML helpers in Rust and TypeScript, covering `base_url` and `model` field edits across provider forms and takeover cleanup
- **Common Config Initialization Lifecycle**: Startup now auto-extracts Common Config snippets from clean live configs before takeover restoration, tracks explicit "snippet cleared" state, and persists a one-time legacy migration flag to avoid repeated backfills
### Fixed
- **Common Config Loss During Takeover**: Fixed cases where proxy takeover could drop Common Config changes, overwrite live configs during sync, or produce incomplete restore snapshots when switching providers
- **Codex Restore Snapshot Preservation**: Fixed Codex takeover restore backups so existing `mcp_servers` blocks survive provider hot-switches instead of being discarded; changed MCP backup preservation from wholesale table replacement to per-server-id merge so provider/common-config MCP updates win on conflict while live-only servers are retained
- **Cleared Snippet Resurrection**: Fixed startup auto-extraction recreating Common Config snippets that users had intentionally cleared
- **Codex `base_url` Misplacement**: Fixed Codex `base_url` extraction and editing to target the active `[model_providers.<name>]` section instead of appending to the file tail or confusing `mcp_servers.*.base_url` entries for provider endpoints
---
## [3.12.1] - 2026-03-12
### Patch Release
Stability-focused patch release fixing the Common Config modal infinite reopen loop, a WebDAV sync foreign key constraint failure, several i18n interpolation issues, and a Windows toolbar compact mode bug. Also adds **StepFun** provider presets, **OpenClaw input type selection** and **authHeader** support, upgrades Gemini to **3.1-pro**, and welcomes four new sponsor partners.
- **StepFun**: Added StepFun (阶跃星辰) provider presets including the step-3.5-flash model across supported applications (#1369, thanks @hengm3467)
#### OpenClaw Enhancements
- **Input Type Selection**: Added input type selection dropdown for model Advanced Options in OpenClaw configuration form (#1368, thanks @liuxxxu)
- **authHeader Field**: Added optional `authHeader` boolean to OpenClawProviderConfig for vendor-specific auth header support (e.g. Longcat), and refactored form state to reuse the shared type
#### Sponsor Partners
- **Micu API**: Added Micu API as sponsor partner with affiliate links
- **XCodeAPI**: Added XCodeAPI as sponsor partner
- **SiliconFlow**: Added SiliconFlow (硅基流动) as sponsor partner with affiliate links
- **CTok**: Added CTok as sponsor partner
### Changed
- **UCloud → Compshare**: Renamed UCloud provider to Compshare (优云智算) with full i18n support across all three locales (EN/ZH/JA)
- **Gemini Model Upgrade**: Upgraded default Gemini model from 2.5-pro to 3.1-pro in provider presets
### Fixed
#### Common Config & UI
- **Common Config Modal Loop**: Fixed an infinite reopen loop in the Common Config modal and added draft editing support to prevent data loss during edits
- **Toolbar Compact Mode (Windows)**: Fixed toolbar compact mode not triggering on Windows due to left-side overflow (#1375, thanks @zuoliangyu)
- **Session Search Index**: Fixed session search index not syncing with query data, causing stale list display after session deletion
#### Sync & Data
- **WebDAV Provider Health FK**: Fixed foreign key constraint failure when restoring `provider_health` table during WebDAV sync
- **Restore Stream Check UI**: Brought back the model health check (Stream Check) panel for testing provider endpoint availability with live streaming validation
- **First-Run Confirmation**: Added a confirmation dialog on first use of Stream Check to inform users about the feature's purpose and network requests
- **OpenAI Chat Format Support**: Stream Check now supports `openai_chat` api_format, enabling health checks for providers using OpenAI-compatible endpoints
#### OpenAI Responses API
- **Responses API Format Conversion**: New `api_format = "openai_responses"` option enabling Anthropic Messages ↔ OpenAI Responses API bidirectional conversion for providers that implement the Responses API
- **Responses API Deduplication**: Deduplicated and improved the Responses API conversion logic, consolidating shared transformation code
#### Bedrock Optimizer
- **Bedrock Request Optimizer**: PRE-SEND optimizer that injects thinking parameters and cache control blocks into AWS Bedrock requests, enabling extended thinking and prompt caching on Bedrock endpoints (#1301)
#### OpenClaw Enhancements
- **JSON5 Round-Trip Write Engine**: Overhauled OpenClaw config panels with a JSON5 round-trip write engine that preserves comments, formatting, and ordering when saving configuration changes
- **Config Panel Improvements**: Redesigned EnvPanel as a full JSON editor, added `tools.profile` selection to ToolsPanel, introduced OpenClawHealthBanner for config validation warnings, and added legacy timeout migration support in Agents Defaults
- **Agent Model Dropdown**: Replaced text inputs with dropdown selects for OpenClaw agent model configuration, offering a curated list of available models
- **User-Agent Toggle**: Added a User-Agent header toggle for OpenClaw, defaulting to off to avoid potential compatibility issues with certain providers
#### Provider Presets
- **Ucloud**: Added Ucloud partner provider preset for Claude, Codex, and OpenClaw with endpointCandidates, unified apiKeyUrl, refreshed model defaults, and OpenClaw `templateValues` / `suggestedDefaults`
- **Micu**: Added Micu partner provider preset for Claude, Codex, OpenClaw, and OpenCode with OpenClaw `templateValues` / `suggestedDefaults`
- **X-Code API**: Added X-Code API partner provider preset for Claude, Codex, and OpenCode with endpointCandidates
- **Novita**: Added Novita provider presets and icon across all supported apps (#1192)
- **Bailian For Coding**: Added Bailian For Coding preset configuration (#1263)
- **Model Role Badges**: Added model role badges (e.g., Opus, Sonnet) to provider presets and reordered presets to prioritize Opus models
#### WebDAV Sync
- **Dual-Layer Versioning**: Added protocol v2 + db-v6 dual-layer versioning to WebDAV sync, enabling backward-compatible sync format evolution and automatic migration detection
- **Auto-Sync Confirmation**: Added a confirmation dialog when toggling WebDAV auto-sync on/off to prevent accidental changes
#### Usage & Data
- **Daily Rollups & Auto-Vacuum**: Added usage daily rollups for aggregated statistics, incremental auto-vacuum for storage management, and sync-aware backup that coordinates with WebDAV sync cycles
- **UsageFooter Extra Fields**: Added extra field display in UsageFooter component for normal mode, showing additional usage metadata (#1137)
#### Session Management
- **Session Deletion**: Added session deletion with per-provider cleanup and path safety validation, allowing users to remove individual conversation sessions
#### UI & Config
- **Auth Field Selector**: Restored Claude provider auth field selector supporting both AUTH_TOKEN and API_KEY authentication modes
- **Failover Toggle**: Moved failover toggle to display independently on the main page with a confirmation dialog for enabling/disabling
- **Common Config Auto-Extract**: Auto-extract Common Config Snippets from live configuration files on first run, seeding initial common config without manual setup
- **New Provider Page Improvements**: Improved the new provider page with API endpoint and model name fields (#1155)
### Changed
#### Architecture
- **Common Config Runtime Overlay**: Common Config is now applied as a runtime overlay during provider switching instead of being materialized (merged) into each provider's stored config. This preserves the original provider config in the database and applies common settings dynamically at write time
- **First-Run Auto-Extract**: On first run, Common Config Snippets are automatically extracted from the current live configuration files, eliminating the need for manual initial setup
### Fixed
#### Proxy & Streaming
- **OpenAI Streaming Conversion**: Fixed OpenAI ChatCompletion → Anthropic Messages streaming conversion that could produce malformed events under certain response structures
- **Codex /responses/compact Route**: Added support for Codex `/responses/compact` route in proxy forwarding (#1194)
- **Codex Common Config TOML Merge**: Fixed Codex Common Config to use structural TOML merge/subset instead of raw string comparison, correctly handling key ordering and formatting differences
- **Proxy Forwarder Failure Logs**: Improved proxy forwarder failure logging with more descriptive error messages
#### Provider & Preset
- **X-Code Rename**: Renamed "X-Code" provider to "X-Code API" for consistency with the official branding
- **SSSAiCode Missing /v1**: Added missing `/v1` path to SSSAiCode default endpoint for Codex and OpenCode
- **AICoding URL Fix**: Removed `www` prefix from aicoding.sh provider URLs to match the correct domain
- **New Provider Page Input Handling**: Fixed the new provider page so API endpoint / model fields handle line-break deletion correctly and added the missing `codexConfig.modelNameHint` i18n key for zh/en/ja
#### Platform
- **Cache Hit Token Statistics**: Fixed missing token statistics for cache hits in streaming responses (#1244)
- **Minimize-to-Tray Auto Exit**: Fixed issue where the application would automatically exit after being minimized to the system tray for a period of time (#1245)
#### i18n & Localization
- **Comprehensive i18n Audit**: Added 69 missing i18n keys and fixed hardcoded Chinese strings across the application, improving localization coverage for all three languages (zh/en/ja)
- **Model Test Panel i18n**: Corrected i18n key paths for model test panel title and description
- **JSON5 Slash Escaping**: Normalized JSON5 slash escaping and added i18n support for OpenClaw panel labels
#### UI
- **Skills Count Display**: Fixed skills count not displaying correctly when adding new skills (#1295)
- **Endpoint Speed Test**: Removed HTTP status code display from endpoint speed test results to reduce visual noise
- **Outline Button Text Tone**: Aligned outline button text color tone with usage refresh control for visual consistency (#1222)
### Performance
- **OpenClaw Config Write Skip**: Skip backup and atomic write when OpenClaw configuration content is unchanged, avoiding unnecessary I/O operations
### Documentation
- **User Manual i18n**: Restructured user manual for internationalization and added complete EN/JA translations alongside the existing ZH documentation
- **User Manual OpenClaw**: Added OpenClaw coverage and completed settings documentation for the user manual
- **UCloud CompShare Sponsor**: Added UCloud CompShare as a sponsor partner
- **Docs Directory Reorganization**: Reorganized docs directory structure, added user manual links to all three README files, removed cross-language links from user manual sections, and synced README features across EN/ZH/JA
### Maintenance
- **Periodic Maintenance Timer**: Consolidated periodic maintenance timers into a unified scheduler, combining vacuum and rollup operations into a single timer
- **OpenClaw Save Toast**: Removed backup path display from OpenClaw save toasts for cleaner notification messages
---
## [3.11.1] - 2026-02-28
### Hotfix Release
This release reverts the Partial Key-Field Merging architecture introduced in v3.11.0, restoring the proven "full config overwrite + Common Config Snippet" mechanism, and fixes several UI and platform compatibility issues.
- **Restore Full Config Overwrite + Common Config Snippet** (revert 992dda5c): Reverted the partial key-field merging refactoring from v3.11.0 due to critical issues — non-whitelisted custom fields were lost during provider switching, backfill permanently stripped non-key fields from the database, and the whitelist required constant maintenance. Restores full config snapshot write, Common Config Snippet UI and backend commands, and 6 frontend components/hooks
### Changed
- **Proxy Panel Layout**: Moved proxy on/off toggle from accordion header into panel content area, placed directly above app takeover options, ensuring users see takeover configuration immediately after enabling the proxy
- **Manual Import for OpenCode/OpenClaw**: Removed auto-import on startup; empty state now shows an "Import Current Config" button, consistent with Claude/Codex/Gemini behavior
### Fixed
- **"Follow System" Theme Not Auto-Updating**: Delegated to Tauri's native theme tracking (`set_window_theme(None)`) so the WebView's `prefers-color-scheme` media query stays in sync with OS theme changes
- **Compact Mode Cannot Exit**: Restored `flex-1` on `toolbarRef` so `useAutoCompact`'s exit condition triggers correctly based on available width instead of content width
- **Proxy Takeover Toast Shows {{app}}**: Added missing `app` interpolation parameter to i18next `t()` calls for proxy takeover enabled/disabled messages
- **Windows Protocol Handler Side Effects**: Disabled environment check and one-click install on Windows to prevent unintended protocol handler registration
---
## [3.11.0] - 2026-02-26
### Feature Release
This release introduces **OpenClaw** as the fifth supported application, a full **Session Manager** for browsing conversation history across all apps, an independent **Backup Management** panel, **Oh My OpenCode (OMO)** integration, and 50+ other features, fixes, and improvements across 147 commits.
- **OpenClaw Integration**: Full management support for OpenClaw as the fifth application in CC Switch, including provider switching, configuration panels (Env / Tools / Agents Defaults), Workspace file management (HEARTBEAT / BOOTSTRAP / BOOT), daily memory files, and additive overlay mode
- **OpenClaw Provider Presets**: 13+ built-in provider presets with brand icon and complete i18n (zh/en/ja)
- **OpenClaw Form Fields**: Dedicated provider form with providerKey input, model allowlist auto-registration, and default model button
- **OpenClaw Config Panels**: Env editor, Tools editor, and Agents Defaults editor backed by JSON5 read/write (`openclaw_config.rs`)
#### Session Manager
- **Session Manager**: Browse and search conversation history for Claude Code, Codex, Gemini CLI, OpenCode, and OpenClaw with table-of-contents navigation and in-session search
- **Session App Filter**: Auto-filter sessions by current app when entering the session page
- **Session Performance**: Parallel directory scanning and head-tail JSONL reading for faster session list loading
#### Backup Management
- **Backup Panel**: Independent backup management panel with configurable backup policy (max count, auto-cleanup) and backup rename support
- **Periodic Backup**: Hourly automatic backup timer during runtime
- **Pre-Migration Backup**: Automatic backup before database schema migrations with backfill warning
- **Delete Backup**: Delete individual backup files with confirmation dialog
- **Backup Time Fix**: Use local time instead of UTC for backup file names
#### Oh My OpenCode (OMO)
- **OMO Integration**: Full Oh My OpenCode config file management with agent model selection, category configuration, and recommended model fill
- **OMO Slim**: Lightweight oh-my-opencode-slim mode support with OmoVariant parameterization
- **OMO Cross-Exclusion**: Enforce OMO ↔ OMO Slim mutual exclusion at the database level
#### Workspace
- **Daily Memory Search**: Full-text search across daily memory files with date-sorted display
- **Clickable Paths**: Directory paths in workspace panels are now clickable; renamed “Today's Note” to “Add Memory”
- **New Model Pricing**: Added pricing data for claude-opus-4-6 and gpt-5.3-codex with incremental data seeding
### Changed
#### Architecture
- **Partial Key-Field Merging (⚠️ Breaking, reverted in v3.11.1)**: Provider switching now uses partial key-field merging instead of full config overwrite, preserving user's non-provider settings (plugins, MCP, permissions). The "Common Config Snippet" feature has been removed as it is no longer needed. Removes 6 frontend files and ~150 lines of backend dead code (#1098)
- **Manual Import**: Replaced auto-import on startup with manual “Import Current Config” button in empty state, reducing ~47 lines of startup code
- **OMO Variant Parameterization**: Eliminated ~250 lines of OMO/OMO Slim code duplication via `OmoVariant` struct with STANDARD/SLIM constants
- **OMO Common Config Removal**: Removed the two-layer merge system for OMO common config (-1,733 lines across 21 files)
#### Code Quality
- **ProviderForm Decomposition**: Extracted ProviderForm.tsx from 2,227 lines to 1,526 lines by splitting into 5 focused modules (opencodeFormUtils, useOmoModelSource, useOpencodeFormState, useOmoDraftState, useOpenclawFormState)
- **Shared MCP/Skills Components**: Extracted AppCountBar, AppToggleGroup, and ListItemRow shared components to eliminate duplication across MCP and Skills panels
- **OpenClaw TanStack Query Migration**: Migrated Env, Tools, and AgentsDefaults panels from manual useState/useEffect to centralized TanStack Query hooks
#### Settings Layout
- **Proxy Tab**: Split Advanced tab into dedicated Proxy tab (local proxy, failover, rectifiers, global outbound proxy); moved pricing config to Usage dashboard as collapsible accordion. SettingsPage reduced from ~716 to ~426 lines with 5-tab layout: General | Proxy | Advanced | Usage | About
- **Data Section Split**: Split data accordion into Import/Export and Cloud Sync sections for better discoverability
#### Terminal & Config
- **Unified Terminal Selection**: Consolidated terminal preference to global settings; added WezTerm support and terminal name mapping (iterm2 → iterm)
- **OpenClaw Agents Panel**: Primary model field set to read-only; detailed model fields (context window, max tokens, reasoning, cost) moved to advanced options
- **Claude Model Update**: Updated Claude model references from 4.5 to 4.6 across all provider presets
### Fixed
#### Critical
- **Windows Home Dir Regression**: Restored default home directory resolution on Windows to prevent providers/settings “disappearing” when `HOME` env var differs from the real user profile directory (Git/MSYS environments); auto-detects v3.10.3 legacy database location
- **Linux White Screen**: Disabled WebKitGTK hardware acceleration on AMD GPUs (Cezanne/Radeon Vega) to prevent EGL initialization failure causing blank screen on startup
- **OpenAI Beta Parameter**: Stopped appending `?beta=true` to OpenAI Chat Completions endpoints, fixing request failures for Nvidia and other `apiFormat=”openai_chat”` providers
- **Health Check Auth Mode**: Health check now respects provider's auth_mode setting instead of always using x-api-key header
#### Provider & Preset
- **OpenClaw /v1 Prefix**: Removed /v1 prefix from OpenClaw anthropic-messages presets to prevent double path (/v1/v1/messages) with Anthropic SDK auto-append
- **Opus Pricing**: Corrected Opus pricing from $15/$75 to $5/$25 and upgraded model ID to claude-opus-4-6
- **AIGoCode URLs**: Unified API base URL to https://api.aigocode.com across all apps; removed trailing /v1 suffix
- **Zhipu GLM**: Removed outdated partner status from Claude, OpenCode, and OpenClaw presets
- **API Key Visibility**: Restored API Key input field when creating new Claude providers (was incorrectly hidden for non-cloud_provider categories)
- **OpenCode Model Validation**: Reject saving OpenCode providers without at least one configured model
#### OpenClaw
- **OpenClaw P0-P3 Fixes**: Fixed 25 missing i18n keys, replaced key={index} with stable crypto.randomUUID(), excluded openclaw from ProxyToggle/FailoverToggle, added deep link merge_additive_config(), unified serde(flatten) naming, added directory existence checks, removed dead code, added duplicate key validation
- **OpenClaw Robustness**: Fixed EnvPanel visibleKeys using entry key names instead of array indices; added NaN guards; validated provider ID and model before import
- **OpenClaw i18n Dedup**: Merged duplicate openclaw i18n keys to restore provider form translations
#### Platform
- **Window Flash**: Prevented window flicker on silent startup (Windows)
- **Title Bar Theme**: Title bar now follows dark/light mode theme changes
- **Skills Path Separator**: Fixed path separator matching for skill installation status on Windows (supports both `/` and `\`)
- **WSL Conditional Compilation**: Added `#[cfg(target_os = “windows”)]` to WSL helper functions to eliminate dead_code warnings on non-Windows platforms
#### UI
- **Toolbar Clipping**: Removed toolbar height limit that was clipping AppSwitcher
- **Update Badge**: Show update badge instead of green check when a newer version is available
- **Session Button Visibility**: Only show Session Manager button for Claude and Codex apps
- **Directory Spacing**: Added vertical spacing between directory setting sections
- **Dark Mode Cards**: Unified SQL import/export card styling in dark mode
- **OpenClaw Scroll**: Enabled scrolling for OpenClaw configuration panel content
#### i18n & Localization
- **Session Manager i18n**: Replaced hardcoded Chinese strings with i18n keys for relative time, role labels, and UI elements
- **OpenClaw Default Model Label**: Renamed “Enable/Default” to “Set as Default / Current Default” with wider button
- **Daily Memory Sort**: Sort daily memory files by filename date (YYYY-MM-DD.md) instead of modification time
- **Backup Name i18n**: Use local time for backup file names
#### Other
- **Skill Doc URL**: Use actual branch from download_repo for documentation URL; switched from /tree/ to /blob/ pointing to SKILL.md
- **Provider Auto-Import**: Removed auto-import side effect from useProvidersQuery queryFn; users now trigger import manually via empty state button
- **Manual Backup Validation**: Treat missing database file as error during manual backup to prevent false success toast
### Performance
- **Session Panel Loading**: Parallel directory scanning and head-tail JSONL reading for Codex, OpenClaw, and OpenCode session providers
- **Query Cache Cleanup**: Removed unnecessary TanStack Query cache overhead for Tauri local IPC calls
### Documentation
- **Sponsors**: Added/updated SSSAiCode, Crazyrouter, AICoding, Right Code, and MiniMax sponsor entries across all README languages
- **User Manual**: Added user manual documentation (#979)
### Maintenance
- **Pre-Release Cleanup**: Removed debug logs, fixed clippy warnings, added missing Japanese translations, and formatted code
- **UI Exclusions**: Hidden MCP, Skills, proxy/pricing, stream check, and model test panels for OpenClaw where not applicable
---
## [3.10.3] - 2026-01-30
### Feature Release
This release introduces a generic API format selector, pricing configuration enhancements, and multiple UX improvements.
### Added
- **API Key Link for OpenCode**: API key link support for OpenCode provider form, enabling quick access to provider key management pages
- **AICodeMirror Partner Preset**: Added AICodeMirror partner preset for all apps (Claude, Codex, Gemini, OpenCode)
- **API Format Selector**: Generic API format chooser for Claude providers, replacing the OpenRouter-specific toggle. Supports Anthropic Messages (native) and OpenAI Chat Completions format
- **API Format Presets**: Allow preset providers to specify API format (anthropic or openai_chat) for third-party proxy services
- **Proxy Hint**: Display info toast when switching to OpenAI Chat format provider, reminding users to enable proxy
- **Pricing Config Enhancement**: Per-provider cost multiplier, pricing model source (request/response), request model logging, and enriched usage UI (#781)
- **Skills ZIP Install**: Install skills directly from local ZIP files with recursive scanning support
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at **farion1231@gmail.com**. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations].
cd src-tauri && cargo fmt --check && cargo clippy && cargo test
```
## Pull Request Guidelines
1.**Open an issue first** for new features — PRs for features that are not a good fit may be closed.
2.**Fork and branch** — Create a feature branch from `main` (e.g., `feat/my-feature` or `fix/issue-123`).
3.**Keep PRs focused** — One feature or fix per PR. Avoid unrelated changes.
4.**Follow the PR template** — Fill in the summary, related issue, and checklist.
### PR Checklist
- [ ]`pnpm typecheck` passes
- [ ]`pnpm format:check` passes
- [ ]`cargo clippy` passes (if Rust code changed)
- [ ] Updated i18n files if user-facing text changed
### Commit Convention
We use [Conventional Commits](https://www.conventionalcommits.org/):
```
feat(provider): add support for new provider
fix(tray): resolve menu not updating after switch
docs(readme): update installation instructions
ci: add format check workflow
chore(deps): update dependencies
```
## AI-Assisted Contributions
We welcome AI-assisted contributions, but **the responsibility stays with you**. AI tools lower the cost of writing code — they do not lower the cost of reviewing it. Maintainers are not obligated to clean up AI-generated output.
By submitting a PR, you agree to the following:
1.**You have read and understood your code.** You must be able to explain any line in your PR. If you cannot, it is not ready for review.
2.**You have tested it yourself.** Every change must be verified locally — not just "it looks right." Do not submit code for platforms or features you cannot test.
3.**PRs must be small and focused.** One issue, one PR. Large, sprawling, multi-topic PRs will be closed.
4.**Open an issue first.** Drive-by PRs with no prior discussion — especially AI-generated ones — may be closed without review.
5.**Maintainers may close without explanation.** PRs that appear to be unreviewed AI output — hallucinated fixes, unnecessary refactors, bulk changes with no context — may be closed at the maintainer's discretion.
**In short**: AI is a tool, not a substitute for understanding. Use it to help you contribute better, not to shift work onto maintainers.
## Internationalization (i18n)
CC Switch supports three languages. When modifying user-facing text:
1. Update **all three** locale files:
-`src/locales/en/translation.json`
-`src/locales/zh/translation.json`
-`src/locales/ja/translation.json`
2. Use the `t()` function from i18next for all UI text.
3. Never hardcode user-facing strings.
## Questions?
- [Open a question](https://github.com/farion1231/cc-switch/issues/new?template=question.yml)
> [Want to appear here?](mailto:farion1231@gmail.com)
This project is sponsored by Z.ai, supporting us with their GLM CODING PLAN.GLM CODING PLAN is a subscription service designed for AI coding, starting at just $3/month. It provides access to their flagship GLM-4.6 model across 10+ popular AI coding tools (Claude Code, Cline, Roo Code, etc.), offering developers top-tier, fast, and stable coding experiences.Get 10% OFF the GLM CODING PLAN with [this link](https://z.ai/subscribe?ic=8JVLJQFSKB)!
MiniMax-M2.7 is a next-generation large language model designed for autonomous evolution and real-world productivity. Unlike traditional models, M2.7 actively participates in its own improvement through agent teams, dynamic tool use, and reinforcement learning loops. It delivers strong performance in software engineering (56.22% on SWE-Pro, 55.6% on VIBE-Pro, 57.0% on Terminal Bench 2) and excels in complex office workflows, achieving a leading 1495 ELO on GDPval-AA. With high-fidelity editing across Word, Excel, and PowerPoint, and a 97% adherence rate across 40+ complex skills, M2.7 sets a new standard for building AI-native workflows and organizations.
[Click](https://platform.minimax.io/subscribe/coding-plan?code=ClLhgxr2je&source=link) to get an exclusive 12% off the MiniMax Token Plan!
<td>Thanks to PackyCode for sponsoring this project! PackyCode is a reliable and efficient API relay service provider, offering relay services for Claude Code, Codex, Gemini, and more. PackyCode provides special discounts for our software users: register using <a href="https://www.packyapi.com/register?aff=cc-switch">this link</a> and enter the "cc-switch" promo code during recharge to get 10% off.</td>
<td>Thanks to PackyCode for sponsoring this project! PackyCode is a reliable and efficient API relay service provider, offering relay services for Claude Code, Codex, Gemini, and more. PackyCode provides special discounts for our software users: register using <a href="https://www.packyapi.com/register?aff=cc-switch">this link</a> and enter the "cc-switch" promo code during first recharge to get 10% off.</td>
</tr>
<tr>
@@ -33,8 +42,19 @@ This project is sponsored by Z.ai, supporting us with their GLM CODING PLAN.GLM
<td>Thanks to DMXAPI for sponsoring this project! DMXAPI provides global large model API services to 200+ enterprise users. One API key for all global models. Features include: instant invoicing, unlimited concurrency, starting from $0.15, 24/7 technical support. GPT/Claude/Gemini all at 32% off, domestic models 20-50% off, Claude Code exclusive models at 66% off! <a href="https://www.dmxapi.cn/register?aff=bUHu">Register here</a></td>
<td>Thanks to Shengsuanyun for sponsoring this project! Shengsuanyun is a super factory serving AI Native Teams — an industrial-grade AI task parallel execution platform. Its model marketplace aggregates Claude, ChatGPT, Gemini, and other domestic and international LLM and multimedia model capabilities with direct supply. Absolutely no reverse engineering or dilution — platform-wide model SLA availability reaches 99.7%, with <a href="https://watch.shengsuanyun.com/status/shengsuanyun">monitoring dashboards</a> showing green across the board. It also offers enterprise-grade custom gateways for fine-grained team cost and permission management, smart routing, security protection, and BYOK (Bring Your Own Key) hosting. The platform charges on a pay-per-use and tokens plan (coming soon) basis, with invoicing available. Register via <a href="https://www.shengsuanyun.com/?from=CH_4HHXMRYF">this link</a> as a new user to receive ¥10 in credits plus a 10% bonus on your first top-up.</td>
<td>Thanks to SiliconFlow for sponsoring this project! SiliconFlow is a high-performance AI infrastructure and model API platform, providing fast and reliable access to language, speech, image, and video models in one place. With pay-as-you-go billing, broad multimodal model support, high-speed inference, and enterprise-grade stability, SiliconFlow helps developers and teams build and scale AI applications more efficiently. Register via <a href="https://cloud.siliconflow.cn/i/drGuwc9k">this link</a> and complete real-name verification to receive ¥20 in bonus credit, usable across models on the platform. SiliconFlow is also now compatible with OpenClaw, allowing users to connect a SiliconFlow API key and call major AI models for free.</td>
<td>Thanks to AICodeMirror for sponsoring this project! AICodeMirror provides official high-stability relay services for Claude Code / Codex / Gemini CLI, with enterprise-grade concurrency, fast invoicing, and 24/7 dedicated technical support.
Claude Code / Codex / Gemini official channels at 38% / 2% / 9% of original price, with extra discounts on top-ups! AICodeMirror offers special benefits for CC Switch users: register via <a href="https://www.aicodemirror.com/register?invitecode=9915W3">this link</a> to enjoy 20% off your first top-up, and enterprise customers can get up to 25% off!</td>
</tr>
<tr>
@@ -42,8 +62,85 @@ This project is sponsored by Z.ai, supporting us with their GLM CODING PLAN.GLM
<td>Thanks to Cubence for sponsoring this project! Cubence is a reliable and efficient API relay service provider, offering relay services for Claude Code, Codex, Gemini, and more with flexible billing options including pay-as-you-go and monthly plans. Cubence provides special discounts for CC Switch users: register using <a href="https://cubence.com/signup?code=CCSWITCH&source=ccs">this link</a> and enter the "CCSWITCH" promo code during recharge to get 10% off every top-up!</td>
<td>Thanks to DMXAPI for sponsoring this project! DMXAPI provides global large model API services to 200+ enterprise users. One API key for all global models. Features include: instant invoicing, unlimited concurrency, starting from $0.15, 24/7 technical support. GPT/Claude/Gemini all at 32% off, domestic models 20-50% off, Claude Code exclusive models at 66% off! <a href="https://www.dmxapi.cn/register?aff=bUHu">Register here</a></td>
<td>Thanks to Compshare for sponsoring this project! Compshare is UCloud's AI cloud platform, providing stable and comprehensive domestic and international model APIs with just one key. Featuring cost-effective monthly and pay-as-you-go Coding Plan packages at 60-80% off official prices. Supports Claude Code, Codex, and API access. Enterprise-grade high concurrency, 24/7 technical support, and self-service invoicing. Users who register via <a href="https://www.compshare.cn/coding-plan?ytag=GPU_YY_YX_git_cc-switch">this link</a> will receive a free 5 CNY platform trial credit!</td>
<td>Thanks to AICoding.sh for sponsoring this project! AICoding.sh — Global AI Model API Relay Service at Unbeatable Prices! Claude Code at 19% of original price, GPT at just 1%! Trusted by hundreds of enterprises for cost-effective AI services. Supports Claude Code, GPT, Gemini and major domestic models, with enterprise-grade high concurrency, fast invoicing, and 24/7 dedicated technical support. CC Switch users who register via <a href="https://aicoding.sh/i/CCSWITCH">this link</a> get 10% off their first top-up!</td>
<td>Thanks to Crazyrouter for sponsoring this project! Crazyrouter is a high-performance AI API aggregation platform — one API key for 300+ models including Claude Code, Codex, Gemini CLI, and more. All models at 55% of official pricing with auto-failover, smart routing, and unlimited concurrency. Crazyrouter offers an exclusive deal for CC Switch users: register via <a href="https://crazyrouter.com/register?aff=OZcm&ref=cc-switch">this link</a> to get <strong>$2 free credit</strong> instantly, plus enter promo code `CCSWITCH` on your first top-up for an extra <strong>30% bonus credit</strong>! </td>
<td>Thank you to Right Code for sponsoring this project! Right Code reliably provides routing services for models such as Claude Code, Codex, and Gemini. It features a highly cost-effective Codex monthly subscription plan and <strong>supports quota rollovers—unused quota from one day can be carried over and used the next day.</strong> Invoices are available upon top-up. Enterprise and team users can receive dedicated one-on-one support. Right Code also offers an exclusive discount for CC Switch users: register via <a href="https://www.right.codes/register?aff=CCSWITCH">this link</a>, and with every top-up you will receive pay-as-you-go credit equivalent to 25% of the amount paid.</td>
<td>Thanks to SSSAiCode for sponsoring this project! SSSAiCode is a stable and reliable API relay service, dedicated to providing stable, reliable, and affordable Claude and Codex model services, <strong>offering high cost-effective official Claude service at just ¥0.5/$ equivalent</strong>, supporting monthly and pay-as-you-go billing plans with same-day fast invoicing. SSSAiCode offers a special deal for CC Switch users: register via <a href="https://www.sssaicode.com/register?ref=DCP0SM">this link</a> to enjoy $10 extra credit on every top-up!</td>
<td>Thanks to Micu API for sponsoring this project! Micu API is a global LLM relay service provider dedicated to delivering the best cost-performance ratio with high stability. Backed by a registered enterprise for core assurance, eliminating any risk of service discontinuation, with fast official invoicing support! We champion "zero cost to try": top up from as low as ¥1 with no minimum, and get fee-free refunds anytime! Micu API offers an exclusive deal for CC Switch users: register via <a href="https://www.openclaudecode.cn/register?aff=aOYQ">this link</a> and enter promo code "ccswitch" when topping up to enjoy a <strong>10% discount</strong>!</td>
<td>Thanks to LemonData for sponsoring this project! LemonData is a high-performance AI API aggregation platform — one API key for 300+ models including GPT, Claude, Gemini, DeepSeek, and more. All models priced 30–70% below official rates with auto-failover, smart routing, and unlimited concurrency. New users get $1 free credit instantly upon registration — sign up via <a href="https://lemondata.cc/r/FFX1ZDUP">this link</a>to claim your bonus and start building right away</strong>!</td>
<td>Thanks to CTok.ai for sponsoring this project! CTok.ai is dedicated to building a one-stop AI programming tool service platform. We offer professional Claude Code packages and technical community services, with support for Google Gemini and OpenAI Codex. Through carefully designed plans and a professional tech community, we provide developers with reliable service guarantees and continuous technical support, making AI-assisted programming a true productivity tool. Click <a href="https://ctok.ai">here</a> to register!</td>
<td>Thanks to ChefShop AI for sponsoring this project! ChefShop AI is a premium account service provider tailored for heavy AI subscription users. The platform offers official top-up and stable account services for mainstream large models including ChatGPT Plus/Pro, Claude Max, Grok Super/Heavy, and Gemini. Click <a href="https://chefshop.ai">here</a> to purchase!</td>
<td>Thanks to LionCC for sponsoring this project! LionCC is built for Vibe Coders who pursue the ultimate development experience. We provide stable, low-latency, and competitively priced computing services for Claude Code, Codex, and OpenClaw, saving up to 50% in costs. After registering, add customer service on WeChat (HSQBJ088888888) with the code "cc-switch" to receive $10 in free credits (10 million tokens). For other collaborations, follow the blog @LionCC.ai. Click <a href="https://vibecodingapi.ai">here</a> to register!</td>
<td>Thanks to DDS for sponsoring this project! DDS Hub is a reliable and high-performance Claude API proxy service. We provides cost-effective domestic Claude direct acceleration services for both individual and enterprise users. We offer stable and low-latency Claude Max number pools, with full support for Claude Haiku, Opus, Sonnet and other flagship models. Invoices are available for recharges of 1000 RMB or more. Enterprise customers can also enjoy customized grouping and dedicated technical support services.
Exclusive benefit for CC Switch users: Register via <a href="https://ddshub.short.gy/ccswitch">the link </a>below and enjoy an extra 10% credit on your first recharge (please contact the group admin to claim after recharging)!</td>
</tr>
</table>
</details>
## Why CC Switch?
Modern AI-powered coding relies on CLI tools like Claude Code, Codex, Gemini CLI, OpenCode, and OpenClaw — but each has its own configuration format. Switching API providers means manually editing JSON, TOML, or `.env` files, and there is no unified way to manage MCP and Skills across multiple tools.
**CC Switch** gives you a single desktop app to manage all five CLI tools. Instead of editing config files by hand, you get a visual interface to import providers with one click, switch between them instantly, with 50+ built-in provider presets, unified MCP and Skills management, and system tray quick switching — all backed by a reliable SQLite database with atomic writes that protect your configs from corruption.
- **One App, Five CLI Tools** — Manage Claude Code, Codex, Gemini CLI, OpenCode, and OpenClaw from a single interface
- **No More Manual Editing** — 50+ provider presets including AWS Bedrock, NVIDIA NIM, and community relays; just pick and switch
- **Unified MCP & Skills Management** — One panel to manage MCP servers and Skills across four apps with bidirectional sync
- **System Tray Quick Switch** — Switch providers instantly from the tray menu, no need to open the full app
- **Cloud Sync** — Sync provider data across devices via Dropbox, OneDrive, iCloud, or WebDAV servers
- **Cross-Platform** — Native desktop app for Windows, macOS, and Linux, built with Tauri 2
- **Built-in Utilities** — Includes various utilities for first-launch login confirmation, signature bypass, plugin extension sync, and more
## Screenshots
| Main Interface | Add Provider |
@@ -52,108 +149,125 @@ This project is sponsored by Z.ai, supporting us with their GLM CODING PLAN.GLM
## Features
### Current Version: v3.9.1 | [Full Changelog](CHANGELOG.md) | [Release Notes](docs/release-note-v3.9.0-en.md)
- One-click import provider configs via shared links
- Security validation + lifecycle integration
CC Switch supports five tools: **Claude Code**, **Codex**, **Gemini CLI**, **OpenCode**, and **OpenClaw**. Each tool has dedicated provider presets and configuration management.
- **Claude Plugin Sync**: One-click apply/restore Claude plugin configurations
For most tools, yes — restart your terminal or the CLI tool for changes to take effect. The exception is **Claude Code**, which currently supports hot-switching of provider data without a restart.
- Granular model configuration (4-tier: Haiku/Sonnet/Opus/Custom)
- WSL environment support with auto-sync on directory change
- 100% hooks test coverage & complete architecture refactoring
<details>
<summary><strong>My plugin configuration disappeared after switching providers — what happened?</strong></summary>
**System Features**
CC Switch provides a "Shared Config Snippet" feature to pass common data (beyond API keys and endpoints) between providers. Go to "Edit Provider" → "Shared Config Panel" → click "Extract from Current Provider" to save all common data. When creating a new provider, check "Write Shared Config" (enabled by default) to include plugin data in the new provider. All your configuration items are preserved in the default provider imported when you first launched the app.
CC Switch for macOS is code-signed and notarized by Apple. You can download and install it directly — no extra steps needed. We recommend using the `.dmg` installer.
</details>
<details>
<summary><strong>Why can't I delete the currently active provider?</strong></summary>
CC Switch follows a "minimal intrusion" design principle — even if you uninstall the app, your CLI tools will continue to work normally. The system always keeps one active configuration, because deleting all configurations would make the corresponding CLI tool unusable. If you rarely use a specific CLI tool, you can hide it in Settings. To switch back to official login, see the next question.
</details>
<details>
<summary><strong>How do I switch back to official login?</strong></summary>
Add an official provider from the preset list. After switching to it, run the Log out / Log in flow, and then you can freely switch between the official provider and third-party providers. Codex supports switching between different official providers, making it easy to switch between multiple Plus or Team accounts.
</details>
<details>
<summary><strong>Where is my data stored?</strong></summary>
- **Backups**: `~/.cc-switch/backups/` (auto-rotated, keeps 10 most recent)
- **Skills**: `~/.cc-switch/skills/` (symlinked to corresponding apps by default)
- **Skill Backups**: `~/.cc-switch/skill-backups/` (created automatically before uninstall, keeps 20 most recent)
</details>
## Documentation
For detailed guides on every feature, check out the **[User Manual](docs/user-manual/en/README.md)** — covering provider management, MCP/Prompts/Skills, proxy & failover, and more.
## Quick Start
### Basic Usage
1.**Add Provider**: Click "Add Provider" → Choose a preset or create custom configuration
2.**Switch Provider**:
- Main UI: Select provider → Click "Enable"
- System Tray: Click provider name directly (instant effect)
3.**Takes Effect**: Restart your terminal or the corresponding CLI tool to apply changes (Claude Code does not require a restart)
4.**Back to Official**: Add an "Official Login" preset, restart the CLI tool, then follow its login/OAuth flow
### MCP, Prompts, Skills & Sessions
- **MCP**: Click the "MCP" button → Add servers via templates or custom config → Toggle per-app sync
- **Prompts**: Click "Prompts" → Create presets with Markdown editor → Activate to sync to live files
- **Skills**: Click "Skills" → Browse GitHub repos → One-click install to all apps
- **Sessions**: Click "Sessions" → Browse, search, and restore conversation history across all apps
> **Note**: On first launch, you can manually import existing CLI tool configs as the default provider.
## Download & Installation
### System Requirements
- **Windows**: Windows 10 and above
- **macOS**: macOS 10.15 (Catalina) and above
- **macOS**: macOS 12 (Monterey) and above
- **Linux**: Ubuntu 22.04+ / Debian 11+ / Fedora 34+ and other mainstream distributions
Download `CC-Switch-v{version}-macOS.zip` from the [Releases](../../releases) page and extract to use.
Download `CC-Switch-v{version}-macOS.dmg` (recommended) or `.zip` from the [Releases](../../releases) page.
> **Note**: Since the author doesn't have an Apple Developer account, you may see an "unidentified developer" warning on first launch. Please close it first, then go to "System Settings" → "Privacy & Security" → click "Open Anyway", and you'll be able to open it normally afterwards.
> **Note**: CC Switch for macOS is code-signed and notarized by Apple. You can install and open it directly.
### ArchLinux 用户
### ArchLinux Users
**Install via paru (Recommended)**
@@ -196,98 +310,11 @@ Download the latest Linux build from the [Releases](../../releases) page:
> **Flatpak**: Not included in official releases. You can build it yourself from the `.deb` — see [`flatpak/README.md`](flatpak/README.md) for instructions.
- System Tray: Click provider name directly (instant effect)
3.**Takes Effect**: Restart your terminal or Claude Code / Codex / Gemini clients to apply changes
4.**Back to Official**: Select the "Official Login" preset (Claude/Codex) or "Google Official" preset (Gemini), restart the corresponding client, then follow its login/OAuth flow
### MCP Management
- **Location**: Click "MCP" button in top-right corner
- **Add Server**:
- Use built-in templates (mcp-fetch, mcp-filesystem, etc.)
- Support stdio / http / sse transport types
- Configure independent MCP servers for different apps
- **Enable/Disable**: Toggle switches to control which servers sync to live config
- **Sync**: Enabled servers auto-sync to each app's live files
- **Import/Export**: Import existing MCP servers from Claude/Codex/Gemini config files
### Skills Management (v3.7.0 New)
- **Location**: Click "Skills" button in top-right corner
<td>SiliconFlow のご支援に感謝します!SiliconFlow は高性能 AI インフラストラクチャおよびモデル API プラットフォームで、言語・音声・画像・動画モデルへの高速かつ信頼性の高いアクセスをワンストップで提供します。従量課金制、豊富なマルチモーダルモデル対応、高速推論、エンタープライズグレードの安定性を備え、開発者やチームがより効率的に AI アプリケーションを構築・拡張できるようサポートします。<a href="https://cloud.siliconflow.cn/i/drGuwc9k">このリンク</a>から登録し、本人確認を完了すると、プラットフォーム内の全モデルで利用可能な ¥20 のボーナスクレジットが付与されます。SiliconFlow は OpenClaw にも対応しており、SiliconFlow の API キーを接続することで主要な AI モデルを無料で呼び出すことができます。</td>
CC Switch には「共有設定スニペット」機能があり、APIキーやエンドポイント以外の共通データをプロバイダ間で引き継ぐことができます。「プロバイダ編集」→「共有設定パネル」→「現在のプロバイダから抽出」をクリックして、すべての共通データを保存してください。新しいプロバイダを作成する際に「共有設定を書き込む」にチェック(デフォルトで有効)を入れれば、プラグインなどのデータが新しいプロバイダ設定に含まれます。すべての設定項目は、アプリ初回起動時にインポートされたデフォルトプロバイダに保存されており、失われることはありません。
プリセットリストから公式プロバイダを追加してください。切り替え後、ログアウト/ログインのフローを実行すれば、以降は公式プロバイダとサードパーティプロバイダを自由に切り替えられます。Codex では異なる公式プロバイダ間の切り替えに対応しており、複数の Plus アカウントや Team アカウントの切り替えに便利です。
<td>感谢硅基流动赞助了本项目!硅基流动是一个高性能 AI 基础设施与模型 API 平台,一站式提供语言、语音、图像、视频等多模态模型的快速、可靠访问。平台支持按量计费、丰富的多模态模型选择、高速推理和企业级稳定性,帮助开发者和团队更高效地构建和扩展 AI 应用。通过<a href="https://cloud.siliconflow.cn/i/drGuwc9k">此链接</a>注册并完成实名认证,即可获得 ¥20 奖励金,可在平台内跨模型使用。硅基流动现已兼容 OpenClaw,用户可接入硅基流动 API Key 免费调用主流 AI 模型。</td>
<td>感谢优云智算赞助了本项目!优云智算是UCloud旗下AI云平台,提供稳定、全面的国内外模型API,仅一个key即可调用。主打包月、按量的高性价比 Coding Plan 套餐,基于官方2~5折优惠。支持接入 Claude Code、Codex 及 API 调用。支持企业高并发、7*24技术支持、自助开票。通过<a href="https://www.compshare.cn/coding-plan?ytag=GPU_YY_YX_git_cc-switch">此链接</a>注册的用户,可得免费5元平台体验金!</td>
<td>感谢 Right Code 赞助了本项目!Right Code 稳定提供 Claude Code、Codex、Gemini 等模型的中转服务。主打<strong>极高性价比</strong>的Codex包月套餐,<strong>提供额度转结,套餐当天用不完的额度,第二天还能接着用!</strong>充值即可开票,企业、团队用户一对一对接。同时为 CC Switch 的用户提供了特别优惠:通过<a href="https://www.right.codes/register?aff=CCSWITCH">此链接</a>注册,每次充值均可获得实付金额25%的按量额度!</td>
<td>感谢 CTok.ai 赞助了本项目!CTok.ai 致力于打造一站式 AI 编程工具服务平台。我们提供 Claude Code 专业套餐及技术社群服务,同时支持 Google Gemini 和 OpenAI Codex。通过精心设计的套餐方案和专业的技术社群,为开发者提供稳定的服务保障和持续的技术支持,让 AI 辅助编程真正成为开发者的生产力工具。点击<a href="https://ctok.ai">这里</a>注册!</td>
<td>感谢 DDS 赞助本项目!呆呆兽是一家专注 Claude 的可靠高效 API 中转站,为个人和企业用户提供极具性价比的国内 Claude 直连加速服务。支持 Claude Haiku / Opus / Sonnet 等满血模型。充值满 1000 元即可开具发票,企业客户更可享受定制化分组和技术支持服务。CC Switch 用户专属福利:通过<a href="https://ddshub.short.gy/ccswitch">此链接</a>注册后,首单充值可额外赠送 10% 额度(充值后请联系群主领取)!</td>
</tr>
</table>
</details>
## 为什么选择 CC Switch?
现代 AI 编程依赖于 Claude Code、Codex、Gemini CLI、OpenCode 和 OpenClaw 等 CLI 工具——但每个工具都有自己的配置格式。切换 API 供应商意味着手动编辑 JSON、TOML 或 `.env` 文件,而在多个工具之间缺乏一个统一管理 MCP, SKILLS 的方式。
CC Switch 使用“通用配置片段”功能,在不同的供应商之间传递 Key 和请求地址之外的通用数据,您可以在“编辑供应商”菜单的“通用配置面板”里,点击“从当前供应商提取”,把所有的通用数据提取到通用配置中,之后在新建“供应商”的时候,只要勾选“写入通用配置”(默认勾选),就会把插件等数据写入到新的供应商配置中。您的所有配置项都会保存在运行本软件的时候,第一次导入的默认供应商里面,不会丢失。
- 系统托盘快速切换
- 单实例守护
- 内置自动更新器
- 原子写入与回滚保护
</details>
<details>
<summary><strong>macOS 安装</strong></summary>
CC Switch macOS 版本已通过 Apple 代码签名和公证,可直接下载安装,无需额外操作。推荐使用 `.dmg` 安装包。
- **Acknowledgment / 确认**: within 48 hours / 48 小时内
- **Initial assessment / 初步评估**: within 7 days / 7 天内
- **Fix for critical issues / 关键问题修复**: within 14 days / 14 天内
## Disclosure Policy / 披露政策
We follow a coordinated disclosure process:
我们遵循协调披露流程:
1. The reporter submits the vulnerability privately. / 报告者私下提交漏洞。
2. We confirm and work on a fix. / 我们确认并修复漏洞。
3. A patch release is published. / 发布修复版本。
4. The vulnerability is publicly disclosed. / 公开披露漏洞详情。
Reporters will be credited in the release notes unless they prefer to remain anonymous.
除非报告者希望匿名,否则将在发布说明中致谢。
## Security Updates / 安全更新
Security fixes are released as patch versions and announced via [GitHub Releases](https://github.com/farion1231/cc-switch/releases). We recommend always updating to the latest version.
CC Switch v3.10.0 introduces OpenCode support, becoming the fourth managed CLI application.
This release also brings global proxy settings, Claude Rectifier (thinking signature fixer), enhanced health checks, per-provider configuration, and many other important features, along with comprehensive improvements to multi-app workflows and terminal experience.
**Release Date**: 2026-01-21
---
## Highlights
- OpenCode Support: Full management of providers, MCP servers, and Skills with auto-import on first launch
- Global Proxy: Configure a unified proxy for all outbound network requests
- Claude Rectifier: Thinking signature fixer for better compatibility with third-party APIs
- Enhanced Health Checks: Configurable prompts and CLI-compatible request format
- Per-Provider Config: Persistent provider-specific configuration support
- App Visibility Control: Freely show/hide apps with synchronized tray menu updates
| `CC-Switch-v3.10.0-macOS.zip` | **Recommended** - Extract and drag to Applications, Universal Binary |
| `CC-Switch-v3.10.0-macOS.tar.gz` | For Homebrew installation and auto-update |
> **Note**: Since the author doesn't have an Apple Developer account, you may see an "unidentified developer" warning on first launch. Please close it, then go to "System Settings" → "Privacy & Security" → click "Open Anyway", and it will open normally afterwards.
### Homebrew (macOS)
```bash
brew tap farion1231/ccswitch
brew install --cask cc-switch
```
Update:
```bash
brew upgrade --cask cc-switch
```
### Linux
| Distribution | Recommended Format | Installation Method |
CC Switch v3.11.0 is a major update that adds full management support for **OpenClaw** as the fifth application, introduces a new **Session Manager** and **Backup Management** feature. Additionally, **Oh My OpenCode (OMO) integration**, the **partial key-field merging** architecture upgrade for provider switching, **settings page refactoring**, and many other improvements make the overall experience more polished.
- **OpenClaw Support**: Fifth managed application with 13 provider presets, Env/Tools/AgentsDefaults config editors, and Workspace file management
- **Session Manager**: Browse conversation history across all five apps with table-of-contents navigation and in-session search
- **Backup Management**: Independent backup panel with configurable policies, periodic backups, and pre-migration auto-backup
- **Oh My OpenCode Integration**: Full OMO config management with OMO Slim lightweight mode support
- **Partial Key-Field Merging (⚠️ Breaking Change)**: Provider switching now only replaces provider-related fields, preserving all other settings; the "Common Config Snippet" feature has been removed
- **Settings Page Refactoring**: 5-tab layout with ~40% code reduction
- **6 New Provider Presets**: AWS Bedrock, SSAI Code, CrazyRouter, AICoding, and more
- **Thinking Budget Rectifier**: Fine-grained thinking budget control
Provider switching now uses partial key-field merging instead of full config overwrite (#1098).
**Before**: Switching providers overwrote the entire `settings_config` to the live config file. This meant that any non-provider settings the user manually added to the live file (plugins, MCP config, permissions, etc.) would be lost on every switch. To work around this, previous versions offered a "Common Config Snippet" feature that let users define shared config to be merged on every switch.
**After**: Switching providers now only replaces provider-related key-values (API keys, endpoints, models, etc.), leaving all other settings intact. The "Common Config Snippet" feature is therefore no longer needed and has been removed.
**Impact & Migration**:
- If you **didn't use** Common Config Snippets, this change is fully transparent — switching just works better now
- If you **used** Common Config Snippets to preserve custom settings (MCP config, permissions, etc.), those settings are now automatically preserved during switches — no action needed
- If you used Common Config Snippets for other purposes (e.g., injecting extra config on every switch), please manually add those settings to your live config file after upgrading
This refactoring removed 6 frontend files (3 components + 3 hooks) and ~150 lines of backend dead code.
### Manual Import Replaces Auto-Import
Startup no longer auto-imports external configurations. Users now click "Import Current Config" manually, preventing accidental data overwrites.
### OmoVariant Parameterization
Eliminated ~250 lines of duplicated code in the OMO module via `OmoVariant` struct parameterization.
### OMO Common Config Removal
Removed the two-layer merge system, reducing ~1,733 lines of code and simplifying the architecture.
### ProviderForm Decomposition
Reduced ProviderForm component from 2,227 lines to 1,526 lines by extracting 5 independent modules (opencodeFormUtils, useOmoModelSource, useOpencodeFormState, useOmoDraftState, useOpenclawFormState), significantly improving maintainability.
### Shared MCP/Skills Components
Extracted AppCountBar, AppToggleGroup, and ListItemRow shared components to reduce duplication across MCP and Skills panels (#897, thanks @PeanutSplash).
### Settings Page Refactoring
Refactored settings page to a 5-tab layout (General | Proxy | Advanced | Usage | About), reducing SettingsPage code from ~716 to ~426 lines.
### Other Improvements
- Unified terminal selection via global settings with WezTerm support added
- Updated Claude model references from 4.5 to 4.6
---
## Bug Fixes
### Critical Fixes
- **Windows Home Dir Regression**: Restored default home directory resolution to prevent providers/settings "disappearing" when `HOME` env var differs from the real user profile directory in Git/MSYS environments
- **Linux White Screen**: Disabled WebKitGTK hardware acceleration on AMD GPUs (Cezanne/Radeon Vega) to prevent blank screen on startup (#986, thanks @ThendCN)
- **OpenAI Beta Parameter**: Stopped appending `?beta=true` to `/v1/chat/completions` endpoints, fixing request failures for Nvidia and other `apiFormat="openai_chat"` providers (#1052, thanks @jnorthrup)
- **Health Check Auth**: Health check now respects provider's `auth_mode` setting, preventing failures for proxy services that only support Bearer authentication (#824, thanks @Jassy930)
- Fixed Skill ZIP symlink resolution (#1040, thanks @yovinchen)
- Added missing OpenCode checkbox in MCP add/edit form (#1026, thanks @yovinchen)
- Removed auto-import side effect from useProvidersQuery queryFn
---
## Performance
- Parallel directory scanning + head-tail JSONL reading for session panel, significantly improving session list loading speed
- Removed unnecessary TanStack Query cache overhead for Tauri local IPC calls
---
## Documentation
- Sponsor updates: SSSAiCode, Crazyrouter, AICoding, Right Code, MiniMax
- Added user manual documentation (#979, thanks @yovinchen)
---
## Notes & Considerations
- **OpenClaw is a newly supported app**: OpenClaw CLI must be installed first to use related features.
- **⚠️ Common Config Snippet feature has been removed**: Since provider switching now uses partial key-field merging (only replacing API keys, endpoints, models, etc.), user's other settings are automatically preserved, making Common Config Snippets unnecessary. See the "Architecture Improvements" section above for migration details.
- **Auto-import changed to manual**: External configurations are no longer auto-imported on startup. Click "Import Current Config" manually when needed.
- **OMO and OMO Slim are mutually exclusive**: Only one can be active at a time. Switching to one automatically disables the other.
- **Backup is enabled by default**: Automatic hourly backup during runtime. Adjust the policy in the Backup panel.
---
## Special Thanks
Thanks to all contributors for their contributions to this release!
| `CC-Switch-v3.11.0-macOS.zip` | **Recommended** - Extract and drag to Applications, Universal Binary |
| `CC-Switch-v3.11.0-macOS.tar.gz` | For Homebrew installation and auto-update |
> **Note**: Since the author doesn't have an Apple Developer account, you may see an "unidentified developer" warning on first launch. Please close it, then go to "System Settings" → "Privacy & Security" → click "Open Anyway", and it will open normally afterwards.
### Homebrew (macOS)
```bash
brew tap farion1231/ccswitch
brew install --cask cc-switch
```
Update:
```bash
brew upgrade --cask cc-switch
```
### Linux
| Distribution | Recommended Format | Installation Method |
CC Switch v3.11.0 は大規模なアップデートです。5番目のアプリケーション **OpenClaw** の完全管理サポートを追加し、新しい**セッションマネージャー**と**バックアップ管理**機能を導入しました。さらに、**Oh My OpenCode (OMO) 統合**、プロバイダー切り替えの**部分キーフィールドマージ**アーキテクチャアップグレード、**設定ページのリファクタリング**など、多数の改善により全体的な体験がさらに向上しました。
CC Switch v3.11.0 是一次大规模更新,新增第五个应用 **OpenClaw** 的完整管理支持,同时带来全新的**会话管理器**和**备份管理**功能。此外,**Oh My OpenCode (OMO) 集成**、供应商切换的**部分键值合并**架构升级、**设置页面重构**等多项改进使整体体验更加完善。
**变更前**:切换供应商时,整个 `settings_config` 会覆写到 live 配置文件。这意味着用户在 live 文件中手动添加的非供应商设置(插件配置、MCP 配置、权限设置等)会在每次切换时丢失。为了弥补这个问题,之前版本提供了"通用配置片段"功能,让用户定义每次切换时都会合并的公共配置。
CC Switch v3.11.1 is a hotfix release that reverts the **Partial Key-Field Merging** architecture introduced in v3.11.0, restoring the proven "**full config overwrite + Common Config Snippet**" mechanism. It also includes several UI and platform compatibility fixes.
- **Restore Full Config Overwrite + Common Config Snippet**: Reverted partial key-field merging due to critical data loss issues; restores full config snapshot write and Common Config Snippet UI
- **Proxy Panel Improvements**: Proxy toggle moved into panel body for better discoverability of takeover options
- **Theme & Compact Mode Fixes**: "Follow System" theme now auto-updates; compact mode exit works correctly
- **Windows Compatibility**: Disabled env check and one-click install to prevent protocol handler side effects
---
## Reverted
### Restore Full Config Overwrite + Common Config Snippet
Reverted the partial key-field merging refactoring introduced in v3.11.0 (revert 992dda5c).
**Why reverted**: The partial key-field merging approach had three critical issues:
1.**Data loss on switch**: Non-whitelisted custom fields were silently dropped during provider switching
2.**Permanent backfill stripping**: Backfill permanently removed non-key fields from the database, causing irreversible data loss
3.**Maintenance burden**: The whitelist of "key fields" required constant maintenance as new config keys were added
**What's restored**:
- Full config snapshot write on provider switch (predictable, complete overwrite)
- If you upgraded to v3.11.0 and your providers lost custom fields, re-import your config or manually re-add the missing fields
- Common Config Snippet is available again — use it to define shared config that should persist across provider switches
---
## Changed
- **Proxy Panel Layout**: Moved proxy on/off toggle from accordion header into panel content area, placed directly above app takeover options. This ensures users see takeover configuration immediately after enabling the proxy, avoiding the common mistake of enabling the proxy without configuring takeover
- **Manual Import for OpenCode/OpenClaw**: Removed auto-import on startup; empty state now shows an "Import Current Config" button, consistent with Claude/Codex/Gemini behavior
---
## Fixed
- **"Follow System" Theme Not Auto-Updating**: Delegated to Tauri's native theme tracking (`set_window_theme(None)`) so the WebView's `prefers-color-scheme` media query stays in sync with OS theme changes
- **Compact Mode Cannot Exit**: Restored `flex-1` on `toolbarRef` so `useAutoCompact`'s exit condition triggers correctly based on available width instead of content width
- **Proxy Takeover Toast Shows {{app}}**: Added missing `app` interpolation parameter to i18next `t()` calls for proxy takeover enabled/disabled messages
- **Windows Protocol Handler Side Effects**: Disabled environment check and one-click install on Windows to prevent unintended protocol handler registration
---
## Notes & Considerations
- **Common Config Snippet is back**: If you relied on this feature in v3.10.x and earlier, it works the same way again. Define shared config that should persist across all provider switches.
- **v3.11.0 Partial Key-Field Merging users**: If you noticed missing config fields after switching providers in v3.11.0, re-import your config to restore them.
---
## Download & Installation
Visit [Releases](https://github.com/farion1231/cc-switch/releases/latest) to download the appropriate version.
| `CC-Switch-v3.11.1-macOS.zip` | **Recommended** - Extract and drag to Applications, Universal Binary |
| `CC-Switch-v3.11.1-macOS.tar.gz` | For Homebrew installation and auto-update |
> **Note**: Since the author doesn't have an Apple Developer account, you may see an "unidentified developer" warning on first launch. Please close it, then go to "System Settings" → "Privacy & Security" → click "Open Anyway", and it will open normally afterwards.
### Homebrew (macOS)
```bash
brew tap farion1231/ccswitch
brew install --cask cc-switch
```
Update:
```bash
brew upgrade --cask cc-switch
```
### Linux
| Distribution | Recommended Format | Installation Method |
CC Switch v3.12.0 is a feature release focused on provider compatibility, OpenClaw editing, Common Config usability, and sync/data reliability. It restores the **Model Health Check (Stream Check)** UI with improved stability, adds **OpenAI Responses API** format conversion, expands provider presets for **Ucloud**, **Micu**, **X-Code API**, **Novita**, and **Bailian For Coding**, and upgrades **WebDAV sync** with dual-layer versioning.
- **Stream Check returns**: Restored the model health check UI, added first-run confirmation, and fixed `openai_chat` provider support
- **OpenAI Responses API**: Added `api_format = "openai_responses"` with bidirectional conversion and shared conversion cleanup — simply select the Responses API format when adding a provider and enable proxy takeover, and you can use GPT-series models in Claude Code!
- **OpenClaw overhaul**: Introduced JSON5 round-trip config editing, a config health banner, better agent model selection, and a User-Agent toggle
- **Preset expansion**: Added Ucloud, Micu, X-Code API, Novita, and Bailian For Coding updates, plus SiliconFlow partner badge and model-role badges
- **Sync and maintenance improvements**: Added WebDAV protocol v2 + db-v6 versioning, daily rollups, incremental auto-vacuum, and sync-aware backup
- **Common Config usability improvements**: After updating a Common Config Snippet, it is now automatically applied when switching providers — no more manual checkbox needed
---
## Main Features
### Model Health Check (Stream Check)
Restored the Stream Check panel for live provider validation, improving the reliability of provider management.
- Restored Stream Check UI panel with single and batch provider availability testing
- Added first-run confirmation dialog to prevent unsupported providers from showing misleading errors
- Fixed detection compatibility for `openai_chat` API format providers
### OpenAI Responses API
Added native support for providers using the OpenAI Responses API with a new `openai_responses` API format.
- New `api_format = "openai_responses"` provider format option
- Bidirectional Anthropic Messages <-> OpenAI Responses API format conversion
- Consolidated shared conversion logic to reduce code duplication
### Bedrock Request Optimizer
Added a PRE-SEND phase request optimizer for AWS Bedrock providers to improve compatibility and performance.
Common Config Snippets are now applied as a runtime overlay instead of being materialized into stored provider configs.
**Before**: Common Config content was merged directly into each provider's `settings_config` on save or switch. This caused shared configuration to be duplicated across every provider entry, requiring manual sync when changes were needed.
**After**: Common Config is only injected as a runtime overlay when switching providers and writing to the live file — provider entries themselves no longer contain shared configuration. This means modifying Common Config takes effect immediately without updating each provider individually.
### Common Config Auto-Extract
On first run, if no Common Config Snippet exists in the database, one is automatically extracted from the current live config. This ensures users upgrading from older versions do not lose their existing shared configuration settings.
### Periodic Maintenance Timer Consolidation
Consolidated daily rollups and auto-vacuum into a unified periodic maintenance timer, eliminating resource contention and complexity from multiple independent timers.
- Skip unnecessary OpenClaw config writes when config is unchanged, reducing disk I/O
---
## Documentation
- Restructured the user manual for i18n and added complete EN/JA coverage
- Added OpenClaw usage documentation and completed settings documentation
- Added UCloud sponsor information
- Reorganized the docs directory and synced README feature sections across EN/ZH/JA
---
## Notes & Considerations
- **Common Config now uses runtime overlay**: Common Config Snippets are no longer materialized into each provider's stored config. They are dynamically applied at switch time. Modifying Common Config takes effect immediately without updating each provider.
- **Stream Check requires first-use confirmation**: A confirmation dialog appears when using the model health check for the first time. Testing proceeds only after confirmation.
- **OpenClaw User-Agent toggle defaults to off**: The User-Agent identifier must be manually enabled in the OpenClaw configuration.
---
## Special Thanks
Thanks to all contributors for their contributions to this release!
| `CC-Switch-v3.12.0-macOS.zip` | **Recommended** - Extract and drag to Applications, Universal Binary |
| `CC-Switch-v3.12.0-macOS.tar.gz` | For Homebrew installation and auto-update |
> **Note**: Since the author doesn't have an Apple Developer account, you may see an "unidentified developer" warning on first launch. Please close it, then go to "System Settings" -> "Privacy & Security" -> click "Open Anyway", and it will open normally afterwards.
### Homebrew (macOS)
```bash
brew tap farion1231/ccswitch
brew install --cask cc-switch
```
Update:
```bash
brew upgrade --cask cc-switch
```
### Linux
| Distribution | Recommended Format | Installation Method |
**変更前**: Common Config の内容は保存時または切り替え時に各プロバイダーの `settings_config` に直接マージされていました。これにより共通設定が各プロバイダーエントリーにコピーされ、変更時には一つずつ同期する必要がありました。
**変更後**: Common Config はプロバイダー切り替え時に live ファイルへ書き込む際のみ runtime overlay として注入され、プロバイダーエントリー自体には共通設定を含みません。つまり Common Config の変更は即座に反映され、各プロバイダーを個別に更新する必要はありません。
### Common Config 初回自動抽出
初回起動時にデータベースに Common Config Snippet がまだ存在しない場合、現在の live config から自動抽出します。これにより旧バージョンからアップグレードしたユーザーの既存の共通設定が失われないことを保証します。
CC Switch v3.12.1 is a patch release focused on stability improvements and bug fixes. It resolves a Common Config modal infinite reopen loop, a WebDAV sync foreign key constraint failure, and several i18n interpolation issues. It also adds **StepFun** provider presets, **OpenClaw input type selection** and **authHeader** support, upgrades the default Gemini model to **3.1-pro**, and welcomes four new sponsor partners.
- **Common Config modal fix**: Resolved an infinite reopen loop in the Common Config modal and added draft editing support
- **WebDAV sync reliability**: Fixed a foreign key constraint failure when restoring `provider_health` during WebDAV sync
- **StepFun presets**: Added StepFun (阶跃星辰) provider presets including the step-3.5-flash model
- **OpenClaw enhancements**: Added input type selection for model Advanced Options and `authHeader` field for vendor-specific auth header support
- **Gemini model upgrade**: Upgraded default Gemini model to 3.1-pro in provider presets
- **New sponsors**: Welcomed Micu API, XCodeAPI, SiliconFlow, and CTok as sponsor partners
---
## New Features
### StepFun Provider Presets
Added provider presets for StepFun (阶跃星辰), a leading Chinese AI model provider.
- New preset entries for StepFun across supported applications
- Includes the step-3.5-flash model (#1369, thanks @hengm3467)
### OpenClaw Enhancements
Enhanced the OpenClaw configuration with more granular control and better vendor compatibility.
- Added input type selection dropdown for model Advanced Options (#1368, thanks @liuxxxu)
- Added optional `authHeader` boolean to `OpenClawProviderConfig` for vendor-specific auth header support (e.g. Longcat), and refactored form state to reuse the shared type
### Sponsor Partners
- **Micu API**: Added Micu API as sponsor partner with affiliate links
- **XCodeAPI**: Added XCodeAPI as sponsor partner
- **SiliconFlow**: Added SiliconFlow (硅基流动) as sponsor partner with affiliate links
- **CTok**: Added CTok as sponsor partner
---
## Changes
- **UCloud → Compshare**: Renamed UCloud provider to Compshare (优云智算) with full i18n support across all three locales (EN/ZH/JA)
| `CC-Switch-v3.12.1-macOS.zip` | **Recommended** - Extract and drag to Applications, Universal Binary |
| `CC-Switch-v3.12.1-macOS.tar.gz` | For Homebrew installation and auto-update |
> **Note**: Since the author doesn't have an Apple Developer account, you may see an "unidentified developer" warning on first launch. Please close it, then go to "System Settings" -> "Privacy & Security" -> click "Open Anyway", and it will open normally afterwards.
### Homebrew (macOS)
```bash
brew tap farion1231/ccswitch
brew install --cask cc-switch
```
Update:
```bash
brew upgrade --cask cc-switch
```
### Linux
| Distribution | Recommended Format | Installation Method |
CC Switch v3.12.2 is a reliability-focused patch release that addresses Common Config loss during proxy takeover and improves Codex TOML editing accuracy. Proxy takeover hot-switches and provider sync now update the restore backup instead of overwriting live config files; the startup sequence has been reordered so snippets are extracted from clean live files before takeover state is restored; and Codex `base_url` editing has been refactored into a section-aware model that no longer appends to the end of the file.
- **Empty state guidance**: Provider list empty state now shows detailed import instructions with a conditional Common Config snippet hint for Claude/Codex/Gemini
- **Proxy takeover restore flow rework**: Hot-switches and provider sync now refresh the restore backup instead of overwriting live config files, preserving the full user configuration on rollback
- **Snippet lifecycle stability**: Introduced a `cleared` flag to prevent auto-extraction from resurrecting cleared snippets, and reordered startup to extract from clean state
- **Section-aware Codex TOML editing**: `base_url` and `model` field reads/writes now target the correct `[model_providers.<name>]` section
- **Codex MCP config protection**: Existing `mcp_servers` blocks in restore snapshots survive provider hot-switches via per-server-id merge instead of wholesale replacement, with provider/common-config definitions winning on conflict
---
## New Features
### Empty State Guidance
Improved the first-run experience with helpful guidance when the provider list is empty.
- Empty state page shows step-by-step import instructions
- Conditionally displays a Common Config snippet hint for Claude/Codex/Gemini providers (not shown for OpenCode/OpenClaw)
---
## Changes
### Proxy Takeover Restore Flow
The proxy takeover hot-switch and provider sync logic has been reworked to protect Common Config throughout the takeover lifecycle.
- Provider sync now updates the restore backup instead of writing directly to live config files when takeover is active
- Effective provider settings are rebuilt with Common Config applied before saving restore snapshots, so rollback restores the real user configuration
- Legacy providers with inferred common config usage are automatically marked with `commonConfigEnabled=true`
### Codex TOML Editing Engine
Codex `config.toml` update logic has been refactored onto shared section-aware TOML helpers.
- New Rust module `codex_config.rs` with `update_codex_toml_field` and `remove_codex_toml_base_url_if`
- New frontend utilities `getTomlSectionRange` / `getCodexProviderSectionName` for section-aware operations
- Inline TOML editing logic scattered across `proxy.rs` now delegates to the new module
### Common Config Initialization Lifecycle
The startup sequence has been reordered for more robust snippet extraction and migration.
- Startup now auto-extracts Common Config snippets from clean live files before restoring proxy takeover state
- Introduced a snippet `cleared` flag to track whether a user intentionally cleared a snippet
- Persisted a one-time legacy migration flag to avoid repeated `commonConfigEnabled` backfills
---
## Bug Fixes
### Common Config Loss
- Fixed multiple scenarios where Common Config could be dropped during proxy takeover: sync overwriting live files, hot-switches producing incomplete restore snapshots, and provider switches losing config changes
### Codex Restore Snapshot Preservation
- Fixed Codex takeover restore backups discarding existing `mcp_servers` blocks during provider hot-switches; changed MCP backup preservation from wholesale table replacement to per-server-id merge so provider/common-config MCP updates win on conflict while backup-only servers are retained
### Cleared Snippet Resurrection
- Fixed startup auto-extraction recreating Common Config snippets that users had intentionally cleared
### Codex `base_url` Misplacement
- Fixed Codex `base_url` extraction and editing not targeting the correct `[model_providers.<name>]` section, causing it to append to the file tail or confuse `mcp_servers.*.base_url` entries for provider endpoints
---
## Download & Installation
Visit [Releases](https://github.com/farion1231/cc-switch/releases/latest) to download the appropriate version.
| `CC-Switch-v3.12.2-macOS.zip` | **Recommended** - Extract and drag to Applications, Universal Binary |
| `CC-Switch-v3.12.2-macOS.tar.gz` | For Homebrew installation and auto-update |
> **Note**: Since the author doesn't have an Apple Developer account, you may see an "unidentified developer" warning on first launch. Please close it, then go to "System Settings" -> "Privacy & Security" -> click "Open Anyway", and it will open normally afterwards.
### Homebrew (macOS)
```bash
brew tap farion1231/ccswitch
brew install --cask cc-switch
```
Update:
```bash
brew upgrade --cask cc-switch
```
### Linux
| Distribution | Recommended Format | Installation Method |
CC Switch v3.12.3 is a major feature release that adds GitHub Copilot reverse proxy support with a dedicated Auth Center, introduces macOS code signing and Apple notarization for a seamless install experience, maps reasoning effort levels across providers, migrates OpenCode to a SQLite backend, enables Tool Search via the native `ENABLE_TOOL_SEARCH` environment variable toggle, and delivers a full skill backup/restore lifecycle. Additional improvements include proxy gzip compression, o-series model compatibility, Skills import rework, Ghostty terminal fix, Skills cache strategy optimization, Claude 4.6 context window update, and multiple bug fixes.
- **GitHub Copilot reverse proxy**: Full Copilot proxy support with OAuth device flow authentication, token refresh, and request fingerprint emulation ([⚠️ Risk Notice](#️-risk-notice))
- **Copilot Auth Center**: Dedicated authentication management UI for GitHub Copilot OAuth flow with token status display and one-click refresh
- **macOS code signing & notarization**: macOS builds are now code-signed and notarized by Apple, eliminating the "unidentified developer" warning entirely
- **Reasoning Effort mapping**: Proxy-layer auto-mapping — explicit `output_config.effort` takes priority, falling back to `budget_tokens` thresholds (<4 000→low, 4 000–16 000→medium, ≥16 000→high) for o-series and GPT-5+ models
- **OpenCode SQLite backend**: Added SQLite session storage for OpenCode alongside existing JSON backend; dual-backend scan with SQLite priority on ID conflicts
- **Codex 1M context window toggle**: One-click checkbox to set `model_context_window = 1000000` with auto-populated `model_auto_compact_token_limit`
- **Disable Auto-Upgrade toggle**: Added `DISABLE_AUTOUPDATER` env var checkbox in the Claude Common Config editor to prevent Claude Code from auto-upgrading
- **Tool Search env var toggle**: Tool Search enabled via Claude 2.1.76+ native `ENABLE_TOOL_SEARCH` environment variable in the Common Config editor — no binary patching required
- **Skill backup/restore lifecycle**: Skills are automatically backed up before uninstall; backup list with restore and delete management added
- **o-series model compatibility**: Chat Completions proxy correctly uses `max_completion_tokens` for o1/o3/o4-mini models; Responses API kept on the correct `max_output_tokens` field
- **Skills import rework**: Replaced implicit filesystem-based app inference with explicit `ImportSkillSelection` to prevent incorrect multi-app activation
- **Ghostty terminal support**: Fixed Claude session restore in Ghostty terminal
---
## New Features
### GitHub Copilot Reverse Proxy
Added full reverse proxy support for GitHub Copilot, enabling Copilot-authenticated requests to be forwarded through CC Switch.
- Implements OAuth device flow authentication for GitHub Copilot
- Automatic token refresh and session management
- Request fingerprint emulation for seamless compatibility
- Integrated into the existing proxy infrastructure alongside Claude, Codex, and Gemini handlers
### Copilot Auth Center
A dedicated authentication management UI for GitHub Copilot.
- OAuth device flow with code display and browser-based authorization
- Token status display showing expiration and validity
- One-click token refresh without re-authentication
- Integrated into the settings panel for easy access
### Reasoning Effort Mapping
Proxy-layer auto-mapping of reasoning effort for OpenAI o-series and GPT-5+ models.
- Two-tier resolution: explicit `output_config.effort` takes priority, falling back to thinking `budget_tokens` thresholds (<4 000→low, 4 000–16 000→medium, ≥16 000→high)
- Covers both Chat Completions and Responses API paths with 17 unit tests
### OpenCode SQLite Backend
Added SQLite session storage support for OpenCode alongside the existing JSON backend.
- Dual-backend scan with SQLite priority on ID conflicts
- Atomic session deletion and path validation
- JSON backend remains functional for backwards compatibility
### Codex 1M Context Window Toggle
Added a one-click toggle for Codex 1M context window in the config editor.
- Checkbox sets `model_context_window = 1000000` in `config.toml`
- Auto-populates `model_auto_compact_token_limit = 900000` when enabled
- Unchecking removes both fields cleanly
### Disable Auto-Upgrade Toggle
Added a checkbox in the Claude Common Config editor to disable Claude Code auto-upgrades.
- Sets `DISABLE_AUTOUPDATER=1` in the environment configuration when enabled
- Displayed alongside Teammates mode, Tool Search, and High Effort toggles
### Tool Search Environment Variable Toggle
Tool Search is now enabled via the native `ENABLE_TOOL_SEARCH` environment variable introduced in Claude 2.1.76+.
- Toggle available in the Common Config editor under environment variables
- Sets `ENABLE_TOOL_SEARCH=1` in the Claude environment configuration
- No binary patching required — uses Claude's built-in support
### macOS Code Signing & Notarization
macOS builds are now code-signed and notarized by Apple.
- Application signed with a valid Apple Developer certificate
- Notarized through Apple's notarization service for Gatekeeper approval
- DMG installer also signed and notarized
- Eliminates the "unidentified developer" warning on first launch
### Skill Auto-Backup on Uninstall
Skill files are now automatically backed up before uninstall to prevent accidental data loss.
- Backups stored in `~/.cc-switch/skill-backups/` with all skill files and a `meta.json` containing original metadata
- Old backups are automatically pruned to keep at most 20
- Backup path is returned to the frontend and shown in the success toast
### Skill Backup Restore & Delete
Added management commands for skill backups created during uninstall.
- List all available skill backups with metadata
- Restore copies files back to SSOT, saves the DB record, and syncs to the current app with rollback on failure
- Delete removes the backup directory after a confirmation dialog
- ConfirmDialog gains a configurable zIndex prop to support nested dialog stacking
---
## Changes
### Skills Cache Strategy Optimization
Optimized the Skills cache invalidation strategy for better performance.
- Reduced unnecessary cache refreshes during skill operations
- Improved cache coherence between skill install/uninstall and list queries
### Claude 4.6 Context Window Update
Updated Claude 4.6 model preset with the latest context window size.
- Reflects the expanded context window for Claude 4.6 models
- Updated in provider presets for accurate model information display
### MiniMax M2.7 Upgrade
- Updated MiniMax provider preset to M2.7 model variant
### Xiaomi MiMo Upgrade
- Updated Xiaomi MiMo provider preset to the latest model version
### AddProviderDialog Simplification
- Removed redundant OAuth tab, reducing dialog from 3 tabs to 2 (app-specific + universal)
### Provider Form Advanced Options Collapse
- Model mapping, API format, and other advanced fields in the Claude provider form now auto-collapse when empty
- Auto-expands when any value is set or when a preset fills them in; does not auto-collapse when manually cleared
### Proxy Gzip Compression
Non-streaming proxy requests now support gzip compression for reduced bandwidth usage.
- Non-streaming requests let reqwest auto-negotiate gzip and transparently decompress responses
- Streaming requests conservatively keep `Accept-Encoding: identity` to avoid decompression errors on interrupted SSE streams
### o1/o3 Model Compatibility
Proxy forwarding now handles OpenAI o-series model token parameters correctly.
- Chat Completions path uses `max_completion_tokens` instead of `max_tokens` for o1/o3/o4-mini models (#1451, thanks @Hemilt0n)
- Responses API path kept on the correct `max_output_tokens` field instead of incorrectly injecting `max_completion_tokens`
### OpenCode Model Variants
- Placed OpenCode model variants at top level instead of inside options for better discoverability (#1317)
### Skills Import Flow
The Skills import flow has been reworked for correctness and cleanup.
- Replaced implicit filesystem-based app inference with explicit `ImportSkillSelection` to prevent incorrect multi-app activation when the same skill directory exists under multiple app paths
- Added reconciliation to `sync_to_app` to remove disabled/orphaned symlinks
- MCP `sync_all_enabled` now removes disabled servers from live config
- Schema migration preserves a snapshot of legacy app mappings to avoid lossy reconstruction
---
## Bug Fixes
### WebDAV Password Clearing
- Fixed an issue where the WebDAV password was silently cleared when saving unrelated settings
### Tool Message Parsing
- Fixed incorrect parsing of tool-use messages in certain proxy response formats
### Dark Mode Styling
- Fixed dark mode rendering inconsistencies in UI components
### Copilot Request Fingerprint
- Fixed request fingerprint generation for Copilot proxy to match expected format
### Provider Form Double Submit
- Prevented duplicate submissions on rapid button clicks in provider add/edit forms (#1352, thanks @Hexi1997)
### Ghostty Session Restore
- Fixed Claude session restore in Ghostty terminal (#1506, thanks @canyonsehun)
### Skill ZIP Import Extension
- Added `.skill` file extension support in ZIP import dialog (#1240, #1455, thanks @yovinchen)
### Skill ZIP Install Target App
- ZIP skill installs now use the currently active app instead of always defaulting to Claude
### OpenClaw Active Card Highlight
- Fixed active OpenClaw provider card not being highlighted (#1419, thanks @funnytime75)
### Responsive Layout with TOC
- Improved responsive design when TOC title exists (#1491, thanks @West-Pavilion)
### Import Skills Dialog White Screen
- Added missing TooltipProvider in ImportSkillsDialog to prevent runtime crash when opening the dialog
### Panel Bottom Blank Area
- Replaced hardcoded `h-[calc(100vh-8rem)]` with `flex-1 min-h-0` across all content panels to eliminate bottom gap caused by mismatched offset values on different platforms
---
## Documentation
### Pricing Model ID Normalization
- Added documentation section explaining model ID normalization rules (prefix stripping, suffix trimming, `@`→`-` replacement) in EN/ZH/JA user manuals (#1591, thanks @makoMakoGo)
### macOS Signed Build Messaging
- Removed all `xattr` workaround instructions and "unidentified developer" warnings from README, README_ZH, installation guides (EN/ZH/JA), and FAQ pages (EN/ZH/JA); replaced with "signed and notarized by Apple" messaging
---
## ⚠️ Risk Notice
**GitHub Copilot Reverse Proxy Disclaimer**
The Copilot reverse proxy feature introduced in this release accesses GitHub Copilot services through reverse-engineered, unofficial APIs. Please be aware of the following risks before enabling this feature:
1.**Terms of Service**: This feature may violate [GitHub's Acceptable Use Policies](https://docs.github.com/en/site-policy/acceptable-use-policies/github-acceptable-use-policies) and [Terms for Additional Products and Features](https://docs.github.com/en/site-policy/github-terms/github-terms-for-additional-products-and-features), which prohibit excessive automated bulk activity, unauthorized service reproduction, and placing undue burden on servers through automated means.
2.**Account Risk**: There are documented cases of GitHub issuing warning emails to users of similar tools, citing "scripted interactions or otherwise deliberately unusual or strenuous" usage patterns. Continued use after a warning may result in temporary or permanent suspension of Copilot access.
3.**No Guarantee**: GitHub may update its detection mechanisms at any time, and usage patterns that work today may be flagged in the future.
Users enable this feature **at their own risk**. CC Switch is not responsible for any account restrictions, warnings, or service suspensions resulting from the use of this feature.
---
## Download & Installation
Visit [Releases](https://github.com/farion1231/cc-switch/releases/latest) to download the appropriate version.
CC Switch v3.13.0 is a major feature release centered on observability, provider workflow ergonomics, and proxy compatibility. It adds inline **quota and balance displays** across official Claude / Codex / Gemini providers plus Token Plan, Copilot, and third-party balance APIs; introduces a **Lightweight Mode** that keeps CC Switch running from the system tray without a main window; delivers **automatic model discovery** via OpenAI-compatible `/v1/models` across all five supported applications; ships a **Codex OAuth reverse proxy** for ChatGPT subscribers; reorganizes the tray menu into **per-app submenus**; rebuilds the proxy forwarding stack on a **Hyper-based client**; and overhauls the **Skills workflow** with discovery, batch updates, storage-location toggling, and built-in skills.sh search and install. Additional improvements include full URL endpoint mode, enhanced token usage tracking, the Copilot interaction optimizer, a UTF-8 streaming chunk boundary fix for multi-byte output, a Linux startup UI responsiveness fix, and a friendlier new-user onboarding experience.
- **Lightweight Mode**: Tray-only operating mode that destroys the main window on exit to tray and recreates it on demand, reducing CC Switch's desktop footprint to near zero when idle
- **Quota & Balance Visibility**: Inline quota or balance readout across provider cards — official Claude / Codex / Gemini subscriptions, GitHub Copilot premium interactions, Codex OAuth, Token Plan providers (Kimi / Zhipu GLM / MiniMax), plus official balance queries for DeepSeek, StepFun, SiliconFlow, OpenRouter, and Novita AI
- **Provider Model Auto-Fetch**: OpenAI-compatible `/v1/models` discovery across Claude, Codex, Gemini, OpenCode, and OpenClaw provider forms, with grouped dropdown selection and failure-specific error messages
- **Codex OAuth Reverse Proxy**: ChatGPT Codex reverse proxy exposed as a new Claude provider card type, allowing users to use their ChatGPT subscription in Claude Code. Includes managed OAuth login and inline subscription quota display ([⚠️ Risk Notice](#️-risk-notice))
- **Tray Per-App Submenus**: Reworked the tray menu into per-application submenus so it never overflows the screen and background provider switching scales to dozens of providers per app
- **Skills Discovery & Batch Updates**: SHA-256-based skill update detection, per-skill and "Update All" batch actions, `skills.sh` search integration, and a storage-location toggle between CC Switch storage and `~/.agents/skills`
- **Session Workflow Upgrades**: Batch session deletion, a directory picker before launching Claude terminal restore, usage import from Claude / Codex / Gemini session logs without proxy interception, precise Codex JSONL parsing, and per-app usage filtering
- **OpenCode / OpenClaw Stream Check Coverage**: OpenCode detection via npm package mapping, OpenClaw `openai-completions` support, and the remaining OpenClaw protocol variants — with custom-header passthrough and auth-header detection fixes
- **Full URL Endpoint Mode**: Provider option that treats `base_url` as a complete upstream endpoint, unblocking vendors that require nonstandard URL layouts
- **Hyper-based Proxy Forwarding Stack**: Refactored proxy forwarding onto a Hyper-based client with transparent header forwarding, improved endpoint rewriting, and better support for dynamic upstream endpoints
- **Copilot Interaction Optimizer**: Request classification and routing logic that reduces unnecessary GitHub Copilot premium interaction consumption
- **UTF-8 Stream Chunk Boundary Fix**: All four SSE streaming paths now preserve incomplete multi-byte UTF-8 sequences across TCP chunks, eliminating intermittent U+FFFD garbled output via the Copilot reverse proxy
- **Linux Startup UI Fix**: Fixed the long-standing issue where the window UI couldn't receive clicks on Linux until the user manually maximized and restored the window
- **First-Run Onboarding**: One-time welcome dialog on fresh installs, automatic seeding of Claude / OpenAI / Google official presets, and auto-import of OpenCode / OpenClaw live configurations on startup
- **Claude Session Titles & Search Highlighting**: Meaningful title extraction for Claude sessions using a priority chain (custom-title metadata → first user message → directory basename), plus keyword highlighting in Session Manager search results
- **URL-Based Provider Icons**: Dual rendering mode supporting Vite URL imports for large SVGs and raster images (PNG, JPG, WebP), keeping small SVGs inlined
- **New Provider Presets**: TheRouter, DDSHub, LionCCAPI, Shengsuanyun (胜算云), PIPELLM, and E-FlowCode across supported applications
---
## New Features
### Lightweight Mode
A tray-only operating mode that dramatically reduces CC Switch's desktop footprint when idle.
- Destroys the main window on exit-to-tray instead of hiding it, freeing UI resources and memory
- Recreates the window on demand when the user reopens CC Switch from the tray, a deeplink, or single-instance activation
- Integrated into every window-re-show path: normal startup, deeplink, single_instance, tray `show_main`, and the lightweight-exit round-trip
### Quota & Balance Visibility
Added inline quota and balance readouts to provider cards so users can see remaining capacity without leaving the card.
- **Official subscriptions**: Inline quota display for Claude, Codex, and Gemini official providers
- **GitHub Copilot**: Premium interactions quota display on the Copilot provider card
- **Codex OAuth**: ChatGPT subscription quota inline with the Codex OAuth provider card
- **Token Plan providers**: Kimi, Zhipu GLM, and MiniMax usage progression display (requires manual activation to avoid confusion)
- **Third-party balances**: Official balance queries for DeepSeek, StepFun, SiliconFlow, OpenRouter, and Novita AI (requires manual activation to avoid confusion)
- Health-check and usage-config buttons are hidden for official providers to keep the card clean
### Provider Model Auto-Fetch
Added OpenAI-compatible model discovery to every provider form, removing the manual copy-paste loop for model IDs.
- Queries the configured provider endpoint's `/v1/models`
- Groups models in the dropdown by category for easier selection
- Supported across all five applications: Claude, Codex, Gemini, OpenCode, and OpenClaw
### Codex OAuth Reverse Proxy
Added a reverse proxy path for ChatGPT subscribers who want to use their ChatGPT subscription in Claude Code.
- Managed OAuth login flow with ChatGPT authentication
- Surfaces as a new Claude provider card type alongside API-key providers
- Inline subscription quota display
- Integrated into the Auth Center for unified token management
- See the [⚠️ Risk Notice](#️-risk-notice) below before enabling
### Tray Per-App Submenus
Reorganized the tray menu so providers are grouped under each application instead of living in a flat list.
- Per-application submenus for Claude, Codex, Gemini, OpenCode, and OpenClaw
- Prevents the tray menu from overflowing the screen when users have many providers
- Background provider switching scales cleanly to long provider lists
### Skills Discovery & Batch Updates
Upgraded the Skills management panel into a complete discovery plus maintenance workflow.
- **SHA-256 update detection**: Skills are content-hashed so the UI knows exactly which ones have upstream changes
- **Per-skill and batch updates**: Individual "Update" buttons plus an animated "Update All" batch action
- **Storage-location toggle**: Switch between CC Switch storage and `~/.agents/skills` without losing skill state
- **Public registry search**: `skills.sh` search integrated directly into the dialog for discovering community skills
### Session Workflow Upgrades
Multiple session management improvements that reduce friction when working with Claude / Codex / Gemini sessions.
- **Batch session deletion**: Select and delete multiple sessions at once from Session Manager (#1693, thanks @Alexlangl)
- **Directory picker before restore**: Claude terminal restore now prompts for the working directory up front (#1752, thanks @yovinchen)
- **Usage from session logs without proxy**: Usage data imported directly from Claude / Codex / Gemini session logs — no proxy interception required
- **Precise Codex JSONL parsing**: Replaced estimated Codex usage with precise JSONL session-log parsing plus Codex model name normalization for consistent pricing lookup
- **Gemini CLI session log integration**: Gemini usage now syncs accurately from Gemini CLI session logs
- **Per-app usage filtering**: Filter the usage dashboard by Claude, Codex, or Gemini independently
### OpenCode / OpenClaw Stream Check Coverage
Extended the Stream Check panel to cover the full OpenCode and OpenClaw surface area.
- OpenCode detection via npm package mapping
- Support for the OpenClaw `openai-completions` protocol
- Support for the remaining three OpenClaw protocol variants
- Edge-case handling for custom-header passthrough, OpenClaw custom auth-header detection, Bedrock error messaging, and OpenCode default `baseURL` fallback
### Full URL Endpoint Mode
Added a provider option that treats `base_url` as a complete upstream endpoint instead of a base URL with path appending (#1561, thanks @yovinchen).
- Proxy forwarding and Stream Check both honor the full-URL mode
- Unblocks vendors that require nonstandard URL layouts
- Configurable per-provider on the provider form
### OpenCode StepFun Step Plan Preset
- Added a StepFun Step Plan provider preset for OpenCode with sensible defaults (#1668, thanks @sky-wang-salvation)
### Copilot Interaction Optimizer
Added request classification and routing logic that reduces unnecessary GitHub Copilot premium interaction consumption.
- Classifies incoming requests by intent and weight
- Routes low-value requests away from premium interaction consumption paths
- Designed to extend the usable lifetime of a Copilot subscription
- Note: Even with optimized consumption, using the Copilot API outside of Copilot still consumes more than using it within Copilot.
### First-Run Welcome Dialog
Added a one-time welcome dialog on fresh installs to guide new users through the CC Switch workflow.
- Explains how existing live configuration is preserved as a default provider
- Introduces the bundled official preset that enables one-click revert to official endpoints
- Upgrade users are automatically excluded via empty provider check
### Official Provider Seeding
- Added automatic seeding of Claude Official, OpenAI Official, and Google Official provider entries on startup, giving every user a one-click path back to the official endpoint
### OpenCode / OpenClaw Auto-Import
- Added automatic startup import of live OpenCode and OpenClaw provider configurations, matching the auto-import behavior already present for Claude, Codex, and Gemini
### Common Config Editor Guidance
- Added an informational guide and empty-state prompt to the Common Config snippet editor modal for Claude, Codex, and Gemini
- Added a one-time informational dialog explaining Common Config Snippets when users first open the provider add/edit form
### Claude Session Titles & Search Highlighting
- Added meaningful title extraction for Claude sessions using a priority chain: custom-title metadata, first real user message, then directory basename fallback
- Added keyword highlighting in session titles and messages during Session Manager search
### URL-Based Provider Icons
- Added a dual rendering mode to the icon system: small SVGs are inlined as React components, while large SVGs and raster images (PNG, JPG, WebP) are loaded via Vite URL imports as `<img>` tags
### Kaku Terminal Support
- Added Kaku as a selectable terminal for session launch on macOS, reusing the WezTerm-compatible launch path (#1983, thanks @yovinchen)
### OMO Slim Council Support
- Restored first-class council support as a built-in oh-my-opencode-slim agent with updated metadata and UI copy (#1982, thanks @yovinchen)
### New Provider Presets
- **TheRouter**: Added across Claude, Codex, Gemini, OpenCode, and OpenClaw (#1891, #1892, thanks @cmzz)
- **DDSHub**: Added as a third-party partner provider for Claude with icon and partner promotion text
- **LionCCAPI**: Added across all five apps with anthropic-messages protocol for OpenCode and OpenClaw
- **Shengsuanyun (胜算云)**: Added as an aggregator partner provider across all five apps with URL-based icon and localized display name
- **PIPELLM**: Added across Claude, Codex, OpenCode, and OpenClaw with full model definitions and icon
- **E-FlowCode**: Added across all five apps with per-app protocol configuration
---
## Changes
### Tray Menu Organization
- Reworked the tray menu into per-application submenus (Claude / Codex / Gemini / OpenCode / OpenClaw)
- Prevents overflow and scales to long provider lists
### Proxy Forwarding Stack
Rebuilt the proxy forwarding layer on a Hyper-based HTTP client (#1714, thanks @yovinchen).
- Transparent header forwarding: headers are forwarded without aggressive filtering
- Improved endpoint rewriting logic
- Better support for dynamic upstream endpoints
- Paired with the new Full URL Endpoint Mode to unblock vendors with nonstandard URL layouts
### OAuth Auth Center UI Polish
- Tightened the Auth Center copy, layout, and icon presentation so the Codex OAuth login flow feels cleaner and less cluttered
### Provider Key Lifecycle & Live Sync
Reworked the additive provider create / rename / duplicate flows so live config writes, cleanup, and rollback stay consistent across OpenCode / OpenClaw and takeover scenarios (#1724, thanks @yovinchen).
- Additive-mode highlight behavior made persistent across refreshes (#1747, thanks @yovinchen)
- Consistent live config writes across OpenCode / OpenClaw
- Rollback behavior preserved when operations fail
### Codex OAuth Defaults
- Updated the Codex OAuth preset to the GPT-5.4 model family
- Corrected enterprise and dynamic endpoint handling
- Repaired clipboard verification-code copying on macOS and Linux
- Fixed Responses routing when Copilot-backed Claude providers target OpenAI models (#1735, thanks @Mason-mengze)
### UTF-8 Stream Chunk Boundaries
Fixed intermittent garbled output (U+FFFD replacement characters) in Claude Code when multi-byte UTF-8 sequences such as Chinese characters and emoji were split across TCP stream chunks via the Copilot reverse proxy (#1923, thanks @Cod1ng).
- Replaced `String::from_utf8_lossy` with a new `append_utf8_safe` helper across all four SSE streaming paths
- Preserves incomplete trailing bytes in a remainder buffer and merges them with the next chunk before decoding
- Not reproducible with direct Copilot connections that pass through raw bytes without format conversion
### Fragmented System Prompt Normalization
Fixed strict OpenAI-compatible chat backends (Nvidia, Qwen-style) rejecting requests when converted Claude payloads contained multiple system messages (#1942, thanks @yovinchen).
- Normalized system content into a single leading system message during the Anthropic → OpenAI chat transformation
- Leaves the rest of the message stream unchanged
### Streaming Parser Compatibility
- Fixed SSE parsing to accept fields with optional spaces, improving compatibility with non-strict streaming implementations (#1664, thanks @Alexlangl)
### Provider Switch State Corruption
- Serialized per-app provider switches to prevent concurrent failover or hot-switch operations from leaving `is_current`, settings state, and live backup state out of sync
### Claude Takeover Live Config Drift
- Fixed provider edits while Claude takeover is active so live settings remain aligned with the latest provider state without breaking takeover restore behavior (#1828, thanks @geekdada)
### WebDAV Password Retention & Validation
- Fixed the WebDAV password field so saved credentials remain visible after refresh
- Aligned usage display layout across provider cards by always rendering action buttons
- Replaced hard proxy-switch blocking with a warning path
- Disabled unsupported test and usage actions for Copilot and Codex OAuth cards
- Hid usage-config and health-check buttons for official providers
- Removed the hover-push animation from provider cards
### Usage Accuracy & Pricing
- Fixed MiniMax quota math and 0% → 100% progression
- Corrected CNY → USD pricing plus missing model definitions
- Improved Gemini session-log syncing accuracy
- Resolved session-based usage entries being shown as unknown providers
### Usage Editor & Skills UI Regressions
- Fixed usage query fields being reset while editing extractor code (#1771, thanks @if-nil)
- Corrected broken `skills.sh` links and empty descriptions
- Fixed auto-query default interval (5 min) and number-input clearing in usage configuration
### Chinese Skills Terminology
- Unified Skills-related labels across settings panels in the `zh` locale so storage and sync options use consistent wording
### Environment & Preset Compatibility
- Added Bun global bin detection in CLI scan (#1742, thanks @makoMakoGo)
- Adapted to the oh-my-openagent rename with backward compatibility (#1746, thanks @yovinchen)
- Corrected the OpenCode `kimi-for-coding` preset (#1738, thanks @makoMakoGo)
- Gated Gemini keychain parsing to macOS only
- Fixed an OpenClaw serializer panic on empty collections (#1724, thanks @yovinchen)
### Linux UI Unresponsive on Startup
Fixed a long-standing Linux bug where the window UI (including native title bar buttons) couldn't receive clicks until the user manually maximized and restored the window.
- **Root causes**: (1) Tauri webview did not acquire keyboard focus after `show()` on Linux, so the first click was consumed by X11/Wayland click-to-activate (Tauri #10746, wry #637); (2) GTK surface's input region failed to renegotiate on the `visible:false → show()` path under some WebKitGTK/compositor combinations, leaving the entire window unresponsive
- **Mitigations**: Set `WEBKIT_DISABLE_COMPOSITING_MODE=1` at startup, and added a new `linux_fix::nudge_main_window` helper that performs `set_focus` + a ±1px no-op resize ~200ms after show, equivalent to a visually invisible "maximize-and-restore"
- **Coverage**: Wired into all window-re-show paths — normal startup, deeplink, single_instance, tray `show_main`, and lightweight-mode exit
### Linux Drag Region on Header
- Removed `data-tauri-drag-region` from the top header bar on Linux to avoid triggering `gtk_window_begin_move_drag` paths affected by Tauri #13440 under Wayland
- macOS drag behavior is preserved
### OpenCode / OpenClaw Stream Check Edge Cases
- Fixed custom-header passthrough
- OpenClaw custom auth-header detection
- Bedrock error messaging
- OpenCode default `baseURL` fallback handling
### Duplicate Toast on Provider Switch
- Fixed double toast notifications (proxy-required warning followed by switch-success) when switching to Copilot, ChatGPT, or OpenAI-format providers with the proxy not running
### Session Search Accuracy & Chinese Support
- Fixed session search result truncation across providers
- Switched FlexSearch tokenizer to full mode for proper Chinese substring matching
### Adaptive Thinking Reasoning Effort
- Fixed `resolve_reasoning_effort()` mapping adaptive thinking to `xhigh` instead of incorrectly using `high` in OpenAI format conversions
### Thinking Model Fallback Display
- Fixed the Claude provider form showing an empty Thinking model field after saving only a main model by applying read-only fallback to ANTHROPIC_MODEL (#1984, thanks @yovinchen)
### Auth Tab Localization
- Fixed missing i18n translation keys for the settings auth tab label across all locale bundles (#1985, thanks @yovinchen)
### Schema Migration Guard
- Fixed database migrations failing when skills or model_pricing tables did not exist by adding table-existence checks before ALTER and UPDATE operations
---
## Documentation
### User Manual Refresh
- Updated the EN / ZH / JA user manuals to cover tray submenus, lightweight mode, provider model fetching, session management, workspace files, WebDAV v2 behavior, OpenCode / OpenClaw activation, and other provider workflow improvements
### Community & Contribution Docs
- Added `CONTRIBUTING.md`, `SECURITY.md`, and `CODE_OF_CONDUCT.md`
- Added bilingual GitHub issue and PR templates
- Added Dependabot configuration (#1829, thanks @bengbengbalabalabeng) and a stale-bot workflow for inactive issues
- Added a PR / push quality-checks CI workflow
### Release Notes Risk Notice Backport
- Added a Copilot reverse proxy risk notice and anchored highlight links in the v3.12.3 release notes across all three languages
### Sponsor Partners
- Added Shengsuanyun, LionCC, and DDS as sponsor partners in README across all languages
---
## ⚠️ Risk Notice
**Codex OAuth Reverse Proxy Disclaimer**
The Codex OAuth reverse proxy introduced in this release accesses ChatGPT Codex services through reverse-engineered OAuth flows. Please be aware of the following risks before enabling this feature:
1.**Terms of Service**: Using reverse-engineered OAuth flows to access OpenAI services may violate OpenAI's terms of service, which prohibit unauthorized automated access, service reproduction, and circumventing intended access paths.
2.**Account Risk**: OpenAI may flag unusual usage patterns as suspicious automated activity, potentially resulting in temporary or permanent restrictions on ChatGPT access.
3.**No Guarantee**: OpenAI may update its authentication and detection mechanisms at any time, and usage patterns that work today may be flagged in the future.
The **GitHub Copilot reverse proxy** introduced in v3.12.3 also remains subject to its existing risk notice — see the [v3.12.3 release notes](v3.12.3-en.md#️-risk-notice) for the full disclosure.
Users enable these features **at their own risk**. CC Switch is not responsible for any account restrictions, warnings, or service suspensions resulting from the use of these features.
---
## Download & Installation
Visit [Releases](https://github.com/farion1231/cc-switch/releases/latest) to download the appropriate version.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.