Commit Graph

1104 Commits

  • feat: unify Codex third-party providers into stable "custom" history bucket
    Codex filters resume history by `model_provider`, so switching between
    provider-specific ids like `rightcode` and `aihubmix` made past sessions
    appear to vanish. Collapse all third-party providers into a single
    stable bucket so cross-switch history stays visible.
    
    - Normalize live `model_provider` to "custom" on every Codex write
      (reserved built-in ids like openai/ollama are preserved).
    - Add device-level one-shot migration that rewrites historical JSONL
      session files and the `state_5.sqlite` threads table from legacy
      provider ids into the "custom" bucket. Backs up originals under
      `~/.cc-switch/backups/codex-history-provider-migration-v1/` and uses
      the SQLite Backup API for the state DB.
    - Record completion in `settings.json` under `localMigrations` so the
      migration is strictly idempotent across launches.
    - Update Codex provider preset templates to emit `model_provider = "custom"`
      out of the box.
  • fix: prevent infinite render loop in Codex model catalog
    Break bidirectional sync cycle between catalogRows (child) and catalogModels (parent):
    - Remove catalogModels from child→parent effect dependencies
    - Track last sent data in ref to avoid redundant callbacks
    - Sync ref when parent pushes new data to prevent false positives
    
    Fixes severe UI jittering when adding/editing catalog entries.
  • fix: Codex model catalog WYSIWYG and config consolidation
    - Remove mergeCodexDefaultCatalogModelForSave implicit injection (P1)
      The model mapping table is now the single source of truth; no hidden
      entries are prepended on save.
    
    - Sync first catalog row model into config.toml on save
      Ensures Codex default request model matches the table's first entry
      instead of retaining a stale template value.
    
    - Remove API Format selector from CodexFormFields (P3)
      wire_api is always 'responses'; the selector confused users into
      thinking they were changing the upstream protocol. Only the 'Needs
      Local Routing' toggle remains.
    
    - Add restart hint to model mapping i18n text (P2)
      model_catalog_json is loaded at Codex startup; users are now informed
      that a restart is needed after changes.
    
    - Unify write_codex_live_with_catalog helper (P4)
      Replaces three scattered prepare+write call sites in config.rs,
      provider/live.rs, and proxy.rs with a single entry point.
    
    - Clean up useCodexConfigState dead state (P3 follow-up)
      Remove codexModelName, codexContextWindow, codexAutoCompactLimit and
      their handlers/effects since no component consumes them after the UI
      consolidation.
  • Add Codex Chat-to-Responses bridge
    - Add Codex provider API format selection and model mapping for Chat-only upstreams.
    - Convert Codex Responses requests to Chat Completions and rebuild Chat responses as Responses output.
    - Preserve reasoning_content across non-streaming, streaming, tool calls, and previous_response_id follow-ups.
    - Add a bounded Codex Chat history cache for restoring tool calls before tool outputs.
    - Cover Chat bridge, compact routing, streaming, and history recovery with focused tests.
  • Add Chat Completions routing for Codex providers
    - Add a Codex API format selector and routing badge for Chat Completions providers.
    - Convert Codex Responses requests to upstream Chat Completions when routing is required.
    - Convert Chat Completions JSON and SSE responses back to Responses format.
    - Keep generated Codex wire_api values on Responses for Codex compatibility.
    - Add i18n labels, provider metadata handling, and focused conversion tests.
  • chore: remove LionCC sponsor and presets
    - Remove LionCC sponsor entry from all README files (en/zh/ja)
    - Remove LionCCAPI presets from all provider configs
    - Remove lionccapi i18n keys from all locales
    - Keep lioncc.png icon file as requested
  • fix(skills): install correct skill from skills.sh search results (#2784)
    * fix(skills): install correct skill from skills.sh search results
    
    When multiple skills share the same directory name across different repos,
    SkillCard was passing directory to onInstall/onUninstall, causing handleInstall
    to always match the first result. Switch to using the unique key field
    (directory:repoOwner:repoName) for precise identification.
    
    * test(skills): add regression test for skills.sh install by key
    
    Verifies that clicking install on the second card when two skills share
    the same directory name correctly installs the second skill, not the first.
    
    ---------
    
    Co-authored-by: mrzhao <mrzhao@iflytek.com>
  • fix(usage): reduce price input step to 0.0001 for sub-cent precision (#2793)
    The step was 0.01, preventing input of prices like DeepSeek's cache read
    cost ($0.0028/million tokens). Extract step value to a constant and apply
    to all four price fields.
    
    Closes #2503
  • feat: add Xiaomi MiMo Token Plan presets (#2803)
    * feat: add Xiaomi MiMo token plan presets
    
    * fix: update Xiaomi MiMo provider presets
    
    * fix: align MiMo V2.5 model specs with official documentation
    
    - Update maxTokens from 32000 to 131072 (128K) for mimo-v2.5-pro and mimo-v2.5
    - Update contextWindow from 262144 to 1048576 (1M) for mimo-v2.5
    - Aligns with official specs from Xiaomi MiMo documentation
    - Ensures consistency between OpenClaw and OpenCode presets
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>
  • Fix race condition in useEffect hooks and type assertion bug (#2827)
    - Add active flag pattern to 3 useEffect hooks in App.tsx to prevent
      event listener leaks when component unmounts before async setup completes
    - Add guard check in useSettings.ts to prevent undefined from being
      stored in localStorage when payload.language is missing
    
    Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
  • Add Claude Desktop official preset
    - Add Claude Desktop Official to the Claude Desktop preset list.
    - Treat selected official presets as official mode in the form.
    - Cover the official preset with a preset-order regression test.
  • refactor(presets): render presets in array order and prioritize partners
    Remove the category-based grouping logic from ProviderPresetSelector,
    letting the array position in each preset config file be the single
    source of truth for display order. Move partner presets (PatewayAI,
    火山Agentplan, BytePlus, DouBaoSeed) right after Shengsuanyun across
    all 6 config files so they appear earlier in the UI.
  • feat(presets): add BytePlus provider preset as partner
    Add BytePlus (international Volcengine) to Claude, Claude Desktop,
    Hermes, OpenCode, and OpenClaw with byteplus icon, 256K context window,
    and trilingual promotion text.
  • feat(presets): add 火山Agentplan provider preset as partner
    Add Volcengine Ark Agentplan to Claude, Claude Desktop, Hermes,
    OpenCode, and OpenClaw with huoshan icon and trilingual promotion.
  • chore(presets): update DouBaoSeed endpoint, links, and add as partner
    Switch Anthropic-format base URL from /api/coding to /api/compatible,
    update website/apiKey URLs to Volcengine console with tracking params,
    and promote DouBaoSeed to partner with trilingual promotion text.
  • chore(presets): switch RelaxyCode icon to custom relaxcode.png
    Replace the generic claude icon with a dedicated relaxcode.png icon
    for the RelaxyCode provider presets.
  • feat(presets): add RelaxyCode provider presets
    Add RelaxyCode as a new third-party provider with support for:
    - Claude Code preset (Anthropic native protocol)
    - Codex preset (gpt-5.5 model)
    - Claude Desktop preset (direct mode with passthrough routes)
    
    RelaxyCode is an enterprise-grade AI programming platform providing
    unified access to Claude Code, Codex, and Gemini CLI models.
  • feat(presets): add RunAPI provider presets
    Add RunAPI as a new partner provider with support for:
    - Claude Code preset (Anthropic native protocol)
    - Codex preset (gpt-5.5 model)
    - Claude Desktop preset (direct mode with passthrough routes)
    - OpenCode preset (@ai-sdk/anthropic)
    - OpenClaw preset (anthropic-messages protocol)
    - Hermes preset (anthropic_messages mode)
    - Icon configuration (runapi.jpg)
    - i18n support (zh/en/ja) with ¥14 free credit promotion
    
    RunAPI is a high-performance AI model API gateway supporting 150+
    mainstream models (OpenAI, Claude, Gemini, DeepSeek, Grok) with
    prices as low as 10% of official rates.
  • feat(presets): add ClaudeCN provider presets
    Add ClaudeCN as a new partner provider with support for:
    - Claude Code preset (Anthropic native protocol)
    - Codex preset (gpt-5.5 model)
    - Claude Desktop preset (direct mode with passthrough routes)
    - OpenCode preset (@ai-sdk/anthropic)
    - OpenClaw preset (anthropic-messages protocol)
    - Hermes preset (anthropic_messages mode)
    - Icon configuration (claudecn.png)
    - i18n support (zh/en/ja) with enterprise service promotion
    
    ClaudeCN is an enterprise-grade AI gateway operated by a registered
    company, supporting enterprise procurement processes with corporate
    payments, contracts, and compliance guarantees.
  • feat(presets): add ClaudeAPI provider presets
    Add ClaudeAPI as a new partner provider with support for:
    - Claude Code preset (using ANTHROPIC_AUTH_TOKEN field)
    - Claude Desktop preset (direct mode with passthrough routes)
    - Icon configuration (ClaudeApi.png)
    - i18n support (zh/en/ja) with test credit promotion
    
    ClaudeAPI provides official Anthropic API keys and AWS Bedrock
    routing with support for Tool Use and 1M context.
  • refactor(presets): switch 20 Claude Desktop providers from proxy to direct mode
    - Change mode from "proxy" to "direct" for 20 third-party/aggregator providers
    - Simplify PipeLLM from mappedRoutes to passthroughRoutes for consistency
    - Reduces unnecessary proxy layer overhead for providers that support direct API calls
    
    Affected providers: ShengSuanYun, AIHubMix, DMXAPI, PackyAPI, PatewayAI,
    Cubence, AIGoCode, RightCodes, AICodeMirror, AICoding, CrazyRouter,
    SSSAICode, ModelVerse, CompShare, MicuAPI, CTOK, E-FlowCode,
    VibeCodingAPI, LemonData, PipeLLM
  • feat(presets): add PatewayAI provider presets
    Add PatewayAI as a new partner provider with support for:
    - Claude Code preset (using ANTHROPIC_API_KEY field)
    - Codex preset (gpt-5.5 model)
    - Claude Desktop preset (proxy mode with passthrough routes)
    - Icon configuration (pateway.jpg)
    - i18n support (zh/en/ja) with $3 registration bonus promotion
    
    PatewayAI provides reliable API routing services for Claude Code,
    Codex, and Gemini models.
  • fix(failover): patch P1-P3 reliability gaps surfaced by team review
    - Forwarder buffers non-streaming bodies and primes streaming first
      chunk before signaling success, so body timeouts and SSE first-chunk
      failures route through the circuit breaker instead of being recorded
      as success on response-header arrival
    - Atomic enable-failover: switch to P1 before persisting the flag, and
      roll back auto-added queue entries when the switch is rejected
      (e.g. official providers)
    - Hot-reload circuit breaker config on per-app proxy config change
      instead of waiting for a proxy restart
    - FailoverToggle / FailoverQueueManager / AutoFailoverConfigPanel
      require proxy takeover for the active app; the backend command also
      rejects enabling when takeover is off
    - ProviderHealthBadge consumes the backend is_healthy flag instead of
      hardcoding the 5-failure threshold
    
    Cleanup:
    - impl From<&AppProxyConfig> for CircuitBreakerConfig and use it from
      the command layer
    - Collapse three identical TabsContent blocks into a single map
  • feat(providers): add routing support badges for Claude Code and Codex
    Add visual indicators for routing capabilities on provider cards:
    - Claude Code: "Needs Routing" badge for non-official providers with non-anthropic API formats
    - Claude Code: "No Routing Support" badge for official providers
    - Codex: "No Routing Support" badge for official providers
    
    The badges help users understand which providers support format conversion through routing.
  • chore(presets): migrate OpenClaudeCode to MicuAPI domain
    Replace all openclaudecode.cn URLs with micuapi.ai across all
    provider presets (Claude, Codex, Hermes, OpenClaw, OpenCode,
    Claude Desktop). This includes website URLs, API key URLs, and
    base URLs.
  • chore(presets): update CrazyRouter API endpoints to cn subdomain
    Update all CrazyRouter baseURL configurations from crazyrouter.com
    to cn.crazyrouter.com across all supported applications (Claude,
    Codex, Gemini, Hermes, OpenClaw, OpenCode, Claude Desktop).
    
    Website and registration URLs remain unchanged.
  • chore(partners): remove DDSHub partner integration
    Remove DDSHub from all provider presets (Claude, Claude Desktop, Codex, Hermes),
    i18n files (zh/en/ja), README docs, and icon system. Physical assets retained for
    potential future restoration.
  • fix(providers): disable model test for third-party Claude providers
    Most third-party Claude Code providers now reject requests from
    non-official clients, so the model test button would just produce
    noisy failures (or worse, trigger risk controls on the provider
    side). Treat third-party Claude providers the same way as official /
    Copilot / Codex OAuth: pass onTest=undefined so ProviderActions
    renders the test button in its existing disabled visual state.
  • feat(codex-oauth): fetch model list from ChatGPT backend on demand
    - Add `get_codex_oauth_models` Tauri command reusing the managed OAuth
      access token to hit `chatgpt.com/backend-api/codex/models`; HTTP and
      multi-shape JSON parsing live in `services::codex_oauth_models` so the
      command stays thin.
    - Unify the Claude form's "fetch models" button across normal / Copilot /
      Codex OAuth presets, drop the auto-load effect for Copilot in favor of
      explicit clicks, and guard against stale responses with a requestId ref.
    - Add Vitest coverage for both Copilot and Codex OAuth paths asserting no
      request on mount and the correct account id on click; add Rust unit
      tests for the four model-list payload shapes.
  • fix(usage): pricing routing, SSE lifecycle, and validation hardening
    * model pricing routing: extend prefix-match families (gpt-/o1-o5/
      gemini-/deepseek-/qwen-/glm-/kimi-/minimax-) with per-family dash
      thresholds so short base IDs like gpt-5 no longer mis-match
      gpt-5-mini; strip ISO and 8-digit date suffixes via UTF-8-safe
      byte matching so claude-haiku-4-5-20251001 falls back to
      claude-haiku-4-5 pricing
    * SSE collector: SseUsageFinishGuard (RAII) guarantees finish() on
      early return or panic; AtomicBool fast path lets push() skip the
      Mutex once first-event time is recorded
    * validation: shared validate_cost_multiplier / validate_pricing_source
      helpers across DAO and service layers; PRICING_SOURCE_RESPONSE /
      PRICING_SOURCE_REQUEST constants replace string literals; price
      fields in update_model_pricing now reject empty / non-decimal /
      negative input before INSERT
    * backfill: add backfill_missing_usage_costs_for_model so a single
      price edit only scans matching rows instead of the full log table;
      startup backfill remains full-scan
    * session_usage{,_codex,_gemini}: share find_model_pricing helper from
      usage_stats; metadata_modified_nanos centralizes mtime precision
    * frontend: NON_NEGATIVE_DECIMAL_REGEX + isNonNegativeDecimalString
      replace three copies of the same multiplier regex; isUnpricedUsage
      surfaces zero-cost rows that have usage tokens (cached per row to
      avoid double evaluation); invalidate usageKeys.all on pricing mutate
      so backfilled rows refresh
  • fix(proxy-ui): accept IPv6 listen addresses in ProxyPanel validation
    The backend already understands `::` -> `::1` and wraps IPv6 literals
    in brackets (services/proxy.rs), but the panel's save-time validator
    only accepted localhost, 0.0.0.0, and IPv4 dotted-quads. Users who
    wanted to listen on an IPv6 loopback had to bypass the UI and edit
    config directly.
    
    Add an isValidIpv6 helper that requires at least one ':' and round-trips
    through `new URL('http://[<addr>]/')` so the platform's built-in IPv6
    parser does the heavy lifting (covers compressed `::`, full 8-group
    form, zone IDs). Update the invalidAddress copy in zh / en / ja so the
    error message reflects the new accepted set.
  • feat(claude-code): role-based model mapping with display names and 1M flag
    - Replace the four flat env inputs with a Sonnet/Opus/Haiku role table.
      Each row exposes ANTHROPIC_DEFAULT_*_MODEL plus a new display name
      field ANTHROPIC_DEFAULT_*_MODEL_NAME, and Sonnet/Opus gain a
      "Declare 1M" checkbox that toggles the [1M] suffix.
    - Strip the [1M] context-capability marker before forwarding non-Copilot
      requests upstream. Copilot keeps its existing [1m]->-1m normalization.
    - Claude Desktop import now consumes ANTHROPIC_DEFAULT_*_MODEL_NAME as
      label_override, closing the Claude Code -> Claude Desktop displayName
      pipeline; add_route's merge logic is shared between hashmap branches.
    - Unify the [1M] marker as ONE_M_CONTEXT_MARKER across
      claude_desktop_config and proxy::model_mapper; rename the strip
      helper to strip_one_m_suffix_for_upstream.
    - Collapse useModelState's seven duplicated useState initializers and
      the useEffect parse block into a single parseModelsFromConfig call.
    - Add tests/hooks/useModelState.test.tsx and a Claude Desktop import
      test covering Kimi K2 -> label_override. i18n (en/ja/zh) updated.
  • refactor(claude-desktop): lock route IDs to sonnet/opus/haiku roles
    Adapt to Claude Desktop 1.6259.1+ fail-all validation which only
    accepts claude-(sonnet|opus|haiku)-* route IDs. Branded model names
    (DeepSeek, Kimi, GLM, etc.) now live in a new labelOverride field
    instead of being embedded in route IDs.
    
    - Backend auto-repairs legacy unsafe routes to the next free
      sonnet/opus/haiku slot instead of erroring
    - Frontend swaps the free-form route input for a role dropdown plus
      menu display name field
    - Add CLAUDE_DESKTOP_ROLE_ROUTE_IDS as the single source of truth
      for role-to-route mapping; presets and form both consume it
    - Drop the dead displayName alias on ClaudeDesktopModelRoute and the
      ineffective /v1/models display_name injection (UI ignores it)
    - Update i18n (en/ja/zh) and form focus test for the new fields
  • feat(usage): filter-driven Hero with cache-normalized totals
    - Normalize OpenAI/Gemini input_tokens semantics in SQL via the new
      fresh_input_sql helper (cache_read subtracted at query time, no data
      migration). Recovers correct cache hit rates for Codex/Gemini.
    - Add get_usage_summary_by_app endpoint for per-app split (single
      UNION ALL + GROUP BY, avoids N+1).
    - Replace UsageSummaryCards + AppBreakdownRail with a single
      filter-driven UsageHero card; clicking a filter button now truly
      changes the displayed numbers and the title accent color.
    - Tighten KNOWN_APP_TYPES to the 3 app_types whose token data is
      reliably collected (claude/codex/gemini); hide claude-desktop,
      hermes, opencode, openclaw filter buttons and i18n keys.
    - Flag cache_creation as N/A for OpenAI-style protocols (Codex,
      Gemini); show a "partial" tooltip when the All view mixes both
      protocol families.
  • feat(claude-desktop): rework Claude Code import flow
    - Derive route keys from the upstream model name (pass-through style)
      instead of fixed Claude aliases, and translate the legacy [1M] suffix
      into the supports1m field at the import boundary. Three Claude aliases
      mapped to the same upstream now collapse to a single route (e.g.
      MiniMax-M2 across SONNET/OPUS/HAIKU env produces one
      claude-MiniMax-M2 -> MiniMax-M2 row), with [1M] OR-aggregated.
    - Add an import-time safety net that rebuilds claude-desktop-official
      when missing, so users who deleted it can recover via the normal
      import button without losing customizations on other providers.
    - Hide API key and endpoint URL inputs in the official provider edit
      form to mirror Claude Code's behavior and prevent user confusion.
    - Reword the empty-state import button label for clarity.
  • refactor(claude-desktop): replace [1M] suffix with supports1m field
    inferenceModels entries now emit {name, supports1m: true} objects when
    1M is enabled (plain strings otherwise), instead of appending a " [1M]"
    suffix to model IDs. Route IDs and upstream model IDs are stored
    verbatim; the suffix is rejected on input rather than silently stripped,
    and proxy request mapping now requires an exact route_id match.
  • fix(ui): center Monitor badge icon in app switcher
    The Monitor glyph's visual weight skews upward (screen rect dominates
    while the stand is two thin lines), making it appear off-center inside
    the 11px Claude Desktop badge. Add a per-badge offsetY config and
    apply translateY(0.5px) to compensate.
  • - 修复 Claude Desktop 模型输入框失焦
    - 为动态模型行添加稳定 rowId,避免编辑模型 ID 时重挂载
    
    - 增加模型映射和直连模型列表焦点保持回归测试
  • - 恢复 Claude Desktop 共享功能入口
    - 将 Claude Desktop 的 Prompts、Skills、Sessions 映射到 Claude Code 配置
    
    - 恢复 Claude Desktop 顶部功能按钮组
    
    - 继续复用统一 MCP 面板入口
  • - 支持 Claude Desktop 使用 Copilot/Codex OAuth 供应商
    - 放开本地路由托管 OAuth 供应商校验,允许动态 Token
    - 新增 Claude Desktop Copilot/Codex 预设与账号选择
    - 添加 OAuth proxy 回归测试
  • refactor(claude-desktop): drop displayName from model route schema
    Claude Desktop's new model menu reads model IDs directly and ignores the
    display_name field, so a separate displayName slot added UI noise without
    any product value. Collapse the routeId / model / displayName tuple down
    to routeId / model, and let the route ID carry the user-visible name
    through a non-editable claude- prefix rendered next to the input.
    
    Drop display_name from ClaudeDesktopModelRoute, ClaudeDesktopDefaultRoute,
    and ResolvedModelRoute on the Rust side plus the matching TS interfaces,
    stop emitting it in /v1/models responses, derive route IDs from upstream
    model IDs when picked via the model dropdown, and update zh/en/ja copy to
    describe the new two-field layout.
  • fix(ui): hide empty toolbar capsule when Claude Desktop is active
    Claude Desktop disables Skills, Prompts, Sessions, and MCP, which left
    the secondary toolbar capsule next to the app switcher completely empty
    but still rendered as a grey rounded pill. Wrap the capsule in an
    activeApp !== "claude-desktop" guard so it disappears entirely, and
    drop the two inner guards that this outer check makes redundant.
  • feat(ui): use "Claude Code" label in app visibility settings
    The app visibility section in Settings showed "Claude" for the first
    entry, identical to "Claude Desktop" at a glance. Add a dedicated
    i18n key apps.claudeCode and point the settings panel at it, while
    leaving apps.claude untouched so other panels (MCP, Skills, Usage,
    etc.) keep their shorter "Claude" label.
  • feat(ui): distinguish Claude Code vs Claude Desktop in app switcher
    The two Claude entries shared the same orange logo, making them hard to
    tell apart at a glance. Rename the first entry to "Claude Code" and
    overlay a Terminal badge on its logo; overlay a Monitor badge on the
    Claude Desktop logo. Changes are scoped to AppSwitcher only; other
    panels (MCP, Skills, Usage, etc.) continue to show "Claude".
  • chore(brand): surface ccswitch.io as the sole official website
    Add an "Only Official Website" header to the three READMEs, an
    About panel button, and a tray menu entry — all pointing to
    ccswitch.io. Consolidates brand and SEO signals on the canonical
    domain across docs, GUI, and system tray.
  • - fix(ci): restore frontend formatting and Linux clippy
    - Format Claude Desktop provider presets with Prettier
    
    - Gate platform-specific Claude Desktop path helpers behind cfg
  • chore(icons): add ClaudeCN and RunAPI raster icons
    Resized to 512x512 to match the existing extracted-icons size convention
    (hermes.png / lemondata.png). Source uploads were oversized (7.3 MB
    8635x8635 for ClaudeCN; 800x800 for RunAPI) and would have bloated the
    bundle if imported as-is.
    
    Note: not yet wired into index.ts / metadata.ts; register there when
    they need to surface in the app UI.