21 Commits
Author SHA1 Message Date
Allen Xu f88068b9e5 fix(proxy): let clients reach local routing through a separate connection address (#7878)
The proxy URL written into client configs (including Claude Desktop's gateway URL) was always derived from the listen address, with 0.0.0.0 written as 127.0.0.1, so clients outside the host's loopback, such as Claude Desktop sessions in WSL2 NAT mode, got an unreachable address.

Add an optional per-device "connection address" in Settings > Routing, stored in ~/.cc-switch/settings.json so cloud sync never carries it to another machine. When set it replaces the host in every proxy URL written to clients; saving rewrites routed clients without restarting the service and is safe to retry.

Fixes #7877
2026-10-11 17:58:46 +08:00
Allen Xu 04638fd4bc fix(ui): stop WebKit layout jitter on the usage page (#7901)
- Reserve the scrollbar gutter with overflow-y: scroll instead of scrollbar-gutter: stable, which WKWebView ignores for custom ::-webkit-scrollbar styles. Switching usage tabs no longer changes the content width and re-picks the chart's x-axis ticks.
- Slide SegmentThumb with left/top instead of transform, so WebKit no longer promotes the buttons above it to compositing layers and the icons stop jittering by half a pixel.
2026-10-06 20:54:13 +08:00
Allen Xu a776a3b184 feat(skills): add a select-all checkbox to the installed list header (#7887)
The header row already reserved space for a checkbox column but had none,
so selecting every Skill meant ticking each row by hand.

- The box acts on the rows the current search and filters show. It is
  checked when all of them are selected, indeterminate when some are, and
  clicking it while unchecked or indeterminate selects the rest.
- Selections outside the current filter are left alone.
2026-10-06 20:38:26 +08:00
Allen Xu beff557e3c feat(logging): log provider switches and routing / aggregation mode changes (#7882)
* feat(logging): log provider switches and routing / aggregation mode changes

Switching providers and entering or leaving the routing / aggregation
modes left nothing in cc-switch.log, so "I clicked switch and nothing
happened" reports could not be told apart from a rule refusal, a user
cancel or a pending roll-forward.

- [SWITCH]: every ProviderService::switch logs where it went (direct
  from -> to, or proxy route from -> to) and how it ended: done, done
  with warnings, refused by the official-provider rule (INFO), or failed
  (ERROR).
- [MODE]: enter / attach, exit / detach, route changes and the direct-mode
  route memory log the mode transition (direct / routing / aggregation),
  the route or direct provider, and whether the client config was
  rewritten; failures log at ERROR.
- Frontend: the mode dialogs log when they open and what the user picked
  (cancel, switch directly anyway, start routing, confirm with a pick),
  and the frontend-only switch gates log too.

Fixes #7881

* fix(logging): drop quoted TOML source lines from switch / mode failure logs

TOML parse diagnostics quote the offending config line, which can be the
one holding a credential. Strip the quoted source lines before the new
backend failure logs write them to cc-switch.log; line/column and the
reason are kept.
2026-10-06 17:56:51 +08:00
Allen Xu 7f3fbd068a test(pi): pin image input on official DeepSeek V4.1 Flash preset (#7865)
Assert that the Pi DeepSeek preset declares image input for deepseek-flash and keeps deepseek-v4-pro text-only.

Refs #7859
2026-10-05 16:10:20 +08:00
Allen Xu c2c24b8ccf fix(usage): drop the gray border inside the active range field and space the picker below the presets (#7864)
The active start/end card drew an orange ring around its own gray border, so a gray box showed inside the orange outline. Use border-ring so the card has a single orange outline, and add focus:ring-0 to the date and time inputs so clicking into them no longer adds another ring inside the card. Add 12px of space between the preset row and the fields below it.
2026-10-05 16:10:15 +08:00
Allen Xu a33c156e5f fix(shell): match the sidebar's bottom divider to the one above it (#7874)
The bottom bar's border-t ran edge to edge and sat flush against the last
global item, so a selected Usage row touched the line. Draw it as an inset
divider with 6px above and below, like the divider above the global items,
and drop the extra gap between Apps and Settings on the collapsed rail.
2026-10-05 09:47:15 +08:00
Allen Xu 55ef871fc7 perf(shell): animate the sidebar edge on the compositor instead of width (#7860)
Lay out the sidebar and content area at their final widths once, then draw the moving edge with a cover panel that slides on a 200 ms transform animation, so the toggle runs at the display's refresh rate instead of WKWebView's ~60fps main-thread rate. Interrupting a toggle continues from the current edge; window-resize auto-collapse and prefers-reduced-motion skip the animation. Drop the width transition and the content-width pinning from #7845. <main> gets an opaque bg-app and isolate so its z-indexed descendants (sticky matrix headers, FullScreenPanel) stay under the cover while collapsing.
2026-10-04 23:02:35 +08:00
Allen Xu cddb3b68ac fix(sessions): read Gemini CLI JSONL chat files (#7866)
Newer Gemini CLI releases record chats as tmp/<hash>/chats/session-*.jsonl and migrate legacy .json files to .jsonl on resume, so the Sessions page showed no Gemini sessions and Gemini usage sync imported nothing from them.

- Replay JSONL like Gemini CLI's loadConversationRecord (in-place upsert by id, $set and $set.messages checkpoints, $rewindTo), with an id index so replay stays linear
- Use the shared parser for the session list, message loader, full-content refs and usage sync
- Hide a legacy .json that sits beside its migrated .jsonl and delete both together, removing the legacy file first
- Skip CLI-injected <session_context>/<hook_context> and slash commands when deriving titles, and mark injected context in the message view

Fixes #7861
2026-10-04 23:02:22 +08:00
Allen Xu 372b169896 perf(shell): keep sidebar toggle from re-rendering and reflowing the page (#7845)
Move the collapsed state and the Cmd/Ctrl+\ shortcut from App into Sidebar so a toggle only re-renders the sidebar. During the 200 ms width transition, pin the content area's children to the collapsed-sidebar width so ResizeObserver-driven content (usage chart, virtual lists, tab indicators) lays out once at the end instead of every frame; skipped under prefers-reduced-motion. useSlidingIndicator no longer sets state when the measured rect is unchanged.
2026-10-04 10:33:48 +08:00
Allen Xu 2cdfc6aebc fix(proxy): preserve terminal web search output order (#6509)
When a Responses SSE stream delivers its output only in the terminal response.completed / response.incomplete event, route it through the established Responses JSON conversion so text before a web search stays ahead of the search result. A missing terminal status falls back by event name, matching the incremental path's stop reason mapping. Also fixes terminal-only function_call items that previously produced stop_reason tool_use without a tool_use block.

Follow-up to #5681.
2026-09-30 09:11:27 +08:00
Allen Xu a659440b9f fix(prompts): refresh active prompts after external file edits (#7194)
Reload the enabled prompt from its live file when the Prompts list loads, and refresh the open panel when the window regains focus, so external edits to CLAUDE.md / AGENTS.md show up without a restart.

- Keep saved templates available when the live file cannot be read.
- Skip the backfill for empty or whitespace-only files, matching enable_prompt.
- Skip the backfill while a sync/restore holds the sync lock, so a list load cannot write a stale live file into a freshly restored database.
2026-09-20 17:13:55 +08:00
Allen XuandJason ceef0a52ad ci: run Windows backend tests against WSL2 filesystems (#6233)
* ci: add WSL2 backend checks

* ci: fix WSL2 backend job by keeping MSVC toolchain on native temp

- compile test binaries before pointing TEMP/TMP at the WSL2 UNC path
  (mt.exe fails with c1010070/LNK1327 when TEMP is a UNC path)
- inject WSL2 TEMP/TMP per test step instead of via GITHUB_ENV
- use --tests so doctests cannot trigger link steps under the UNC temp
- run the filesystem contract gate before the full serial suite
- drop fmt/clippy steps duplicated from the existing Windows job

* ci: move full WSL2 suite to nightly, keep per-PR contract gate

- the full serial suite needs 50+ minutes on the 9P filesystem
  (2026/2343 lib tests finished in 39.5min before the 45min timeout)
- per-PR job now runs only the atomic-write contract (~6min total)
  and builds just the lib test binary via --lib
- new nightly workflow (schedule + workflow_dispatch, 90min timeout)
  runs the contract plus the full serial suite on the WSL2 home

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-08-10 16:21:42 +08:00
Allen Xu c39c90322a fix(windows): fall back when WSL rejects atomic replace (#6232)
* fix(windows): fall back when WSL rejects atomic replace

* fix(windows): preserve config during WSL fallback

* fix(windows): use rename fallback for WSL UNC
2026-08-10 11:29:12 +08:00
Allen Xu 0345fad604 fix(opencode): support unified OMO config (#6011)
* fix(opencode): support unified OMO config

* fix(opencode): couple rollback snapshots to writes

* fix(ci): simplify rollback version type

* fix OMO unified config review issues

* validate OMO round-trip semantics
2026-08-05 09:04:15 +08:00
Allen Xu 92ca95ffcd feat(opencode): load OMO models from runtime opencode models (#5522)
* feat(opencode): load OMO models from runtime opencode models

Surface OAuth/Zen free models in OMO/OMO Slim pickers by running the
installed OpenCode CLI, with a 20s timeout and a toast when discovery fails.

* style: fix rustfmt and prettier for OMO runtime models

* fix(opencode): pass OPENCODE_CONFIG_DIR for runtime model discovery

Honor the configured OpenCode config directory when running
`opencode models`, including WSL UNC path translation. Also drop the
unused run_detected_tool_command wrapper that failed clippy.

* fix(opencode): satisfy Windows Clippy

* fix(opencode): bound runtime model discovery

* fix(opencode): address runtime model review feedback

* fix(ci): parenthesize unsafe kill expression
2026-08-04 09:43:20 +08:00
Allen Xu 968794e30e fix(ui): reduce idle GPU usage for route status (#5767)
* fix(ui): reduce idle GPU usage for route status

* fix(ui): disable heartbeat for reduced motion

* fix(ui): preserve polling outside Tauri focus
2026-08-04 08:34:19 +08:00
Allen Xu edea624a27 fix(skills): preserve deleted default repositories (#5356)
* fix(skills): preserve deleted default repositories

* fix(skills): persist default repo initialization state
2026-07-17 15:51:29 +08:00
Allen Xu e78aa8a7c3 fix: sync openclaw and hermes live provider updates (#5098)
* fix: sync openclaw live provider updates

* fix: sync hermes live provider updates

* fix test: hermes live import stores models as array after denormalize

The test import_hermes_providers_from_live_updates_existing_provider_from_live
seeded models as a dict, but import_hermes_providers_from_live reads via
get_providers() which calls denormalize_provider_models_for_read(), converting
models from YAML dict to UI-friendly array. The test assertion accessed models
as dict -> Null -> assertion failure.

Fix: access models as array by index, matching the actual storage format after
live import. Also verify the id field is preserved in the denormalized output.
2026-07-08 12:09:56 +08:00
Allen Xu e191af4aa1 fix: OpenCode live provider import updates (#4712)
* fix: sync existing opencode providers from live config

* fix: preserve OpenCode provider display names

* docs: update comments and log messages to reflect new update behavior

- fix stale comment in lib.rs that said existing providers are skipped
- change log message from 'Imported' to 'Synced' since count now
  includes both new imports and updates
2026-07-08 10:34:49 +08:00
Allen XuandJason 03a9296c1f fix: polish usage statistics ui (#3426)
* fix: improve usage statistics ui

* chore: remove unused token suffix translation

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-06-05 08:12:17 +08:00