Commit Graph

1476 Commits

  • 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
  • docs(release-notes): sync user edits across en/zh/ja and add PR credits
    - 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)
  • chore(release): bump version to v3.13.0 and sync changelog/release notes
    Backfill post-draft changes into CHANGELOG and three-language release
    notes (en/zh/ja): 16 new Added entries, 6 Fixed entries, 1 Docs entry,
    and updated header stats (139 commits, 280 files, +31627/-3042).
  • feat: update PIPELLM preset with full config, add Codex support and icon
    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.
  • feat: add E-FlowCode provider preset across all five apps
    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.
  • feat: add Shengsuanyun provider preset with partner promotion
    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.
  • chore: remove generate-icon-index.js to prevent accidental regeneration
    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.
  • feat: add LionCCAPI provider preset with partner promotion
    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.
  • fix: map adaptive thinking to xhigh reasoning_effort instead of high
    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.
  • feat: replace x-code icon with high-res xcode icon via URL import
    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.
  • feat: support URL-based icons for large SVGs and raster images
    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.
  • feat: add ddshub provider preset with partner promotion
    Add ddshub as a third-party partner provider for Claude, including
    SVG icon and i18n promotion text in zh/en/ja locales.
  • Restore first-class OMO Slim council support (#1981) (#1982)
    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
  • Let Kaku users launch sessions from their chosen terminal (#1954) (#1983)
    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
  • Align Thinking fallback with main-model-only Claude mappings (#1984)
    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
  • Restore auth tab localization in settings (#1985)
    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
  • feat(provider): add TheRouter presets for Claude, Codex, and Gemini (#1891)
    * feat(provider): add TheRouter presets for Claude and Codex
    
    * feat(provider): add TheRouter Gemini preset
    
    ---------
    
    Co-authored-by: max <me19@qq.com>
  • fix: guard migrations against missing tables and fix highlighted text assertion
    - 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
  • fix: update tests for InstalledSkill new fields and missing hook mocks
    - 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
  • docs: add working directory feature implementation plan
    Design document for per-directory state switching (providers, MCP,
    skills, prompts). Not yet implemented - saved for future reference.
  • fix(session-manager): improve session search accuracy and Chinese support
    - 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
  • feat(session-manager): extract meaningful titles for Claude sessions
    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)
  • feat(common-config): show first-run notice dialog when editing providers
    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.
  • feat(common-config): add guide info and empty state to common config editor
    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.
  • fix(usage): only show CLI subscription quota for active provider
    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.
  • fix(notifications): remove duplicate toast when switching to proxy providers
    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.
  • feat(welcome): show first-run welcome dialog on fresh install
    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.
  • docs(user-manual): update to v3.13.0 across en/zh/ja
    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
  • feat(providers): auto-import OpenCode/OpenClaw live providers on startup
    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.
  • feat(providers): seed an official preset on startup for Claude/Codex/Gemini
    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.
  • fix(usage): only auto-poll Copilot/ChatGPT quota for current provider
    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.
  • docs(release-notes): add v3.13.0 release notes (en/zh/ja)
    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.
  • docs(changelog): cover UTF-8 boundary and system prompt fixes
    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.
  • docs(changelog): add Unreleased section for upcoming release
    Catalog all user-visible changes since v3.12.3: lightweight mode,
    provider model auto-fetch, quota and balance visibility, skills
    discovery and batch updates, session workflow upgrades, Codex OAuth
    reverse proxy, OpenCode/OpenClaw stream check coverage, tray submenus,
    Hyper-based proxy stack, provider key lifecycle, OAuth Auth Center UI
    polish, and the accompanying Copilot auth, WebDAV, usage pricing,
    Linux UI, and Skills i18n fixes.
  • refactor(stream-check): rename helper and drop phase markers
    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.
  • feat(stream-check): handle edge cases for OpenCode/OpenClaw
    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.
  • feat(stream-check): support OpenCode via npm package mapping
    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.
  • feat(stream-check): support remaining 3 OpenClaw protocols
    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.