64 Commits

  • 调整预设供应商按钮外观与搜索框位置 (#4183)
    * 调整预设供应商按钮外观与搜索框位置
    
    1. 调整预设供应商按钮外观,显示默认图标,大小统一;
    2. 调整预设供应商搜索框位置。
    
    Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
    
    * test(provider): 新增预设按钮外观与 inline 搜索的单元测试
    
    覆盖:
    1. 所有预设按钮固定 200px 宽度,视觉对齐一致
    2. preset.icon 存在时按钮内渲染 ProviderIcon
    3. preset 无 icon 且无 theme.icon 时渲染占位元素保持文字对齐
    4. 点击放大镜 inline 切换搜索输入框可见性,ESC 收起并清空
    
    Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
    
    * refactor(provider-preset): responsive grid layout and search polish
    
    - Replace fixed-width preset buttons with a responsive CSS grid (auto-fill, 150px min column)
    - Add a leading placeholder to the custom button so its label aligns with iconed presets
    - Close the inline search box on outside click, restoring the old Popover behavior
    - Span the empty-state hint across the full grid row
    - Update component tests for the new layout and behaviors
    
    ---------
    
    Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
    Co-authored-by: Jason <farion1231@gmail.com>
  • test: align preset tests with Kimi K2.7 and Fable model tiers
    Update the Codex chat preset test's Kimi expectation (kimi-k2.6 -> kimi-k2.7-code) after the Kimi K2.7 upgrade, update the Claude Desktop form test for the four-tier (Sonnet/Opus/Fable/Haiku) routes, and reformat UsageDateRangePicker imports (prettier).
  • fix(providers): scope preset search to provider names only
    The preset search text also included websiteUrl and the shared category label, producing imprecise matches: a single category term matched the whole group, and URL fragments like "com"/"api" matched nearly everything. Restrict the search text to the display name and raw name; category labels are still used for rendering.
  • feat: add Claude Fable 5 model mapping across Claude Code and Desktop
    - Wire claude-fable-5 as a fourth tier on both proxy paths, with a
      fable -> opus -> default fallback mirroring the official downgrade.
    - Whitelist the fable- prefix for the Desktop 1.12603.1+ validator.
    - Clarify fallbackModelHint (zh/en/ja/zh-TW): a blank tier on
      third-party endpoints forwards the literal model name and 404s.
    
    Refs #3980, #4026, #4049.
  • feat(provider-form): custom User-Agent presets dropdown in advanced settings
    Polish the provider-level User-Agent override UI on the Claude and Codex forms.
    
    - Add a shared CustomUserAgentField (label + input + preset dropdown + live
      validation) so both forms stay in sync.
    - Provide curated UA presets (Claude Code / Kilo Code families that pass
      coding-plan UA whitelists per #3671); the first is Claude Code's real
      `claude-cli/x (external, cli)` format. Whitelists gate on the name prefix,
      not the version, so static values stay valid across upgrades.
    - Expose presets via a dropdown to the right of the input (z-[200] so it
      renders above the dialog layers) instead of inline chips.
    - Move the field into the existing advanced/reasoning collapsibles.
    - userAgent.ts mirrors the backend byte rule (reject only control chars;
      non-ASCII is allowed) for a non-blocking inline hint.
    - i18n for all four locales (zh/en/ja/zh-TW).
  • [codex] Fix VS Code session previews (#3593)
    * Fix Codex VS Code session previews
    
    * fix(codex): use last IDE request heading for session previews
    
    A markdown heading inside the active selection / open file could precede the real injected request, so matching the first "## My request for Codex:" heading picked selection content instead of the user prompt. Scan for the last matching heading (the IDE injects the real request as the final section) on both the Rust title path and the frontend TOC preview path.
    
    Add regression tests for the selection-heading case, and pin the known best-effort limitation when the request body itself repeats the heading.
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>
  • Fix Codex edit dialog masking live OAuth during proxy takeover
    The reported "OAuth access token disappears when enabling Codex proxy
    takeover" was a display artifact, not data loss: auth.json on disk kept
    the OAuth login the whole time. During takeover the edit dialog falls
    back to the stored provider config (so it does not surface the proxy
    placeholder), which for a third-party provider shows that provider's own
    key instead of the live auth.json, making the OAuth token look gone.
    
    Thread an isProxyTakeover flag from App through ProviderForm into the
    Codex editor and show an explicit notice plus storage-aware auth/config
    hints clarifying that the form displays the stored provider config while
    the live config is temporarily managed by the proxy. Drop the
    proxy-running condition so the notice shows whenever takeover is active,
    even with the proxy stopped.
    
    Add a regression test asserting the dialog does not read live settings
    during takeover and renders the database config. i18n synced across
    en/zh/ja/zh-TW.
  • Fix Codex model catalog being wiped by live-config backfill
    `modelCatalog` is a cc-switch-private field whose SSOT is the database; Live's
    config.toml only carries a lossy `model_catalog_json` projection. Proxy
    takeover/restore cycles and the official Codex.app rewriting config.toml can
    drop that projection, so `read_live_settings` reconstructs an empty catalog.
    Two paths then overwrote the stored mapping with that empty Live snapshot:
    
    - Switch-away backfill (`switch_normal` -> `restore_live_settings_for_provider_backfill`):
      now overlays the DB provider's `modelCatalog`, falling back to the
      Live-reconstructed one only when the DB has none.
    - Edit dialog (`EditProviderDialog`): when editing the active Codex provider it
      preferred Live over the DB SSOT; now keeps the DB `modelCatalog` so opening +
      saving no longer clears the mapping table.
    
    Add Rust backfill tests (preserve DB catalog when Live lacks it; keep Live
    catalog when DB has none) and a frontend regression test for the edit dialog.
  • Align Claude Desktop model mapping with Claude Code three-role tiers
    Claude Desktop's 3P validation only accepts claude-{sonnet,opus,haiku}-*
    role IDs, so providers must map every tier. Bring the Desktop mapping flow
    in line with Claude Code and fix the fallout that broke sub-agent Haiku calls.
    
    - Proxy form: replace the dynamic route list with fixed Sonnet/Opus/Haiku
      tiers; blank tiers backfill from the first filled tier (Sonnet first) on
      submit and inherit its supports1m flag
    - Backend: add a role-keyword fallback in map_proxy_request_model so dated
      official names (e.g. claude-haiku-4-5-20251001) resolve to the right tier,
      guarded by is_claude_safe_model_id so [1m]-suffixed IDs stay rejected
    - Tighten is_claude_safe_model_id / isClaudeSafeRoute to reject degenerate
      role IDs like "claude-sonnet-"
    - Fix the seed-effect race where normalizing empty routes to three blank
      tiers blocked the default-route backfill
    - Sync switch hints, placeholders, and the zh/en/ja/zh-TW locales to the
      three-role-ID rule
    - Update zh/en/ja user manual (2.1, 2.6), calling out legacy Claude IDs
      (claude-3-5-sonnet-...) as a rejected example
    
    Tests: 282 frontend + 34 backend claude_desktop; typecheck, clippy, fmt clean.
  • Enable Codex goals in provider templates (#3089)
    * Enable Codex goals in provider templates
    
    * feat: add Codex goal mode toggle
    
    - Remove forced goals=true from Codex provider presets and custom templates.
    - Add a Codex provider editor switch that updates [features].goals on demand.
    - Update docs, i18n, and regression coverage for the optional Goal mode flow.
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>
  • feat(i18n): add Traditional Chinese localization (#3093)
    * Add Traditional Chinese localization
    
    * fix: address zh-TW formatting and token units
    
    - Format `zh-TW.json` with Prettier.
    - Use Traditional Chinese `萬` and `億` units for zh-TW token summaries.
    - Add usage formatting coverage for Traditional Chinese locale aliases.
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>
  • fix: Codex model catalog WYSIWYG and config consolidation
    - Remove mergeCodexDefaultCatalogModelForSave implicit injection (P1)
      The model mapping table is now the single source of truth; no hidden
      entries are prepended on save.
    
    - Sync first catalog row model into config.toml on save
      Ensures Codex default request model matches the table's first entry
      instead of retaining a stale template value.
    
    - Remove API Format selector from CodexFormFields (P3)
      wire_api is always 'responses'; the selector confused users into
      thinking they were changing the upstream protocol. Only the 'Needs
      Local Routing' toggle remains.
    
    - Add restart hint to model mapping i18n text (P2)
      model_catalog_json is loaded at Codex startup; users are now informed
      that a restart is needed after changes.
    
    - Unify write_codex_live_with_catalog helper (P4)
      Replaces three scattered prepare+write call sites in config.rs,
      provider/live.rs, and proxy.rs with a single entry point.
    
    - Clean up useCodexConfigState dead state (P3 follow-up)
      Remove codexModelName, codexContextWindow, codexAutoCompactLimit and
      their handlers/effects since no component consumes them after the UI
      consolidation.
  • fix(skills): install correct skill from skills.sh search results (#2784)
    * fix(skills): install correct skill from skills.sh search results
    
    When multiple skills share the same directory name across different repos,
    SkillCard was passing directory to onInstall/onUninstall, causing handleInstall
    to always match the first result. Switch to using the unique key field
    (directory:repoOwner:repoName) for precise identification.
    
    * test(skills): add regression test for skills.sh install by key
    
    Verifies that clicking install on the second card when two skills share
    the same directory name correctly installs the second skill, not the first.
    
    ---------
    
    Co-authored-by: mrzhao <mrzhao@iflytek.com>
  • fix(usage): reduce price input step to 0.0001 for sub-cent precision (#2793)
    The step was 0.01, preventing input of prices like DeepSeek's cache read
    cost ($0.0028/million tokens). Extract step value to a constant and apply
    to all four price fields.
    
    Closes #2503
  • refactor(presets): render presets in array order and prioritize partners
    Remove the category-based grouping logic from ProviderPresetSelector,
    letting the array position in each preset config file be the single
    source of truth for display order. Move partner presets (PatewayAI,
    火山Agentplan, BytePlus, DouBaoSeed) right after Shengsuanyun across
    all 6 config files so they appear earlier in the UI.
  • feat(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.
  • refactor(claude-desktop): lock route IDs to sonnet/opus/haiku roles
    Adapt to Claude Desktop 1.6259.1+ fail-all validation which only
    accepts claude-(sonnet|opus|haiku)-* route IDs. Branded model names
    (DeepSeek, Kimi, GLM, etc.) now live in a new labelOverride field
    instead of being embedded in route IDs.
    
    - Backend auto-repairs legacy unsafe routes to the next free
      sonnet/opus/haiku slot instead of erroring
    - Frontend swaps the free-form route input for a role dropdown plus
      menu display name field
    - Add CLAUDE_DESKTOP_ROLE_ROUTE_IDS as the single source of truth
      for role-to-route mapping; presets and form both consume it
    - Drop the dead displayName alias on ClaudeDesktopModelRoute and the
      ineffective /v1/models display_name injection (UI ignores it)
    - Update i18n (en/ja/zh) and form focus test for the new fields
  • - 修复 Claude Desktop 模型输入框失焦
    - 为动态模型行添加稳定 rowId,避免编辑模型 ID 时重挂载
    
    - 增加模型映射和直连模型列表焦点保持回归测试
  • test: sync stale fixtures and isolate openclaw env tests
    Three unrelated test failures surfaced after rebase:
    
    - McpFormModal expected the apps boolean set without `hermes`; Hermes MCP
      support is now wired, so the fixture must include `hermes: false`.
    - therouter Gemini preset was bumped to `gemini-3.1-pro` in a later
      commit; update the assertions to match current config.
    - openclaw_config tests mutate process-level `CC_SWITCH_TEST_HOME` and
      `HOME` inside a module-local Mutex, but hermes_config does the same
      under its own separate Mutex. Running both modules in parallel let the
      env races corrupt hermes_config's `with_test_home`. Tag the four
      env-mutating openclaw tests with `#[serial]` so they serialize across
      modules via serial_test's process-wide default key.
  • 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>
  • 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
  • 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
  • fix: preserve WebDAV password display and validate MKCOL 405 (#1685)
    * fix: preserve WebDAV password display and validate MKCOL 405
    
    * fix: scope WebDAV password preservation to post-save refresh
  • chore(release): consolidate v3.12.3 release notes, changelog and test fixes
    Merge previously unreleased v3.12.4 content into v3.12.3:
    - CHANGELOG: combine [Unreleased] into [3.12.3], clear [Unreleased]
    - Release notes (zh/en/ja): add Copilot proxy, macOS signing,
      Reasoning Effort, OpenCode SQLite, Codex 1M toggle, Disable
      Auto-Upgrade toggle, and contributor thanks
    - Fix test mocks for skill backup/restore hooks
    - Fix schema migration test missing providers table
    - Fix TempHome to save/restore CC_SWITCH_TEST_HOME env var
  • 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.
  • fix: prevent common config modal infinite reopen loop and add draft editing
    The auto-open useEffect in CodexConfigEditor and GeminiConfigEditor
    created an inescapable loop: commonConfigError triggered modal open,
    closing the modal didn't clear the error, so the effect immediately
    reopened it — locking the entire UI.
    
    - Remove auto-open useEffect from both Codex and Gemini config editors
    - Convert common config modals to draft editing (edit locally, validate
      before save) instead of persisting on every keystroke
    - Add TOML/JSON pre-validation via parseCommonConfigSnippet before any
      merge operation to prevent invalid content from being persisted
    - Expose clearCommonConfigError so editors can clear stale errors on
      modal close
  • fix: sync session search index with query data to refresh list after deletion
    Replace useRef+useEffect async index rebuild with useMemo so the
    FlexSearch index and the sessions array always reference the same data.
    This ensures filtered search results update immediately when a session
    is deleted via TanStack Query setQueryData.
  • 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.
  • 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
  • feat(webdav): follow-up 补齐自动同步与大文件防护 (#1043)
    * feat(webdav): add robust auto sync with failure feedback
    
    (cherry picked from commit bb6760124a62a964b36902c004e173534910728f)
    
    * fix(webdav): enforce bounded download and extraction size
    
    (cherry picked from commit 7777d6ec2b9bba07c8bbba9b04fe3ea6b15e0e79)
    
    * fix(webdav): only show auto-sync callout for auto-source errors
    
    * refactor(webdav): remove services->commands auto-sync dependency
  • feat(openclaw): add Workspace Files panel for managing bootstrap md files
    Add a dedicated panel to read/write OpenClaw's 6 workspace bootstrap files
    (AGENTS.md, SOUL.md, USER.md, IDENTITY.md, TOOLS.md, MEMORY.md) directly
    from ~/.openclaw/workspace/, with a whitelist-secured backend and Markdown
    editor UI. Also fix prompt auto-import missing OpenCode/OpenClaw and the
    PromptFormPanel filenameMap type exclusion.
  • Webdav (#923)
    * feat: WebDAV backup/restore
    
    - Add WebDAV test/backup/restore commands and settings\n- Fix ja i18n missing keys; decode PROPFIND href as UTF-8\n- Stabilize Windows prompt auto-import tests via CC_SWITCH_TEST_HOME
    
    * chore: format and minor cleanups
    
    * fix: update build config
    
    * feat(webdav): unify sync UX and hardening fixes
    
    * fix(webdav): harden sync flow and stabilize sync UX/tests
    
    * fix(webdav): add resource limits to skills.zip extraction
    
    Prevent zip bomb / resource exhaustion by enforcing:
    - MAX_EXTRACT_ENTRIES (10,000 files)
    - MAX_EXTRACT_BYTES (512 MB cumulative)
    
    * refactor(webdav): drop deviceId and display deviceName only
    
    ---------
    
    Co-authored-by: small-lovely-cat <77799160+small-lovely-cat@users.noreply.github.com>
    Co-authored-by: saladday <1203511142@qq.com>
  • feat(omo): improve agent model selection UX and fix lowercase keys (#1004)
    * fix(omo): use lowercase keys for builtin agent definitions
    
    OMO config schema expects all agent keys to be lowercase.
    Updated OMO_BUILTIN_AGENTS keys (Sisyphus → sisyphus, Hephaestus →
    hephaestus, etc.) and aligned Rust test fixtures accordingly.
    
    * feat(omo): add i18n support and tooltips for agent/category descriptions
    
    * feat(omo): add preset model variants for thinking level support
    
    Add OPENCODE_PRESET_MODEL_VARIANTS constant with variant definitions
    for Google, OpenAI, and Anthropic models. The omoModelVariantsMap
    builder now falls back to presets when config-defined variants are
    absent, enabling the variant selector for supported models.
    
    * feat(omo): replace model select with searchable combobox and improve fallback handling
    
    * feat(omo): enrich preset model defaults and metadata fallback
    
    * fix(omo): preserve custom fields and align otherFields import/validation
    
    * fix: resolve omo clippy warnings and include app update
  • Feat/pricing config enhancement (#781)
    * feat(db): add pricing config fields to proxy_config table
    
    - Add default_cost_multiplier field per app type
    - Add pricing_model_source field (request/response)
    - Add request_model field to proxy_request_logs table
    - Implement schema migration v5
    
    * feat(api): add pricing config commands and provider meta fields
    
    - Add get/set commands for default cost multiplier
    - Add get/set commands for pricing model source
    - Extend ProviderMeta with cost_multiplier and pricing_model_source
    - Register new commands in Tauri invoke handler
    
    * fix(proxy): apply cost multiplier to total cost only
    
    - Move multiplier calculation from per-item to total cost
    - Add resolve_pricing_config for provider-level override
    - Include request_model and cost_multiplier in usage logs
    - Return new fields in get_request_logs API
    
    * feat(ui): add pricing config UI and usage log enhancements
    
    - Add pricing config section to provider advanced settings
    - Refactor PricingConfigPanel to compact table layout
    - Display all three apps (Claude/Codex/Gemini) in one view
    - Add multiplier column and request model display to logs
    - Add frontend API wrappers for pricing config
    
    * feat(i18n): add pricing config translations
    
    - Add zh/en/ja translations for pricing defaults config
    - Add translations for multiplier, requestModel, responseModel
    - Add provider pricing config translations
    
    * fix(pricing): align backfill cost calculation with real-time logic
    
    - Fix backfill to deduct cache_read_tokens from input (avoid double billing)
    - Apply multiplier only to total cost, not to each item
    - Add multiplier display in request detail panel with i18n support
    - Use AppError::localized for backend error messages
    - Fix init_proxy_config_rows to use per-app default values
    - Fix silent failure in set_default_cost_multiplier/set_pricing_model_source
    - Add clippy allow annotation for test mutex across await
    
    * style: format code with cargo fmt and prettier
    
    * fix(tests): correct error type assertions in proxy DAO tests
    
    The tests expected AppError::InvalidInput but the DAO functions use
    AppError::localized() which returns AppError::Localized variant.
    Updated assertions to match the correct error type with key validation.
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>
  • chore: fix code formatting and test setup
    - Format Rust code with rustfmt (misc.rs, types.rs)
    - Format TypeScript/React code with Prettier (4 files)
    - Fix ProviderList test by wrapping with QueryClientProvider
  • fix(opencode): address issues found during OpenCode integration review
    - Fix MCP server not removed from opencode.json when unchecked in edit modal
    - Fix Windows atomic write failure when opencode.json already exists
    - Fix i18n keys mismatch in OpenCodeFormFields (use opencode.* namespace)
    - Fix unit test missing apps.opencode field assertion
  • Feat/auto failover switch (#440)
    * feat(failover): add auto-failover master switch with proxy integration
    
    - Add persistent auto_failover_enabled setting in database
    - Add get/set_auto_failover_enabled commands
    - Provider router respects master switch state
    - Proxy shutdown automatically disables failover
    - Enabling failover auto-starts proxy server
    - Optimistic updates for failover queue toggle
    
    * feat(proxy): persist proxy takeover state across app restarts
    
    - Add proxy_takeover_{app_type} settings for per-app state tracking
    - Restore proxy takeover state automatically on app startup
    - Preserve state on normal exit, clear on manual stop
    - Add stop_with_restore_keep_state method for graceful shutdown
    
    * fix(proxy): set takeover state for all apps in start_with_takeover
    
    * fix(windows): hide console window when checking CLI versions
    
    Add CREATE_NO_WINDOW flag to prevent command prompt from flashing
    when detecting claude/codex/gemini CLI versions on Windows.
    
    * refactor(failover): make auto-failover toggle per-app independent
    
    - Change setting key from 'auto_failover_enabled' to 'auto_failover_enabled_{app_type}'
    - Update provider_router to check per-app failover setting
    - When failover disabled, use current provider only; when enabled, use queue order
    - Add unit tests for failover enabled/disabled behavior
    
    * feat(failover): auto-switch to higher priority provider on recovery
    
    - After circuit breaker reset, check if recovered provider has higher priority
    - Automatically switch back if queue_order is lower (higher priority)
    - Stream health check now resets circuit breaker on success/degraded
    
    * chore: remove unused start_proxy_with_takeover command
    
    - Remove command registration from lib.rs
    - Add comment clarifying failover queue is preserved on proxy stop
    
    * feat(ui): integrate failover controls into provider cards
    
    - Add failover toggle button to provider card actions
    - Show priority badge (P1, P2, ...) for queued providers
    - Highlight active provider with green border in failover mode
    - Sync drag-drop order with failover queue
    - Move per-app failover toggle to FailoverQueueManager
    - Simplify SettingsPage failover section
    
    * test(providers): add mocks for failover hooks in ProviderList tests
    
    * refactor(failover): merge failover_queue table into providers
    
    - Add in_failover_queue field to providers table
    - Remove standalone failover_queue table and related indexes
    - Simplify queue ordering by reusing sort_index field
    - Remove reorder_failover_queue and set_failover_item_enabled commands
    - Update frontend to use simplified FailoverQueueItem type
    
    * fix(database): ensure in_failover_queue column exists for v2 databases
    
    Add column check in create_tables to handle existing v2 databases
    that were created before the failover queue refactor.
    
    * fix(ui): differentiate active provider border color by proxy mode
    
    - Use green border/gradient when proxy takeover is active
    - Use blue border/gradient in normal mode (no proxy)
    - Improves visual distinction between proxy and non-proxy states
    
    * fix(database): clear provider health record when removing from failover queue
    
    When a provider is removed from the failover queue, its health monitoring
    is no longer needed. This change ensures the health record is also deleted
    from the database to prevent stale data.
    
    * fix(failover): improve cache cleanup for provider health and circuit breaker
    
    - Use removeQueries instead of invalidateQueries when stopping proxy to
      completely clear health and circuit breaker caches
    - Clear provider health and circuit breaker caches when removing from
      failover queue
    - Refresh failover queue after drag-sort since queue order depends on
      sort_index
    - Only show health badge when provider is in failover queue
    
    * style: apply prettier formatting to App.tsx and ProviderList.tsx
    
    * fix(proxy): handle missing health records and clear health on proxy stop
    
    - Return default healthy state when provider health record not found
    - Add clear_provider_health_for_app to clear health for specific app
    - Clear app health records when stopping proxy takeover
    
    * fix(proxy): track actual provider used in forwarding for accurate logging
    
    Introduce ForwardResult and ForwardError structs to return the actual
    provider that handled the request. This ensures usage statistics and
    error logs reflect the correct provider after failover.
  • feat: add provider search filter (#435)
    * feat: add provider search filter
    
    * feat: add provider search overlay
  • feat(settings): add option to skip Claude Code first-run confirmation
    Add a new setting to automatically skip Claude Code's onboarding screen
    by writing hasCompletedOnboarding=true to ~/.claude.json. The setting
    defaults to enabled for better user experience.
    
    - Add set/clear_has_completed_onboarding functions in claude_mcp.rs
    - Add Tauri commands and frontend API integration
    - Add toggle in WindowSettings with i18n support (en/zh/ja)
    - Fix hardcoded Chinese text in tests to use i18n keys
  • refactor(proxy): remove is_proxy_target in favor of failover_queue
    - Remove `is_proxy_target` field from Provider struct (Rust & TypeScript)
    - Remove related DAO methods: get_proxy_target_provider, set_proxy_target
    - Remove deprecated Tauri commands: get_proxy_targets, set_proxy_target
    - Add `is_available()` method to CircuitBreaker for availability checks
      without consuming HalfOpen probe permits (used in select_providers)
    - Keep `allow_request()` for actual request gating with permit tracking
    - Update stream_check to use failover_queue instead of is_proxy_target
    - Clean up commented-out reset circuit breaker button in ProviderActions
    - Remove unused useProxyTargets and useSetProxyTarget hooks
  • Feat/auto failover (#367)
    * feat(db): add circuit breaker config table and provider proxy target APIs
    
    Add database support for auto-failover feature:
    
    - Add circuit_breaker_config table for storing failover thresholds
    - Add get/update_circuit_breaker_config methods in proxy DAO
    - Add reset_provider_health method for manual recovery
    - Add set_proxy_target and get_proxy_targets methods in providers DAO
      for managing multi-provider failover configuration
    
    * feat(proxy): implement circuit breaker and provider router for auto-failover
    
    Add core failover logic:
    
    - CircuitBreaker: Tracks provider health with three states:
      - Closed: Normal operation, requests pass through
      - Open: Circuit broken after consecutive failures, skip provider
      - HalfOpen: Testing recovery with limited requests
    - ProviderRouter: Routes requests across multiple providers with:
      - Health tracking and automatic failover
      - Configurable failure/success thresholds
      - Auto-disable proxy target after reaching failure threshold
      - Support for manual circuit breaker reset
    - Export new types in proxy module
    
    * feat(proxy): add failover Tauri commands and integrate with forwarder
    
    Expose failover functionality to frontend:
    
    - Add Tauri commands: get_proxy_targets, set_proxy_target,
      get_provider_health, reset_circuit_breaker,
      get/update_circuit_breaker_config, get_circuit_breaker_stats
    - Register all new commands in lib.rs invoke handler
    - Update forwarder with improved error handling and logging
    - Integrate ProviderRouter with proxy server startup
    - Add provider health tracking in request handlers
    
    * feat(frontend): add failover API layer and TanStack Query hooks
    
    Add frontend data layer for failover management:
    
    - Add failover.ts API: Tauri invoke wrappers for all failover commands
    - Add failover.ts query hooks: TanStack Query mutations and queries
      - useProxyTargets, useProviderHealth queries
      - useSetProxyTarget, useResetCircuitBreaker mutations
      - useCircuitBreakerConfig query and mutation
    - Update queries.ts with provider health query key
    - Update mutations.ts to invalidate health on provider changes
    - Add CircuitBreakerConfig and ProviderHealth types
    
    * feat(ui): add auto-failover configuration UI and provider health display
    
    Add comprehensive UI for failover management:
    
    Components:
    - ProviderHealthBadge: Display provider health status with color coding
    - CircuitBreakerConfigPanel: Configure failure/success thresholds,
      timeout duration, and error rate limits
    - AutoFailoverConfigPanel: Manage proxy targets with drag-and-drop
      priority ordering and individual enable/disable controls
    - ProxyPanel: Integrate failover tabs for unified proxy management
    
    Provider enhancements:
    - ProviderCard: Show health badge and proxy target indicator
    - ProviderActions: Add "Set as Proxy Target" action
    - EditProviderDialog: Add is_proxy_target toggle
    - ProviderList: Support proxy target filtering mode
    
    Other:
    - Update App.tsx routing for settings integration
    - Update useProviderActions hook with proxy target mutation
    - Fix ProviderList tests for updated component API
    
    * fix(usage): stabilize date range to prevent infinite re-renders
    
    * feat(backend): add tool version check command
    
    Add get_tool_versions command to check local and latest versions of
    Claude, Codex, and Gemini CLI tools:
    
    - Detect local installed versions via command line execution
    - Fetch latest versions from npm registry (Claude, Gemini)
      and GitHub releases API (Codex)
    - Return comprehensive version info including error details
      for uninstalled tools
    - Register command in Tauri invoke handler
    
    * style(ui): format accordion component code style
    
    Apply consistent code formatting to accordion component:
    - Convert double quotes to semicolons at line endings
    - Adjust indentation to 2-space standard
    - Align with project code style conventions
    
    * refactor(providers): update provider card styling to use theme tokens
    
    Replace hardcoded color classes with semantic design tokens:
    - Use bg-card, border-border, text-card-foreground instead of glass-card
    - Replace gray/white color literals with muted/foreground tokens
    - Change proxy target indicator color from purple to green
    - Improve hover states with border-border-active
    - Ensure consistent dark mode support via CSS variables
    
    * refactor(proxy): simplify auto-failover config panel structure
    
    Restructure AutoFailoverConfigPanel for better integration:
    - Remove internal Card wrapper and expansion toggle (now handled by parent)
    - Extract enabled state to props for external control
    - Simplify loading state display
    - Clean up redundant CardHeader/CardContent wrappers
    - ProxyPanel: reduce complexity by delegating to parent components
    
    * feat(settings): enhance settings page with accordion layout and tool versions
    
    Major settings page improvements:
    
    AboutSection:
    - Add local tool version detection (Claude, Codex, Gemini)
    - Display installed vs latest version comparison with visual indicators
    - Show update availability badges and environment check cards
    
    SettingsPage:
    - Reorganize advanced settings into collapsible accordion sections
    - Add proxy control panel with inline status toggle
    - Integrate auto-failover configuration with accordion UI
    - Add database and cost calculation config sections
    
    DirectorySettings & WindowSettings:
    - Minor styling adjustments for consistency
    
    settings.ts API:
    - Add getToolVersions() wrapper for new backend command
    
    * refactor(usage): restructure usage dashboard components
    
    Comprehensive usage statistics panel refactoring:
    
    UsageDashboard:
    - Reorganize layout with improved section headers
    - Add better loading states and empty state handling
    
    ModelStatsTable & ProviderStatsTable:
    - Minor styling updates for consistency
    
    ModelTestConfigPanel & PricingConfigPanel:
    - Simplify component structure
    - Remove redundant Card wrappers
    - Improve form field organization
    
    RequestLogTable:
    - Enhance table layout with better column sizing
    - Improve pagination controls
    
    UsageSummaryCards:
    - Update card styling with semantic tokens
    - Better responsive grid layout
    
    UsageTrendChart:
    - Refine chart container styling
    - Improve legend and tooltip display
    
    * chore(deps): add accordion and animation dependencies
    
    Package updates:
    - Add @radix-ui/react-accordion for collapsible sections
    - Add cmdk for command palette support
    - Add framer-motion for enhanced animations
    
    Tailwind config:
    - Add accordion-up/accordion-down animations
    - Update darkMode config to support both selector and class
    - Reorganize color and keyframe definitions for clarity
    
    * style(app): update header and app switcher styling
    
    App.tsx:
    - Replace glass-header with explicit bg-background/80 backdrop-blur
    - Update navigation button container to use bg-muted
    
    AppSwitcher:
    - Replace hardcoded gray colors with semantic muted/foreground tokens
    - Ensure consistent dark mode support via CSS variables
    - Add group class for better hover state transitions
  • Feat/proxy server (#355)
    * feat(proxy): implement local HTTP proxy server with multi-provider failover
    
    Add a complete HTTP proxy server implementation built on Axum framework,
    enabling local API request forwarding with automatic provider failover
    and load balancing capabilities.
    
    Backend Implementation (Rust):
    - Add proxy server module with 7 core components:
      * server.rs: Axum HTTP server lifecycle management (start/stop/status)
      * router.rs: API routing configuration for Claude/OpenAI/Gemini endpoints
      * handlers.rs: Request/response handling and transformation
      * forwarder.rs: Upstream forwarding logic with retry mechanism (652 lines)
      * error.rs: Comprehensive error handling and HTTP status mapping
      * types.rs: Shared types (ProxyConfig, ProxyStatus, ProxyServerInfo)
      * health.rs: Provider health check infrastructure
    
    Service Layer:
    - Add ProxyService (services/proxy.rs, 157 lines):
      * Manage proxy server lifecycle
      * Handle configuration updates
      * Track runtime status and metrics
    
    Database Layer:
    - Add proxy configuration DAO (dao/proxy.rs, 242 lines):
      * Persist proxy settings (listen address, port, timeout)
      * Store provider priority and availability flags
    - Update schema with proxy_config table (schema.rs):
      * Support runtime configuration persistence
    
    Tauri Commands:
    - Add 6 command endpoints (commands/proxy.rs):
      * start_proxy_server: Launch proxy server
      * stop_proxy_server: Gracefully shutdown server
      * get_proxy_status: Query runtime status
      * get_proxy_config: Retrieve current configuration
      * update_proxy_config: Modify settings without restart
      * is_proxy_running: Check server state
    
    Frontend Implementation (React + TypeScript):
    - Add ProxyPanel component (222 lines):
      * Real-time server status display
      * Start/stop controls
      * Provider availability monitoring
    - Add ProxySettingsDialog component (420 lines):
      * Configuration editor (address, port, timeout)
      * Provider priority management
      * Settings validation
    - Add React hooks:
      * useProxyConfig: Manage proxy configuration state
      * useProxyStatus: Poll and display server status
    - Add TypeScript types (types/proxy.ts):
      * Define ProxyConfig, ProxyStatus interfaces
    
    Provider Integration:
    - Extend Provider model with availability field (providers.rs):
      * Track provider health for failover logic
    - Update ProviderCard UI to display proxy status
    - Integrate proxy controls in Settings page
    
    Dependencies:
    - Add Axum 0.7 (async web framework)
    - Add Tower 0.4 (middleware and service abstractions)
    - Add Tower-HTTP (CORS layer)
    - Add Tokio sync primitives (oneshot, RwLock)
    
    Technical Details:
    - Graceful shutdown via oneshot channel
    - Shared state with Arc<RwLock<T>> for thread-safe config updates
    - CORS enabled for cross-origin frontend access
    - Request/response streaming support
    - Automatic retry with exponential backoff (forwarder)
    - API key extraction from multiple config formats (Claude/Codex/Gemini)
    
    File Statistics:
    - 41 files changed
    - 3491 insertions(+), 41 deletions(-)
    - Core modules: 1393 lines (server + forwarder + handlers)
    - Frontend UI: 642 lines (ProxyPanel + ProxySettingsDialog)
    - Database/DAO: 326 lines
    
    This implementation provides the foundation for advanced features like:
    - Multi-provider load balancing
    - Automatic failover on provider errors
    - Request logging and analytics
    - Usage tracking and cost monitoring
    
    * fix(proxy): resolve UI/UX issues and database constraint error
    
    Simplify proxy control interface and fix database persistence issues:
    
    Backend Fixes:
    - Fix NOT NULL constraint error in proxy_config.created_at field
      * Use COALESCE to preserve created_at on updates
      * Ensure proper INSERT OR REPLACE behavior
    - Remove redundant enabled field validation on startup
      * Auto-enable when user clicks start button
      * Persist enabled state after successful start
    - Preserve enabled state during config updates
      * Prevent accidental service shutdown on config save
    
    Frontend Improvements:
    - Remove duplicate proxy enable switch from settings dialog
      * Keep only runtime toggle in ProxyPanel
      * Simplify user experience with single control point
    - Hide proxy target button when proxy service is stopped
      * Add isProxyRunning prop to ProviderCard
      * Conditionally render proxy controls based on service status
    - Update form schema to omit enabled field
      * Managed automatically by backend
    
    Files: 5 changed, 81 insertions(+), 94 deletions(-)
    
    * fix(proxy): improve URL building and Gemini request handling
    
    - Refactor URL construction with version path deduplication (/v1, /v1beta)
    - Preserve query parameters for Gemini API requests
    - Support GOOGLE_GEMINI_API_KEY field name (with fallback)
    - Change default proxy port from 5000 to 15721
    - Fix test: use Option type for is_proxy_target field
    
    * refactor(proxy): remove unused request handlers and routes
    
    - Remove unused GET/DELETE request forwarding methods
    - Remove count_tokens, get/delete response handlers
    - Simplify router by removing unused endpoints
    - Keep only essential routes: /v1/messages, /v1/responses, /v1beta/*
    
    * Merge branch 'main' into feat/proxy-server
    
    * fix(proxy): resolve clippy warnings for dead code and uninlined format args
    
    - Add #[allow(dead_code)] to unused ProviderUnhealthy variant
    - Inline format string arguments in handlers.rs and codex.rs log macros
    - Refactor error response handling to properly pass through upstream errors
    - Add URL deduplication logic for /v1/v1 paths in CodexAdapter
    
    * feat(proxy): implement provider adapter pattern with OpenRouter support
    
    This major refactoring introduces a modular provider adapter architecture
    to support format transformation between different AI API formats.
    
    New features:
    - Add ProviderAdapter trait for unified provider abstraction
    - Implement Claude, Codex, and Gemini adapters with specific logic
    - Add Anthropic ↔ OpenAI format transformation for OpenRouter compatibility
    - Support model mapping from provider configuration (ANTHROPIC_MODEL, etc.)
    - Add OpenRouter preset to Claude provider presets
    
    Refactoring:
    - Extract authentication logic into auth.rs with AuthInfo and AuthStrategy
    - Move URL building and request transformation to individual adapters
    - Simplify ProviderRouter to only use proxy target providers
    - Refactor RequestForwarder to use adapter-based request/response handling
    - Use whitelist mode for header forwarding (only pass necessary headers)
    
    Architecture:
    - providers/adapter.rs: ProviderAdapter trait definition
    - providers/auth.rs: AuthInfo, AuthStrategy types
    - providers/claude.rs: Claude adapter with OpenRouter detection
    - providers/codex.rs: Codex (OpenAI) adapter
    - providers/gemini.rs: Gemini (Google) adapter
    - providers/models/: Anthropic and OpenAI API data models
    - providers/transform.rs: Bidirectional format transformation
    
    * feat(proxy): add streaming SSE transform and thinking parameter support
    
    New features:
    - Add OpenAI → Anthropic SSE streaming response transformation
    - Support thinking parameter detection for reasoning model selection
    - Add ANTHROPIC_REASONING_MODEL config option for extended thinking
    
    Changes:
    - streaming.rs: Implement SSE event parsing and Anthropic format conversion
    - transform.rs: Add thinking detection logic and reasoning model mapping
    - handlers.rs: Integrate streaming transform for OpenRouter compatibility
    - Cargo.toml: Add async-stream and bytes dependencies
    
    * feat(db): add usage tracking schema and types
    
    Add database tables for proxy request logs and model pricing.
    Extend Provider and error types to support usage statistics.
    
    * feat(proxy): implement usage tracking subsystem
    
    Add request logger with automatic cost calculation.
    Implement token parser for Claude/OpenAI/Gemini responses.
    Add cost calculator based on model pricing configuration.
    
    * feat(proxy): integrate usage logging into request handlers
    
    Add usage logging to forwarder and streaming handlers.
    Track token usage and costs for each proxy request.
    
    * feat(commands): add usage statistics Tauri commands
    
    Register usage commands for summary, trends, logs, and pricing.
    Expose usage stats service through Tauri command layer.
    
    * feat(api): add frontend usage API and query hooks
    
    Add TypeScript types for usage statistics.
    Implement usage API with Tauri invoke calls.
    Add TanStack Query hooks for usage data fetching.
    
    * feat(ui): add usage dashboard components
    
    Add UsageDashboard with summary cards, trend chart, and data tables.
    Implement model pricing configuration panel.
    Add request log viewer with filtering and detail panel.
    
    * fix(ui): integrate usage dashboard and fix type errors
    
    Add usage dashboard tab to settings page.
    Fix UsageScriptModal TypeScript type annotations.
    
    * deps: add recharts for charts and rust_decimal/uuid for usage tracking
    
    - recharts: Chart visualization for usage trends
    - rust_decimal: Precise cost calculations
    - uuid: Request ID generation
    
    * feat(proxy): add ProviderType enum for fine-grained provider detection
    
    Introduce ProviderType enum to distinguish between different provider
    implementations (Claude, ClaudeAuth, Codex, Gemini, GeminiCli, OpenRouter).
    This enables proper authentication handling and request transformation
    based on the actual provider type rather than just AppType.
    
    - Add ProviderType enum with detection logic from config
    - Enhance Claude adapter with OpenRouter detection
    - Enhance Gemini adapter with CLI mode detection
    - Add helper methods for provider type inference
    
    * feat(database): extend schema with streaming and timing fields
    
    Add new columns to proxy_request_logs table for enhanced usage tracking:
    - first_token_ms and duration_ms for performance metrics
    - provider_type and is_streaming for request classification
    - cost_multiplier for flexible pricing
    
    Update model pricing with accurate rates for Claude/GPT/Gemini models.
    Add ensure_model_pricing_seeded() call on database initialization.
    Add test for model pricing auto-seeding verification.
    
    * feat(proxy/usage): enhance token parser and logger for multi-format support
    
    Parser enhancements:
    - Add OpenAI Chat Completions format parsing (prompt_tokens/completion_tokens)
    - Add model field to TokenUsage for actual model name extraction
    - Add from_codex_response_adjusted() for proper cache token handling
    - Add debug logging for better stream event tracing
    
    Logger enhancements:
    - Add first_token_ms, provider_type, is_streaming, cost_multiplier fields
    - Extend RequestLog struct with full metadata tracking
    - Update log_with_calculation() signature for new fields
    
    Calculator: Update tests with model field in TokenUsage.
    
    * feat(proxy): enhance proxy server with session tracking and OpenAI route
    
    Error handling:
    - Add StreamIdleTimeout and AuthError variants for better error classification
    
    Module exports:
    - Export ResponseType, StreamHandler, NonStreamHandler from response_handler
    - Export ProxySession, ClientFormat from session module
    
    Server routing:
    - Add /v1/chat/completions route for OpenAI Chat Completions API
    
    Handlers:
    - Add log_usage_with_session() for enhanced usage tracking with session context
    - Add first_token_ms timing measurement for streaming responses
    - Use SseUsageCollector with start_time for accurate latency calculation
    - Track is_streaming flag in usage logs
    
    * feat(services): add pagination and enhanced filtering for request logs
    
    Usage stats service:
    - Change get_request_logs() from limit/offset to page/page_size pagination
    - Return PaginatedLogs with total count, page, and page_size
    - Add appType and providerName filters with LIKE search
    - Add is_streaming, first_token_ms, duration_ms to RequestLogDetail
    - Join with providers table for provider name lookup
    
    Commands:
    - Update get_request_logs command signature for pagination params
    
    Module exports:
    - Export PaginatedLogs struct
    
    * feat(frontend): update usage types and API for pagination support
    
    Types (usage.ts):
    - Add isStreaming, firstTokenMs, durationMs to RequestLog
    - Add PaginatedLogs interface with data, total, page, pageSize
    - Change LogFilters: providerId -> appType + providerName
    
    API (usage.ts):
    - Change getRequestLogs params from limit/offset to page/pageSize
    - Return PaginatedLogs instead of RequestLog[]
    - Pass filters object directly to backend
    
    Query (usage.ts):
    - Update usageKeys.logs key generation for pagination
    - Update useRequestLogs hook signature
    
    * refactor(ui): enhance RequestLogTable with filtering and pagination
    
    UI improvements:
    - Add filter bar with app type, provider name, model, status selectors
    - Add date range picker (startDate/endDate)
    - Add search/reset/refresh buttons
    
    Pagination:
    - Implement proper page-based pagination with page info display
    - Show total count and current page range
    - Add prev/next navigation buttons
    
    Features:
    - Default to last 24 hours filter
    - Streamlined table columns layout
    - Query invalidation on refresh
    
    * style(config): format mcpPresets code style
    
    Apply consistent formatting to createNpxCommand function and
    sequential-thinking server configuration.
    
    * fix(ui): update SettingsPage tab styles for improved appearance (#342)
    
    * feat(model-test): add provider model availability testing
    
    Implement standalone model testing feature to verify provider API connectivity:
    - Add ModelTestService for Claude/Codex/Gemini endpoint testing
    - Create model_test_logs table for test result persistence
    - Add test button to ProviderCard with loading state
    - Include ModelTestConfigPanel for customizing test parameters
    
    * fix(proxy): resolve token parsing for OpenRouter streaming responses
    
    Problem:
    - OpenRouter and similar third-party services return streaming responses
      where input_tokens appear in message_delta instead of message_start
    - The previous implementation only extracted input_tokens from message_start,
      causing input_tokens to be recorded as 0 for these providers
    
    Changes:
    - streaming.rs: Add prompt_tokens field to Usage struct and include
      input_tokens in the transformed message_delta event when converting
      OpenAI format to Anthropic format
    - parser.rs: Update from_claude_stream_events() to handle input_tokens
      from both message_start (native Claude API) and message_delta (OpenRouter)
      - Use if-let pattern instead of direct unwrap for safer parsing
      - Only update input_tokens from message_delta if not already set
    - logger.rs: Adjust test parameters to match updated function signature
    
    Tests:
    - Add test_openrouter_stream_parsing() for OpenRouter format validation
    - Add test_native_claude_stream_parsing() for native Claude API validation
    
    * fix(pricing): standardize model ID format for pricing lookup
    
    Normalize model IDs by removing vendor prefixes and converting dots to hyphens to ensure consistent pricing lookups across different API response formats.
    
    Changes:
    - Update seed data to use hyphen format (e.g., gpt-5-1, gemini-2-5-pro)
    - Add normalize_model_id() function to strip vendor prefixes (anthropic/, openai/)
    - Convert dots to hyphens in model IDs (claude-haiku-4.5 → claude-haiku-4-5)
    - Try both original and normalized IDs for exact matching
    - Use normalized ID for suffix-based fallback matching
    - Add comprehensive test cases for prefix and dot handling
    - Add warning log when no pricing found
    
    This ensures pricing lookups work correctly for:
    - Models with vendor prefixes: anthropic/claude-haiku-4.5
    - Models with dots in version: claude-sonnet-4.5
    - Models with date suffixes: claude-haiku-4-5-20240229
    
    * style(rust): apply clippy formatting suggestions
    
    Apply automatic clippy fixes for uninlined_format_args warnings across Rust codebase. Replace format string placeholders with inline variable syntax for improved readability.
    
    Changes:
    - Convert format!("{}", var) to format!("{var}")
    - Apply to model_test.rs, parser.rs, and usage_stats.rs
    - Fix line length issues by breaking long function calls
    - Improve code formatting consistency
    
    All changes are automatic formatting with no functional impact.
    
    * fix(ui): restore card borders in usage statistics panels
    
    Restore proper card styling for ModelTestConfigPanel and PricingConfigPanel by adding back border and rounded-lg classes. The transparent background styling was causing visual inconsistency.
    
    Changes:
    - Replace border-none bg-transparent shadow-none with border rounded-lg
    - Apply to both loading and error states for consistency
    - Format TypeScript code for better readability
    - Break long function signatures across multiple lines
    
    This ensures the usage statistics panels have consistent visual appearance with proper borders and rounded corners.
    
    * feat(pricing): add GPT-5 Codex model pricing presets
    
    Add pricing configuration for GPT-5 Codex variants to support cost tracking for Codex-specific models.
    
    Changes:
    - Add gpt-5-codex model with standard GPT-5 pricing
    - Add gpt-5-1-codex model with standard GPT-5.1 pricing
    - Input: $1.25/M tokens, Output: $10/M tokens
    - Cache read: $0.125/M tokens, Cache creation: $0
    
    This ensures accurate cost calculation for Codex API requests using GPT-5 Codex models.
  • fix(test): update component tests to match current implementation
    - Add JsonEditor mock to McpFormModal tests (component uses CodeMirror
      instead of Textarea)
    - Fix assertion for missing command error message
    - Update ImportExportSection tests for new button behavior and file
      display format