mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-06-16 13:34:04 +08:00
ad8bdf16aed593c59d730857aebdf5be9d0852bb
238 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.
Jason ·
2026-05-25 22:20:33 +08:00 -
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
Jason ·
2026-05-14 21:35:02 +08:00 -
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.
Jason ·
2026-05-14 15:03:31 +08:00 -
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 refreshJason ·
2026-05-14 11:53:51 +08:00 -
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.
Jason ·
2026-05-13 10:27:29 +08:00 -
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.
Jason ·
2026-05-12 10:46:35 +08:00 -
feat(claude-desktop): add 3P provider switching with proxy gateway
Adds a new ClaudeDesktop AppType that writes Claude Desktop's third-party inference profile under configLibrary/, sharing _meta.json with other launchers (Ollama-compatible) so cc-switch can coexist with them. Two switch modes: - direct: provider already exposes claude-* / anthropic/claude-* model ids on Anthropic Messages, Claude Desktop connects to it directly. - proxy: cc-switch's local proxy acts as the inference gateway, presenting only claude-* route names to Claude Desktop and mapping them to real upstream models. Required after Anthropic restricted Claude Desktop to claude-family ids. Backend: - New module claude_desktop_config with snapshot/rollback, official seed bypass, /claude-desktop/v1/{models,messages} routes, and a single source of truth for default proxy routes. - Gateway token persisted in SQLite, validated on every proxied request. - get_claude_desktop_status surfaces drift signals (stale models, missing routes, proxy stopped, base URL mismatch, missing token). Frontend: - Slim ClaudeDesktopProviderForm independent from ProviderForm, controlled by a top-level appId guard. - ProviderList banner consumes the status query (5s polling) and renders actionable diagnostics. - ClaudeDesktopRouteToggle in the header to start/stop the local gateway without touching takeover state. - Three-locale i18n synchronised.Jason ·
2026-05-08 22:34:46 +08:00 -
fix(model-fetch): support /models for Anthropic-compat subpath providers
Providers like DeepSeek, Kimi, Zhipu GLM and MiniMax expose the Anthropic-compatible API on a subpath (e.g. /anthropic) while the OpenAI-style /models endpoint lives at the API root. The previous heuristic blindly appended /v1/models to the Base URL, so every such provider returned 404 and the UI mislabeled it as "provider does not support fetching models". Backend now generates a candidate list and tries them in order: preset override -> baseURL /v1/models -> stripped-subpath /v1/models -> stripped-subpath /models. Non-404/405 responses (auth, network) stop immediately so we never retry against hostile status codes. Known compat suffixes are kept in a length-descending constant so the longest match wins; response bodies are truncated to 512 chars to avoid HTML 404 pages bloating the error string. Preset type gains an optional modelsUrl (DeepSeek points at https://api.deepseek.com/models). Frontend threads the override through fetchModelsForConfig when the current Base URL still matches the preset default. A new fetchModelsEndpointNotFound i18n key replaces the misleading "not supported" toast for exhausted-candidate and 404/405 cases (zh/en/ja).
Jason ·
2026-04-24 23:20:10 +08:00 -
refactor(hermes): drop config health check scanner
The Hermes config.yaml schema has stabilized and users have migrated to the current provider fields, so the value of scanning for model.provider dangling references, custom_providers shape errors, v12 migration residue etc. no longer justifies the maintenance surface — and the scan produces false positives when users keep some providers under Hermes' v12+ providers: dict (Hermes' runtime merges both shapes, but CC Switch's scanner only looked at the list form). Removes the whole HermesHealthWarning type, scan_hermes_config_health command, HermesHealthBanner React component, useHermesHealth hook, warnings field on HermesWriteOutcome, and the three helper functions (yaml_as_non_empty_str, collect_mapping_string_keys, hermes_warning) that only served the scanner. Drops the matching i18n keys in zh/en/ja and the fixInWebUI button label that only the banner used.
Jason ·
2026-04-23 16:18:38 +08:00 -
feat(tray): show cached provider usage in the system tray menu (#2184)
* feat: add Rust-side write-through usage cache Introduce an in-memory UsageCache on AppState that the existing usage query commands populate on success. The cache is read-only to the rest of the app today; the next commit consumes it from the tray menu. - New services::usage_cache module with split maps: subscription keyed by AppType, script keyed by (AppType, provider_id). - AppType gains Eq + Hash so it can be used as a HashMap key. - commands::subscription::get_subscription_quota now takes State<AppState> and writes through on success (signature change is invisible to the frontend — Tauri injects State automatically). - commands::provider::queryProviderUsage body extracted into an inner async fn; the public command wraps it with write-through, covering Copilot, coding-plan, balance, and generic script paths uniformly. Cache is in-memory only; auto-query interval and the upcoming tray refresh action rebuild it after restarts. * feat(tray): surface cached usage in the system tray menu Read UsageCache populated by the previous commit and render it in three places, scoped to whatever TRAY_SECTIONS covers (Claude/Codex/Gemini): 1. Inline suffix on each provider submenu item "AnyProvider · 🟢 5h 18% / 7d 23%" 2. Disabled summary row per visible app under "Show Main" "Claude · Anthropic Official · 🟢 5h 18% / 7d 23%" 3. "Refresh all usage" menu item that triggers get_subscription_quota + queryProviderUsage for every applicable provider, then rebuilds the tray menu via the existing refresh_tray_menu path. Color encoding uses emoji (🟢 <70% / 🟠 70-89% / 🔴 ≥90%) since Tauri 2 tray labels are plain text. Missing cache entry leaves the label unchanged — tray never issues network requests when opened. Three new i18n-ready strings live in TrayTexts (en/zh/ja), following the existing pattern for tray text. Closes #2178. * feat(usage): bridge tray UsageCache writes to frontend React Query Why: tray hover triggers backend-only refresh that wrote to UsageCache but never notified the frontend, leaving main UI stale while tray showed fresh numbers. Emit a payload-carrying event after each cache write so React Query can setQueryData directly, keeping both views in sync without duplicate fetches. * fix(tray): skip hidden apps on hover refresh and drop stale disabled-script cache Address P2 findings from automated review on #2184: 1. refresh_all_usage_in_tray now filters TRAY_SECTIONS by settings.visible_apps before scheduling subscription/script queries, matching create_tray_menu and preventing wasted external API calls (and rate-limit/auth-error log noise) for apps the user has hidden. 2. format_usage_suffix only trusts the script cache when provider.meta.usage_script is still enabled; when a script is disabled/removed the cached suffix is now invalidated so the tray label no longer shows stale data indefinitely. * refactor: consolidate codex provider helpers and fix test semantics - Add Provider::is_codex_oauth() and Provider::codex_fast_mode_enabled() to eliminate duplicated meta extraction in claude.rs and stream_check.rs - Fix non-codex-oauth tests to pass codex_fast_mode=false (was true, harmless but semantically misleading) - Remove redundant is_dir() guard after resolve_skill_source_dir already guarantees the returned path is a directory * style: apply cargo fmt * fix(tray): reflect failed refreshes in cache and support Gemini flash-lite Follow-up to the tray usage-display feature addressing review feedback: - Write snapshots for both Ok(success:false) and Err paths in queryProviderUsage / get_subscription_quota so stale success data no longer persists across failed refreshes; the original Err is still returned to the frontend onError handler. - Include gemini_flash_lite tier in the tray summary with label "l". Matches the frontend SubscriptionQuotaFooter and keeps the worst emoji correct when lite is the highest utilization. - Add TIER_GEMINI_PRO / _FLASH / _FLASH_LITE constants in services/subscription.rs and reuse them in classify_gemini_model and sort_order. - Extract Provider::has_usage_script_enabled() to remove the duplicated meta.usage_script chain at two call sites. - Use db.get_provider_by_id in refresh_all_usage_in_tray instead of materialising the full provider map, and parallelise subscription and script futures via futures::future::join. - Narrow refresh_all_usage_in_tray to each section's effective current provider (script if enabled, else subscription when the provider is official). Hover refreshes now issue at most TRAY_SECTIONS.len() outbound requests. - Add 10 unit tests in tray::tests covering Claude/Codex h/w dispatch, Gemini p/f/l dispatch (including lite-only and lite-worst cases), and success/failure guards. --------- Co-authored-by: Jason <farion1231@gmail.com>
涂瑜 ·
2026-04-23 16:17:15 +08:00 -
feat(hermes): launch dashboard from toolbar when Web UI is offline
When the Hermes Web UI probe fails, the toolbar entry now opens an info confirm dialog offering to run `hermes dashboard` in the user's preferred terminal. Accepting spawns it via a temp bash/batch script; `hermes dashboard` itself opens the browser once ready, so we do not poll. The Memory panel and Health banner keep the existing toast behavior. Also corrects the stale `hermes web` hint in the offline toast (the real command is `hermes dashboard`) and reorders Linux terminal detection to try `which` before stat'ing /usr/bin, /bin, /usr/local/bin.
Jason ·
2026-04-21 21:11:15 +08:00 -
feat(hermes): memory enable switch + clearer migration warning copy
Replaces the greyed-out "Memory is disabled" banner with a real Switch at the top of each memory tab. Users can now toggle Hermes' memory/user blobs without leaving CC Switch; the underlying write goes through the merge-aware `set_memory_enabled`, so budgets and external-provider settings survive toggle operations. The new `useToggleHermesMemoryEnabled` mutation invalidates the limits query so the Switch state and the amber disabled-hint update in lockstep. Reworks the `schema_migrated_v12` health banner copy to match the simplified "CC Switch only manages custom_providers" posture — it now tells users to reconcile migrated dict entries via Hermes Web UI, instead of the earlier (and now inaccurate) "CC Switch reads both".
Jason ·
2026-04-21 11:57:07 +08:00 -
feat(hermes): replace Prompts entry with Memory panel
Hermes has no slash-prompt concept (templates live as Skills), so the Prompts tab for the Hermes app was always empty. Swap the toolbar Book button for a Brain button that opens a new Memory panel editing ~/.hermes/memories/{MEMORY,USER}.md — Hermes' first-class memory store which its Web UI exposes only as on/off toggles, never as an editor. The panel shows each file in its own tab with a character-budget bar read from config.yaml's nested memory.* section (memory_char_limit / user_char_limit, default 2200 / 1375). Edits are written atomically; Hermes picks them up on the next session start per MemoryStore. Also extract useDarkMode to src/hooks/useDarkMode.ts — the codebase already repeats the same MutationObserver pattern in 12+ places; this PR introduces the shared hook and uses it once, leaving the migration of the other copies to a follow-up.Jason ·
2026-04-21 11:57:07 +08:00 -
refactor(hermes): delegate deep config to Hermes Web UI
Slim the Hermes surface in CC Switch to match its core positioning — cross-client provider switching and shared MCP/prompts/skills — and delegate deep configuration (model, agent, env, skills, cron, logs) to the Hermes Web UI at http://127.0.0.1:9119. - Drop AgentPanel/EnvPanel/ModelPanel and their mutation commands, hooks, types, and i18n keys across zh/en/ja. - Add open_hermes_web_ui Tauri command that probes /api/status and launches the URL in the system browser. Hermes injects its own session token into the returned HTML, so CC Switch doesn't need to touch auth. - Surface the launcher from the Hermes toolbar and the health banner via a shared useOpenHermesWebUI() hook; the offline error code is defined once per side and referenced across the contract. - Keep read-only access to model.provider so ProviderList can still highlight the active supplier; apply_switch_defaults continues to write the top-level model section when switching providers. Net diff: +152 / -1253.
Jason ·
2026-04-21 11:57:06 +08:00 -
fix(hermes): show active provider and wire add/enable/remove actions
Switching a Hermes provider previously only fired a toast because the frontend treated Hermes as non-additive (unlike backend AppType::is_additive_mode, which lists OpenCode | OpenClaw | Hermes) and relied on the unused is_current DB flag for highlighting. Align the UI model with the backend: - Include Hermes in ProviderActions' isAdditiveMode so the main button switches between "Add" and "Remove". - Drive the "current" highlight from model.provider (via useHermesModelConfig) instead of the DB is_current field; model.provider is Hermes's real SSOT for the active provider. - Reuse OpenClaw's set-as-default button slot to expose an "Enable" action on Hermes that calls switchProvider, so providers already in config can be activated without re-adding. switch_normal + apply_switch_defaults already atomically update custom_providers and model.provider, so no backend change is needed. - Invalidate liveProviderIds + modelConfig + health in parallel after add/update/delete/switch via a new invalidateHermesProviderCaches helper, replacing four copies of three sequential awaits.
Jason ·
2026-04-21 11:57:06 +08:00 -
feat: add Hermes frontend types, API layer, and hooks (Phase 7)
- Add "hermes" to AppId union type and all exhaustive Record<AppId> - Add HermesModelConfig, HermesAgentConfig, HermesEnvConfig types - Add hermes field to VisibleApps, McpApps, ProxyTakeoverStatus - Create src/lib/api/hermes.ts with Tauri invoke wrappers - Create src/hooks/useHermes.ts with 5 query + 3 mutation hooks - Register hermes in APP_IDS, APP_ICON_MAP (violet color scheme) - Split MCP_SKILLS_APP_IDS into MCP_APP_IDS (includes hermes) and SKILLS_APP_IDS (excludes hermes, since Hermes has no Skills support) - Wire hermes additive-mode into App.tsx (remove/duplicate handlers), ProviderList.tsx (live provider ID query + In Config badge), mutations.ts (cache invalidation on switch/add/delete) - Add Hermes checkbox to McpFormModal - Add basic hermes i18n keys (en/zh/ja)
Jason ·
2026-04-21 11:57:06 +08:00 -
Add OpenClaw config directory settings (#1518)
Co-authored-by: 张斌 <zhangbin25@xiaomi.com>
Franklin ·
2026-04-20 08:44:38 +08:00 -
feat(copilot): add GitHub Enterprise Server support (#2175)
* feat(copilot): add GitHub Enterprise Server support * fix(copilot): address GHES PR review findings (P1 + 2×P2) - P1: Use composite account ID (domain:user_id) for GHES to prevent cross-instance ID collisions; github.com keeps plain numeric ID for backward compatibilit - P2-a: Use get_api_endpoint() for model list URL with automatic fallback to static URL when dynamic endpoint resolution fails - P2-b: Add normalize_github_domain() as backend SSOT for domain normalization (lowercase, strip protocol/path/query, reject userinfo) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
hotelbe ·
2026-04-19 20:29:46 +08:00 -
feat(usage): refine usage dashboard UI and date range picker (#2002)
* feat(usage): enhance usage stats backend and query hooks * feat(usage): redesign calendar date range picker with auto-switch and simplified layout * refactor(usage): streamline dashboard layout and stats components * refactor(usage): compact request log table with merged cache/multiplier columns and centered layout * feat(i18n): add cache short labels and usage stats translations for zh/en/ja * Align usage dashboard stats with range boundaries The usage dashboard mixed second-precision detail rows with day-level rollups, which caused custom half-day ranges to overcount historical rollup data and left the request log paginator on stale pages after top-level filter changes. This change limits rollups to fully covered local days, aligns multi-day trend buckets with natural local days, and resets request log pagination when the dashboard range or app filter changes. Constraint: usage_daily_rollups stores only daily aggregates after pruning old detail rows Rejected: Include partial boundary rollups proportionally | historical intra-day detail is unavailable after pruning Rejected: Force RequestLogTable remount on range change | would discard local draft filters unnecessarily Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep summary, trends, provider stats, and model stats on the same rollup-boundary rules Tested: cargo test --manifest-path src-tauri/Cargo.toml usage_stats Tested: pnpm exec vitest run tests/components/RequestLogTable.test.tsx Tested: pnpm typecheck Not-tested: Manual UI validation in the Tauri app * Preserve full-day usage filters at minute precision The latest review surfaced two interaction bugs in the usage dashboard: rollup-backed stats undercounted end days selected via the minute-precision picker, and immediate select changes accidentally applied unsubmitted text drafts from the request log filters. This change treats 23:59 as a fully selected local end day for rollup inclusion and narrows select-side state syncing so app/status updates do not commit provider/model drafts. Constraint: The custom range picker emits minute-precision timestamps, while rollups are stored at day granularity Rejected: Require exact 23:59:59 end timestamps | unreachable from the current picker UI Rejected: Rebuild applied filters from the full draft state on select changes | silently commits unsaved text input Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep request-log text fields on explicit apply semantics even when select filters remain immediate Tested: cargo test --manifest-path src-tauri/Cargo.toml usage_stats Tested: pnpm exec vitest run tests/components/RequestLogTable.test.tsx Tested: pnpm typecheck Not-tested: Manual Tauri dashboard interaction * refactor(usage): move range presets into date picker, single-row layout - UsageDateRangePicker: add preset shortcuts (今天/1d/7d/14d/30d) inside popover top; clicking a preset applies immediately and closes popover - UsageDashboard: collapse to single row (app filters + refresh + picker); remove standalone preset buttons and summary stats bar - RequestLogTable: replace static Calendar badge with interactive UsageDateRangePicker via onRangeChange prop; single filter row * Keep usage pagination regression coverage aligned with the rendered UI The new regression test was asserting a non-existent pagination label and page summary text, so it failed before it could verify the real page-reset behavior. This commit switches the assertions to the numbered pagination buttons that the component actually renders and validates the reset through the query hook arguments. Constraint: RequestLogTable exposes numbered pagination buttons, not a "Next page" label or "2 / 6" summary text Rejected: Add synthetic pagination labels solely for the test | would couple production markup to a test-only assumption Confidence: high Scope-risk: narrow Reversibility: clean Directive: Prefer pagination assertions that follow the rendered controls or hook inputs instead of invented summary text Tested: pnpm vitest run tests/components/RequestLogTable.test.tsx; pnpm typecheck; pnpm test:unit * refactor(usage): clean up dead code and polish date range picker - Remove unused exports MAX_CUSTOM_USAGE_RANGE_SECONDS, timestampToLocalDatetime, and localDatetimeToTimestamp from usageRange.ts (replaced by the calendar picker) - Deduplicate getPresetLabel from UsageDashboard and UsageDateRangePicker into shared getUsageRangePresetLabel helper - Add aria-label, aria-current and aria-pressed to calendar day buttons so screen readers can disambiguate same-numbered days across adjacent months - Drop unused cacheReadShort and cacheWriteShort i18n keys (zh/en/ja); the request log table renders R/W prefixes inline - Align customRangeHint copy with the removed 30-day limit by dropping "up to 30 days" wording (zh/en/ja) * fix(usage): align rollup cutoff to local midnight to keep days complete `rollup_and_prune` previously used `Utc::now() - retain_days * 86400` as the cutoff. Because rollups are bucketed by *local* date and detail rows below the cutoff are pruned, an unaligned cutoff left the youngest rolled-up day half-rolled-up and half-pruned. Combined with the new `compute_rollup_date_bounds` boundary trimming (which excludes any rollup day not fully covered by the requested range), custom range queries that touch that day silently under-count summary, trend, provider, and model stats. Fix the invariant at the source: snap the cutoff to the next local midnight after `(now - retain_days)`. Every rollup row now reflects a complete local day, so the boundary trimmer's all-or-nothing assumption holds. Includes unit tests for the cutoff math (typical case + already-on- midnight case). DST gap is handled defensively by bumping forward by an hour. Addresses Codex P2 review finding on PR #2002. --------- Co-authored-by: Jason <farion1231@gmail.com>
Dex Miller ·
2026-04-16 17:00:28 +08:00 -
feat(stream-check): refresh default models and detect model-not-found errors (#2099)
* 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>
Jason Young ·
2026-04-15 15:25:32 +08:00 -
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.
Jason ·
2026-04-09 16:49:14 +08:00 -
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.
Jason ·
2026-04-09 16:49:14 +08:00 -
fix(linux): repair unresponsive UI on startup and full-screen panels
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.
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: display subscription quota for Codex OAuth provider cards
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.Jason ·
2026-04-09 16:49:13 +08:00 -
feat: add Codex OAuth (ChatGPT Plus/Pro) reverse proxy support
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.
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: display Copilot premium interactions quota on provider card
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.
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: add per-app usage filtering (Claude/Codex/Gemini)
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.
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: add session log usage tracking without proxy
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
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: integrate skills.sh search for discovering skills from public registry
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.
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: add skill storage location toggle between CC Switch and ~/.agents/skills
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.
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: add skill update detection via SHA-256 content hashing
- 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
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: add official balance query for DeepSeek, StepFun, SiliconFlow, OpenRouter, Novita AI
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
Jason ·
2026-04-09 16:49:13 +08:00 -
feat: add Token Plan quota query for Kimi, Zhipu GLM, and MiniMax
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)
Jason ·
2026-04-05 11:39:29 +08:00 -
feat: display official subscription quota on Claude provider cards
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.
Jason ·
2026-04-04 22:53:20 +08:00 -
feat: differentiate fetch models error messages by failure type
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.
Jason ·
2026-04-04 22:53:20 +08:00 -
feat: add auto-fetch models from provider's /v1/models endpoint
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
Jason ·
2026-04-04 22:53:20 +08:00 -
fix(copilot): 修复 GitHub Copilot 认证和代理问题 (#1854)
* 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>
Zhou Mengze ·
2026-04-04 22:52:23 +08:00 -
feat(provider): additive provider key lifecycle & fix openclaw serializer panic (#1724)
* 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>Dex Miller ·
2026-04-01 21:16:41 +08:00 -
feat(terminal): add directory picker before launching Claude terminal (#1752)
* 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.
Dex Miller ·
2026-03-31 15:10:08 +08:00 -
feat: add bulk delete for session manager (#1693)
* feat: add bulk delete for session manager * fix: address batch delete review issues * fix: keep session list in sync after batch delete
Alexlangl ·
2026-03-30 22:15:57 +08:00 -
feat(copilot): add GitHub Copilot reverse proxy support (#930)
* 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>Zhou Mengze ·
2026-03-17 23:57:58 +08:00 -
feat(skills): add restore and delete for skill backups
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.
Jason ·
2026-03-16 00:00:31 +08:00 -
feat(skills): auto-backup skill files before uninstall
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.
Jason ·
2026-03-15 23:26:50 +08:00 -
feat: add Tool Search domain restriction bypass with active-installation patching
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.
Jason ·
2026-03-14 23:41:36 +08:00 -
fix: replace implicit app inference with explicit selection for Skills import and sync
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).
Jason ·
2026-03-14 23:41:36 +08:00 -
Jason ·
2026-03-08 21:45:05 +08:00 -
feat: add dual-layer versioning to WebDAV sync (protocol v2 + db-v6)
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.
Jason ·
2026-03-08 19:42:18 +08:00 -
feat: add session deletion with per-provider cleanup and path safety
Add delete_session Tauri command dispatching to provider-specific deletion logic for all 5 providers (Claude, Codex, Gemini, OpenCode, OpenClaw). Includes path traversal protection via canonicalize + starts_with validation, session ID verification against file contents, frontend confirmation dialog with optimistic cache updates, i18n keys (zh/en/ja), and component tests.
Jason ·
2026-03-08 19:42:18 +08:00 -
feat: overhaul OpenClaw config panels with JSON5 round-trip write engine
- Add json-five crate for JSON5 serialization preserving comments and formatting - Rewrite openclaw_config.rs with comment-preserving JSON5 read/write engine - Add Tauri commands: get_openclaw_live_provider, write_openclaw_config_section - Redesign EnvPanel as full JSON editor with structured error handling - Add tools.profile selection (minimal/coding/messaging/full) to ToolsPanel - Add legacy timeout migration support to AgentsDefaultsPanel - Add OpenClawHealthBanner component for config validation warnings - Add supporting hooks, mutations, utility functions, and unit tests
Jason ·
2026-03-08 19:42:18 +08:00 -
feat: add Bedrock request optimizer (PRE-SEND thinking + cache injection) (#1301)
* feat: add Bedrock request optimizer (PRE-SEND thinking + cache injection) Add a PRE-SEND request optimizer that enhances Bedrock API requests before forwarding, complementing the existing POST-ERROR rectifier system. New modules: - thinking_optimizer: 3-path model detection (adaptive/legacy/skip) - Opus 4.6/Sonnet 4.6: adaptive thinking + effort max + 1M context beta - Legacy models: inject extended thinking with max budget - Haiku: skip (no modification) - cache_injector: auto-inject cache_control breakpoints (max 4) - Injects at tools/system/assistant message positions - TTL upgrade for existing breakpoints (5m → 1h) Gate: only activates for Bedrock providers (CLAUDE_CODE_USE_BEDROCK=1) Config: stored in SQLite settings table, default OFF, user opt-in UI: new Optimizer section in RectifierConfigPanel with 3 toggles + TTL 18 unit tests covering all paths. Verified against live Bedrock API. * chore: remove docs/plans directory * fix: address code review findings for Bedrock request optimizer P0 fixes: - Replace hardcoded Chinese with i18n t() calls in optimizer panel, add translation keys to zh/en/ja locale files - Fix u64 underflow: max_tokens - 1 → max_tokens.saturating_sub(1) - Move optimizer from before retry loop to per-provider with body cloning, preventing Bedrock fields leaking to non-Bedrock providers P1 fixes: - Replace .map() side-effect pattern with idiomatic if-let (clippy) - Fix module alphabetical ordering in mod.rs - Add cache_ttl whitelist validation in set_optimizer_config - Remove #[allow(unused_assignments)] and dead budget decrement --------- Co-authored-by: Keith (via OpenClaw) <keithyt06@users.noreply.github.com> Co-authored-by: Jason <farion1231@gmail.com>
Keith Yu ·
2026-03-07 18:57:21 +08:00