When a repo itself is a single skill (SKILL.md at repo root), the
discovery phase sets directory to the repo name, but after ZIP
extraction (which strips the root folder), no matching subdirectory
exists. Add a fallback to check if SKILL.md exists directly in the
extracted temp directory before reporting SKILL_DIR_NOT_FOUND.
Fixes installation of repos like zlbigger/Google-SEOs.skill.
The request count and total cost were displayed both in the app filter
bar and in the UsageSummaryCards below it. Remove the redundant inline
summary and its unused imports.
Replace all remaining "代理服务/Proxy Service/プロキシサービス" references
in the local routing feature context with "路由服务/Routing Service/
ルーティングサービス". This covers service settings, status messages,
tooltips, field descriptions, and tab labels.
Global Proxy, HTTP proxy hints, and AI Agent references are unchanged.
Rename 4.2-takeover.md to 4.2-routing.md in zh/en/ja user manuals,
replacing all "接管/takeover" terminology with "路由/routing" to match
the rebranded feature name. Update README index links accordingly.
Replace all user-facing references to "本地代理接管/Local Proxy/Takeover"
with "本地路由/Local Routing/ローカルルーティング" across zh/en/ja to
eliminate naming confusion with the separate "Global Proxy" feature.
Only i18n string values are changed; keys, code identifiers, and
database schema remain untouched.
The per-provider proxy configuration (meta.proxyConfig) is removed
because its scope is too narrow and covered by global proxy settings
and proxy takeover mode. Users can achieve the same result via the
global proxy panel.
Changes:
- Remove ProviderProxyConfig type (frontend TS + backend Rust)
- Remove ProviderAdvancedConfig proxy UI block, keep testConfig/pricingConfig
- Simplify http_client: delete build_proxy_url_from_config,
build_client_for_provider, get_for_provider
- Simplify forwarder/stream_check/model_fetch to use global client
- Remove i18n keys (en/zh/ja)
- Fix pre-existing test bug in transform.rs (extra None arg)
- Fix request classification: treat messages containing tool_result as
agent continuation instead of user-initiated, preventing false premium
charges on every tool call
- Add subagent detection via __SUBAGENT_MARKER__ and metadata._agent_
fallback, setting x-interaction-type=conversation-subagent
- Add deterministic x-interaction-id derived from session ID to group
requests into a single billing interaction
- Add orphan tool_result sanitization to prevent upstream API errors
that could cause retries and duplicate billing
- Reorder pipeline: classify (on original body) → sanitize → merge →
warmup, ensuring classification sees raw tool_result semantics
- Enable warmup downgrade by default with gpt-5-mini model
- Enhance session ID extraction priority chain for Copilot cache keys
- Detect infinite whitespace bug in streaming tool call arguments
SSRF protection (private IP blocking, suspicious hostname detection) was
originally added for web-server threat models but is unnecessary for a
local desktop app where the user already has full network access. This
removal unblocks legitimate use cases like enterprise intranet APIs,
Docker container addresses, and self-hosted services.
Retained: HTTPS enforcement and same-origin checks which still provide
meaningful security (protecting API keys in transit and preventing
scripts from leaking keys to unrelated domains).
The RequestLogTable had a hardcoded 24-hour rolling window, ignoring the
dashboard's time range selector. Now it accepts a timeRange prop and
dynamically adjusts the query window, so users can view logs beyond just
the last day.
Show first 3 and last 3 page buttons instead of just first/last, with
Set-based deduplication for clean edge merging. Add a page number input
field with Go button for direct page navigation.
OpenClaw gateway injects `[message_id: UUID]` metadata at the end of
every message, wasting display space. Strip this suffix from both title
and summary fields.
Also change session title display from single-line truncate to
line-clamp-2, so longer titles (e.g. OpenClaw's timestamp-prefixed
messages) can show more meaningful content across two lines.
Previously Codex and OpenClaw sessions only showed the working directory
basename as the title, making it hard to distinguish sessions in the same
project. Now both providers extract the first real user message as the
session title, matching the existing Claude Code behavior.
- Codex: first user message → dir basename (skips AGENTS.md injection)
- OpenClaw: displayName (sessions.json) → first user message → dir basename
- Move TITLE_MAX_CHARS constant to shared utils.rs
- Use Option<&HashMap> for OpenClaw parse_session to avoid leaky abstraction
Extract message_id from Claude API responses (msg_xxx) and use it to
generate a shared request_id format (session:{msg_xxx}) between the
proxy logger and session log sync. When session sync encounters the
same request_id via INSERT OR IGNORE, it skips the duplicate.
- Add message_id field to TokenUsage, extracted from Claude responses
- Add TokenUsage::dedup_request_id() to generate shared request IDs
- Define SESSION_REQUEST_ID_PREFIX constant to eliminate magic strings
- Change proxy logger to INSERT OR REPLACE for richer-data-wins semantics
Add pricing data for 4 new providers (Qwen, xAI Grok, Mistral, Cohere)
and supplement existing providers (MiniMax M2.5/M2.7, GLM-5/5.1,
Doubao Seed 2.0, MiMo V2 Pro, OpenAI o1/o3/codex-mini/gpt-5-mini/nano).
Fix outdated prices for deepseek-chat, deepseek-reasoner, and kimi-k2.5.
Fix display_name casing "Mimo" → "MiMo" for consistency.
Use prepared statement in seed_model_pricing() to avoid recompiling SQL
on each of ~130 INSERT iterations.
Schema migration v8→v9: DELETE + re-seed model_pricing for existing users.
Prevent users from switching to official providers (Anthropic/OpenAI/Google)
when proxy takeover is active, as using a proxy with official APIs may cause
account bans.
Defense-in-depth across 4 layers:
- Backend: ProviderService::switch(), hot_switch_provider(), switch_proxy_provider command
- Frontend: useProviderActions soft guard with error toast
- UI: ProviderActions button disabled with ShieldAlert icon
- Tray menu: official provider items disabled with ⛔ indicator
Also warns when enabling proxy takeover while current provider is official.
* Preserve cache hints when collapsing system prompts
Strict OpenAI-compatible chat backends still need fragmented Claude\nsystem prompts collapsed into one leading system message, but that\nnormalization should not silently drop stable cache hints. Preserve\nmessage-level cache_control when the merged system fragments agree,\nand fall back to omitting it when the fragments conflict.\n\nConstraint: Must keep single-system normalization for Nvidia/Qwen-style chat backends\nRejected: Always copy the first cache_control | could misrepresent conflicting cache boundaries\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: If system prompt merging changes again, preserve cache_control whenever the merged metadata is unambiguous\nTested: cargo test proxy::providers::transform --manifest-path src-tauri/Cargo.toml\nNot-tested: End-to-end prompt caching behavior against cache-aware OpenAI-compatible upstreams\nRelated: #1881
* Tighten cache hint inheritance for merged system prompts
The follow-up cache hint fix still treated mixed present/absent\ncache_control across fragmented system prompts as inheritable, which\nexpanded the cache scope after prompt collapse. Treat that mix as\nambiguous and only preserve cache_control when every merged fragment\nexplicitly agrees on the same value.\n\nConstraint: Must preserve strict-backend system prompt normalization from #1942\nRejected: Inherit first present cache_control | widens cache scope when later fragments were intentionally uncached\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Any future merged-system cache hint logic should treat missing cache_control as semantically significant\nTested: cargo test proxy::providers::transform --manifest-path src-tauri/Cargo.toml\nNot-tested: End-to-end upstream caching behavior against cache-aware relays\nRelated: #1881\nRelated: #1946
* Keep cache-control merge regressions easy to review
Reflow the two long cache-control regression assertions in transform.rs so the neighboring merge cases stay rustfmt-aligned and easier to scan.
This keeps the preserved code change separate from the untracked Markdown design notes the user did not want committed.
Constraint: Exclude Markdown design files from the commit while preserving the local code change
Rejected: Include docs in the same commit | user explicitly asked to leave Markdown files out
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Treat this as a readability-only test change; do not infer runtime behavior changes from it
Tested: cargo test --manifest-path src-tauri/Cargo.toml test_anthropic_to_openai_drops_ --lib
Tested: cargo check --manifest-path src-tauri/Cargo.toml --tests
Tested: pnpm format:check
Tested: pnpm typecheck
Not-tested: Full application integration and manual flows
Responses conversions still use promptCacheKey, but chat completions now stay a pure shape transform. This keeps Claude -> chat requests aligned with providers that do not understand the field and keeps stream checks consistent with production behavior.
Constraint: Issue #1919 requires removing prompt_cache_key from Claude -> OpenAI Chat requests
Rejected: Add a runtime toggle for chat injection | requested behavior is unconditional removal
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep promptCacheKey limited to Claude -> Responses conversions unless a provider-specific contract is proven
Tested: cargo test anthropic_to_openai
Tested: cargo test anthropic_to_responses_with_cache_key
Tested: cargo test transform_claude_request_for_api_format_responses
Not-tested: Full src-tauri test suite
Related: #1919
* feat(window): add app-level window controls with settings toggle
Add a persistent settings toggle to enable app-level minimize/maximize/close controls and hide system decorations when enabled, providing a Wayland-friendly fallback for broken native titlebar interactions.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(window): restrict app-level window controls to Linux only and fix startup flicker
- Guard useAppWindowControls with isLinux() in App.tsx so it's always
false on macOS/Windows even if persisted as true
- Wrap set_decorations call in lib.rs with #[cfg(target_os = "linux")]
- Only show the toggle in WindowSettings on Linux
- Skip setDecorations effect while settingsData is still loading to
prevent the Rust-side decoration state from being overridden by the
undefined->false fallback, which caused a brief title bar flicker
---------
Co-authored-by: wzk <wx13571681304@outlook.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Jason <farion1231@gmail.com>
- Simplify "ChatGPT Plus / Pro" → "ChatGPT" across all three languages
- Clarify Codex OAuth description to highlight Claude Code usage
- Add "requires manual activation" note for Token Plan and third-party balances
- Add Copilot API consumption caveat to the interaction optimizer section
- Update overview with skills.sh search, usage tracking, and onboarding mentions
- Add PR credits for TheRouter (@cmzz), Kaku/OMO Slim/Thinking fallback/auth tab (@yovinchen)
Update base URL to cc-api.pipellm.ai, add complete model definitions
(Opus/Sonnet/Haiku), add Codex preset with custom TOML config, add
pipellm PNG icon, and set apiKeyUrl to referral link.
Multi-protocol provider: Anthropic for Claude, OpenAI Responses for
Codex/OpenClaw, OpenAI for OpenCode, custom Gemini config. Includes
PNG icon via URL import and provider-specific settings like effortLevel,
enabledPlugins, and custom TOML config for Codex.
Add Shengsuanyun (胜算云) as an aggregator partner across all five apps,
positioned right after official providers. Uses anthropic-messages
protocol for OpenCode/OpenClaw. Includes URL-based icon import (217KB
SVG), partner promotion i18n for zh/en/ja, and localized display name.
The icon index (index.ts) is hand-curated with optimized SVG content
and custom name mappings. Running the generation script destroys these
optimizations. Remove the script entirely to eliminate the risk.
Add LionCCAPI as a third-party partner provider across all five apps
(Claude, Codex, Gemini, OpenCode, OpenClaw) with anthropic-messages
protocol for OpenCode and OpenClaw. Include partner promotion i18n
entries for zh/en/ja locales and lioncc icon.
When thinking.type is "adaptive" (Claude's maximum thinking mode) and
output_config.effort is absent, resolve_reasoning_effort() incorrectly
mapped it to "high" instead of "xhigh" in OpenAI format conversions.
Replace the old low-res x-code inline SVG (7.6KB) with a new high-res
xcode.svg (286KB) loaded via Vite URL import. Update all three provider
preset files to reference the new icon name.
Add dual rendering mode to the icon system: small optimized SVGs
continue to be inlined via dangerouslySetInnerHTML, while large SVGs
and raster images (png/jpg/webp/etc) use Vite URL imports rendered
as <img> tags. Added dds.svg (1.4MB) as the first URL-based icon.
Updated generate-icon-index.js to support multi-format icons with
a manual URL_ICONS control list. Updated ProviderIcon to handle
both inline SVG and URL-based rendering paths.
cc-switch could already persist arbitrary OMO Slim agent keys and top-level fields, but the built-in metadata and UI copy still reflected the pre-council agent set. This made the upstream council feature look unsupported and pushed users toward manual JSON-only setup.
Promote council to a built-in OMO Slim agent, add copy that points top-level plugin settings at Other Fields, and lock the behavior with regression tests.
Constraint: oh-my-opencode-slim exposes council through both agents.council and top-level council config
Rejected: Add a dedicated council editor UI now | too much surface area for issue #1981
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep OMO Slim built-in agent metadata aligned with upstream agent additions before shipping UI support
Tested: pnpm exec vitest run tests/utils/omoConfig.test.ts tests/components/OmoFormFields.mergeCustomModelsIntoStore.test.ts
Tested: pnpm typecheck
Not-tested: End-to-end validation against a live oh-my-opencode-slim installation
Related: farion1231/cc-switch#1981
Kaku is a WezTerm-derived macOS terminal, so reusing the existing WezTerm-compatible launch path keeps the change small while making it selectable in settings and session resume flows.
Constraint: Kaku support should stay macOS-only and avoid introducing a separate launcher model
Rejected: Treat Kaku as a silent WezTerm fallback | users could not explicitly choose it in settings
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep Kaku on the shared WezTerm-compatible launch path unless upstream drops the start-compatible CLI
Tested: pnpm typecheck; pnpm format:check; cargo check --manifest-path src-tauri/Cargo.toml; cargo fmt --manifest-path src-tauri/Cargo.toml --check; cargo test --manifest-path src-tauri/Cargo.toml --lib session_manager::terminal::tests
Not-tested: End-to-end launch against a locally installed Kaku.app
Related: #1954
The Claude provider form reopened with an empty Thinking model after users saved only a main model. This updates model-state hydration to mirror the existing Haiku-style fallback semantics: read ANTHROPIC_REASONING_MODEL when present, otherwise display ANTHROPIC_MODEL, without writing a synthetic reasoning field back into config.
Constraint: Existing Haiku, Sonnet, and Opus selectors already rely on read-time fallback behavior
Rejected: Persist ANTHROPIC_REASONING_MODEL from ANTHROPIC_MODEL automatically | would diverge from Haiku behavior and silently rewrite saved config
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep Thinking fallback read-only unless all model-mapping fields are intentionally migrated to write-through semantics
Tested: pnpm typecheck
Tested: pnpm test:unit (1 unrelated pre-existing failure in tests/components/UnifiedSkillsPanel.test.tsx mock setup)
Not-tested: Manual add-provider reopen flow in the desktop UI
The settings page already routes the auth tab label through the shared i18n key, but the locale bundles never defined that key. Adding the missing entries fixes the label with the same simple pattern used by the other tabs.
Constraint: Keep the fix aligned with the existing settings-tab i18n flow
Rejected: Add component-level bilingual rendering | unnecessary for a missing translation key
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: When adding settings tabs, define locale keys in every bundled language before relying on fallback text
Tested: pnpm format:check; pnpm typecheck
Not-tested: Manual verification in the desktop UI
- Make migrate_v6_to_v7 check skills table existence before ALTER
- Make migrate_v7_to_v8 check model_pricing table existence before UPDATE
- Fix SessionManagerPage test: use getByRole heading instead of getAllByText
which breaks when highlightText splits text across <mark> elements
- Add content_hash and updated_at fields to 4 InstalledSkill literals in skill_sync.rs
- Add useCheckSkillUpdates and useUpdateSkill to UnifiedSkillsPanel test mock
- Suppress unused import warning in auto_launch.rs test module