* feat(kimi): manage multiple official accounts in auth center
Isolate account credentials, providers and model aliases; preserve native logins and protect official OAuth nodes. Fix session image access, drop unpublished usage repair paths and the kimi-cli alias, and synchronize all four READMEs.
* fix(kimi): address account compatibility review feedback
Restore the native default credential slot for the first account, stop rewriting tool services on account switches, allow deleting profiles removed from native config, and fix official-account test fixtures and documentation.
* fix(kimi): pin OAuth endpoints to the login region
Use fixed official hosts for mainland and global sign-ins, keep existing account regions and credential slots during reauthentication, and preserve sanitized transport error causes. Add regional routing and network-error regression coverage.
Add Kimi Code as the 12th managed app (additive mode): native multi-provider config in ~/.kimi-code/config.toml (honors KIMI_CODE_HOME), presets derived from the Pi catalog, MCP (stdio/HTTP/SSE), Skills with native-directory protection, global prompts, session browsing/resume, and session-log usage import. Local routing and aggregation do not apply; official OAuth stays managed by Kimi Code. Schema v21 -> v22 adds enabled_kimi columns.
Add a "Create a desktop shortcut" checkbox to the MSI install-directory page and a public CREATEDESKTOPSHORTCUT property for silent installs. Upgrades keep the current state of the desktop shortcut, and clearing the option during an upgrade removes the old one.
The desktop shortcut is now copied from the Start Menu shortcut by custom actions with Return="ignore", so a Desktop that cannot be written no longer blocks or rolls back the install.
Fixes#5667
Co-authored-by: thefool <thefoolyuzhe@gmail.com>
Size the provider column to the main panel's height and scroll long lists inside it, so hovering between apps no longer shifts rows under the cursor. Convert between WebView CSS pixels and screen logical pixels using the monitor scale factor on Windows, narrow and clamp the panel to the monitor work area, and let footer buttons shrink. On Windows, left-click on the tray icon now always opens the main window; right-click shows the selected tray style.
Fixes#8553Fixes#8549
Explicit provider-scoped or per-model context windows now apply to mirrored official GPT catalog entries (context_window and max_context_window), with the auto-compact limit kept in sync; official defaults remain when nothing is configured. Gemini input-overflow errors on the Codex Chat path are normalized to context_length_exceeded and returned as a response.failed stream so Codex can compact, and non-string SSE error codes are stringified so upstream messages survive.
Fixes#8366
Add a bar / area segmented toggle to the usage trend chart. Bar stays the default; the choice is remembered locally and unknown values fall back to bar. Both styles share the same metrics, axes (RFC3339 bucket keys), tooltip and currency conversion; the area chart draws a dot when there is a single data point. Fixes#8406.
When Codex replays tool-call history, empty assistant messages, progress text or reasoning can sit between a function_call and its results. Converted to Chat, these become standalone assistant messages and DeepSeek rejects the request with HTTP 400. For explicit DeepSeek model ids only, fold such messages into the open tool-call message after conversion (running after the malformed-call recovery from #8241); well-formed histories stay byte-identical. Refs #8331.
Use CSS.Translate so dragged provider cards keep their size, lift the drag layer onto the positioned wrapper, and lock horizontal movement. Fixes#8283.
Share one grid template between the Apps page header and rows so the version column lines up, and size the actions column from the widest visible button group via ResizeObserver so it shrinks once upgrade buttons are gone. Keep row height stable and truncate long install hints.
Pi session imports now estimate request duration from each assistant message's own request-start and write timestamps, so eligible rows show an estimated speed instead of a dash. Rows imported earlier keep latency 0; nothing is backfilled, matching the Claude Code and Codex importers.
* feat: add uninstall support for tools, including UI and backend integration
* feat: add manual uninstall support with UI integration and localization
* fix(usage): honor Codex thread model settings (#8176)
* fix(usage): stop treating empty OpenRouter credits as expired (#8175)
* fix(settings): use confirmed directories for unrelated autosaves (#8023)
* fix(settings): keep directory drafts out of autosaves
* fix(settings): reconcile directory display after autosave
* feat: enhance tool uninstall process with new commands and UI updates
- Added localized strings for manual uninstall hints and commands in Japanese, Traditional Chinese, and Simplified Chinese.
- Introduced a new API method `prepareToolUninstall` to generate uninstall plans.
- Created a `ToolUninstallConfirmDialog` component to confirm uninstallation and display relevant commands.
- Implemented uninstall command methods for various package managers including npm, pnpm, bun, and Homebrew.
- Updated tests to cover new uninstall functionality and ensure proper command visibility and error handling.
* fix(installer): don't recreate a deleted desktop shortcut on MSI upgrade
A major upgrade removes the old product and installs the new one from
scratch, and the desktop shortcut component was unconditional, so every
update put the shortcut back even after the user had deleted it.
Look for the existing shortcut during AppSearch (before the old version
is removed) and only install the desktop shortcut on a fresh install or
when it is still present on an upgrade.
* fix(deeplink): stop losing links on cold start and tighten import checks
Deep links that arrived before the frontend was listening were dropped:
on Windows/Linux the plugin emits the startup URL before our handler is
registered, and Tauri events fired before the JS listener exists (cold
start, window rebuilt in lightweight mode) go nowhere.
- Keep the parsed link (or parse error) in a backend pending slot with a
monotonic id and emit `deeplink-pending`. The dialog peeks on mount and
on every notification, and acks by id only after the link is shown, so
an interrupted read never loses it and a stale ack never clears a newer
link.
- Read `get_current()` after registering the URL handler so the startup
URL is handled on Windows/Linux.
- Drop our own `RunEvent::Opened` handling on macOS; the deep-link plugin
already emits it, which made links open twice.
- Process pending links serially in the dialog (rerun on notifications
that arrive mid-processing) so a late read of an older link can't
replace a newer one, including during config merge. The effect no
longer depends on `t`, so the startup language sync can't interrupt it.
- Reject `configUrl` up front instead of failing after the user confirms.
- Accept `mcode` for prompts and `pi`/`mcode` for MCP apps.
- Warn on the confirm dialog when the provider will be switched to right
away (`enabled=true`), and refresh the tray menu after a provider import.
* feat(deeplink): enable imported usage scripts by default
A provider link that carries a usage script now enables usage query
unless it says `usageEnabled=false`. Site owners attach the script so
users see their balance; making them switch it on again after import
was an extra step with little safety benefit: the script runs in the
QuickJS sandbox, sends a single request, and deep-link scripts have no
template type, so that request must be same-origin HTTPS with the base
URL.
Links without a script still import usage fields disabled. The
confirmation badge follows the same rule as the backend, and the
script body is still shown in full before the user imports.
* fix(deeplink): keep a Codex link's provider config instead of rebuilding a fixed template
A Codex provider link could carry a full config.toml, but import only
pulled the key, endpoint and model out of it and rebuilt a fixed
template, silently dropping the provider's auth mode, headers, websocket
support and model catalog URL.
When a link carries a config, keep the parts that belong to the
provider, using the same field lists the live projection writes on
switch:
- from the selected [model_providers.*] table: connection and auth
fields (wire_api, requires_openai_auth, http_headers, query_params,
supports_websockets, retries/timeouts, capabilities, ...); the route
is always renamed to `custom`
- model_catalog_url only on the same origin as the endpoint, since
Codex sends the provider's credentials when fetching it
- top-level key and provider-exclusive fields (model, reasoning effort,
web_search, context window, subagent model)
Global settings ([features], [tools], MCP, approval_policy, notify,
local file paths) are not imported. Links whose provider table makes
Codex run a command or read local credentials (auth, aws,
gateway_oauth, env_http_headers) are rejected; env_key is dropped in
favor of the link's own key, and an env_key-only link is rejected.
URL params still take priority, and a table's bearer token is reset to
the final key.
Links without a config keep the old template byte for byte; a new
golden snapshot locks the shape of config-carrying imports. The confirm
dialog notes that only provider settings are imported, and the manual
documents the rules (and that configUrl is rejected).
Refs #7438, #7942, #5510
* fix(proxy): bump the Claude Code haiku alias to claude-haiku-5-5
Routing mode writes stable role aliases into settings.json, and Claude
Code looks the alias up in its own model table to decide how to send
thinking. claude-haiku-4-5 is listed there as a model whose thinking can
be turned off and that lacks adaptive thinking, so haiku-tier requests
went out with thinking disabled and upstreams that require thinking
rejected them. claude-haiku-5-5 rejects disabled thinking and uses
adaptive thinking, matching what the sonnet and opus aliases already
send to the same upstreams.
The proxy still maps by the "haiku" role keyword, so routing is
unaffected; the new alias is written the next time the contract is
applied.
Fixes#8118
* fix(grokbuild): point session_summary at the active provider and keep a link's model profile
Session titles: when `models.session_summary` is unset, Grok Build
(verified on 1.0.50) generates titles with the built-in `grok-4.6`
model but sends the request to the default model table's endpoint, so
third-party upstreams reject it and title generation fails. Switching
never wrote this key, so fixing the row templates alone would not
reach live. The Grok switch patch now makes session_summary follow the
provider when it is unset or names a table CC Switch wrote (the
target, the write record, or a table retired in this switch): it points
at the target table, or is removed when switching to the official
account. A user's own choice (a built-in model or their own table) is
left alone.
Deep links: a Grok Build link carrying a config.toml no longer gets
rebuilt into a fixed template that dropped the profile's display name,
description, API backend and context window. The table named by
`[models] default` is kept through an allowlist of Grok 1.0.50 profile
fields; the endpoint, key and model come from the link parameters.
Links whose table uses auth_provider, env_http_headers or
mtls_cert_dir are rejected, and env_key is still dropped. Only one
model table is imported, since a provider owns one table in live.
Links without a config keep the old template byte for byte.
Fixes#7003
Refs #6457
* chore(presets): point OpenModel sign-up links at the cc-switch referral URL
Replace the campaign page link with https://www.openmodel.ai?ref=cc-switch
in every OpenModel preset's apiKeyUrl (Claude Code, Claude Desktop, Codex,
Gemini CLI, Grok Build, OpenCode, OpenClaw, Hermes, Pi; MiniMax Code
reuses the Pi preset) and in both links of the four README sponsor rows.
websiteUrl stays on the plain homepage, and the "cc-switch" promo code
already in the READMEs is unchanged.
* chore(presets): show YYLX as 鱼鱼连线 in Chinese
Give the YYLX presets a nameKey so the picker shows the site's Chinese
name, 鱼鱼连线 (魚魚連線 in zh-TW), while en and ja keep "YYLX". All nine
preset files get the key; MiniMax Code inherits it from the Pi preset.
The preset name and the inner settingsConfig.name stay "YYLX": the
former keys the search alias table and the latter is the provider name
written into client configs.
* feat(deeplink): let links declare the API format, import Pi providers, and leave activation to the user
- Add a single `apiFormat` parameter (anthropic / openai_chat /
openai_responses / gemini_native) that maps to each app's own field:
meta.apiFormat for Claude Code, Codex and Grok Build (non-native formats
need local routing), `npm` for OpenCode, `api` for OpenClaw and Pi,
`api_mode` for Hermes. Unsupported combinations are rejected while
parsing; links without it keep the previous defaults byte for byte.
- Support Pi provider links. They write a models.json node and must carry
a model.
- The confirmation dialog now has a switch for "switch after import"
(providers), "add to the app config" (additive apps, on by default) and
"enable after import" (prompts). The link's `enabled` only sets its
initial state.
- Turning the switch off really only saves the row: a new
`ProviderService::add_without_switching` skips the first-provider path
in `add` that would otherwise write the client config. The deep-link
golden rows now have is_current false accordingly.
- Reject link values that additive apps would expand: Pi keys starting
with `!` and `$NAME` / `${NAME}`, OpenCode `{env:}` / `{file:}`, and
`${...}` for OpenClaw and Hermes. These would run a command or send
local secrets and files to the link's endpoint. Checked when parsing,
when merging `config`, and when building the provider.
- Update the deep-link manual in zh/en/ja.
* docs(deeplink): add a Chinese integration guide for site owners
* feat(providers): upload a custom provider icon
The icon picker gets an "Upload Image" button (PNG, JPG, WebP or SVG, up
to 2 MB and 4096 px). The image is redrawn on a canvas into a 96x96 PNG
and stored as a data URI in the existing `icon` column, so it travels
with the row through cloud sync, duplication and profiles. No new column,
no files on disk, nothing keyed by provider id (ids are shared across
apps). Opaque square images fill the icon box; anything else is padded to
the size of a built-in transparent logo. Uploading only changes the form;
nothing is written until Save.
The original file never reaches the database: SVG is loaded through
<img> (no scripts, no external requests) and rasterized, and re-encoding
drops EXIF. Custom icons are only ever rendered with <img>; remote URLs
are never loaded as icons.
Validation at every way in:
- Saving a provider or a universal provider, and syncing a universal
provider to its apps, fully decodes the PNG with the `png` crate
(already in the tree via `image`) under a 1 MiB decode limit and caps
it at 64 KiB and 256x256. Other strings still pass as icon names so old
rows stay editable.
- SQL import and cloud sync bypass saving, so the staging database drops
invalid custom icons from both `providers` and the universal provider
JSON before it replaces the main one. The rest of the backup imports
normally.
- Rendering checks the length and reads the PNG signature, IHDR length
and dimensions from the header before showing an image, and falls back
to initials if it fails to decode. Browsers sniff image formats, so
without the signature check a disguised GIF could slip past the size
limit.
Also:
- Uploads still being processed are dropped once the user removes the
icon, picks a built-in one, uploads again or closes the picker.
- Aggregation mode no longer derives model key prefixes from a custom
icon; it falls back to the provider name.
- The deep-link `icon` parameter only accepts built-in icon names; other
values are dropped instead of failing the link, so links cannot put a
data URI straight into the database.
Refs #8117
* fix(usage): stop treating an empty Novita balance as an expired plan
Novita marked the key invalid whenever availableBalance was zero or
negative, so the card and tray showed "plan expired" for a key that still
works. Keep a parsed balance valid and let the UI show the existing
"balance used up" line instead, the same as OpenRouter in #8175.
A missing or malformed availableBalance now returns an error instead of
being read as a zero balance.
* feat(deeplink): let provider links bring their own icon via iconUrl
A provider link can now carry `iconUrl`, an https address of the site's
own logo. The confirmation dialog downloads it as soon as it opens and
shows it at the top; importing stores it as the card's custom icon. No
extra confirmation step. Any failure is silent: the card falls back to
the built-in `icon` name, or to the name's initials.
The image goes through the same path as a local upload: the backend
returns a data URI, the frontend redraws it on a canvas into a 96x96 PNG,
and the provider save validation checks it again. The address itself is
never stored or rendered, and the import command never downloads.
The download (`deeplink/icon_fetch.rs`):
- Parsing drops addresses that are not https, use an IP or a non-default
port, carry credentials or exceed 2048 characters; the rest of the link
still imports.
- Every resolved address must be public, and the connection is pinned to
them so a second DNS answer cannot point it elsewhere. Redirects are
followed by hand, up to 3, and each hop is checked again.
- No system proxy, no cookies, no Referer, 5 s overall timeout, body read
as a stream and capped at 256 KB.
- Content-Type must be PNG, JPEG, WebP or SVG and match the file's magic
bytes; bitmap dimensions are read from the header and capped at 4096.
- 198.18.0.0/15 is allowed on purpose: Clash and Surge fake-ip mode
resolve every domain into it. The trade-off is written next to
`is_public_ipv4`.
- Errors are logged without the URL, which may carry query tokens.
Closes#8117
* docs(deeplink): rework the link generator and document iconUrl
deplink.html becomes a generator for site owners instead of a test page:
a sidebar layout with light and dark themes, tabs for provider, MCP,
prompt and Skill links, per-app `apiFormat` choices, usage script
templates, and examples that follow the v4.0.10 rules (Pi providers,
the activation toggle, `apiFormat`).
iconUrl:
- The generator gets an `iconUrl` field and checks it with the same
shape rules as the app (https, a domain, default port, no
credentials), so a link is never generated with an address CC Switch
would drop. Built-in `icon` names are checked against the same
whitelist as the parser.
- The parser marks `icon` and `iconUrl` values that would be dropped.
- New example and FAQ entry for a site's own icon.
- The integration guide adds `iconUrl` to the Node.js sample and a
debugging step pointing at the log line. The zh and ja manuals list
`iconUrl` and say what `icon` accepts.
* feat(usage): add a Sub2API usage query template
Sub2API sites expose GET /v1/usage authenticated with the API key, so the
template only needs the provider's key and base URL, like the general one.
The script accepts a base URL with or without /v1, shows the plan name, and
reports used/total only when the quota has a limit, so unlimited
subscriptions (remaining -1) no longer show a negative balance.
The modal's two hand-written template-type unions are replaced with the
shared TemplateType so new templates are not silently dropped on save.
* docs(usage): document the Sub2API template and add it to the link generator
The user manual (zh/en/ja) gains a Sub2API template section, and the link
generator and the site owner guide gain a Sub2API example. All of them use
the same script as the in-app template.
* docs(deeplink): show site owners how to wire the import button
The guide explained how to build a link but not how to put it on a page.
Add a section on fetching the link from the backend when the button is
clicked (so the key never sits in the page source), the button markup,
and what to show when CC Switch is not installed. Add a fast path at the
top and fold the sections most sites can skip.
The link generator folds the Base64 tool and the MCP, prompt and Skill
examples, opens them when reached from the sidebar or an anchor, and
gains an FAQ entry pointing to the new section.
* docs: point the deep link generator to ccswitch.io and link the site owner guide
The manual linked the generator at farion1231.github.io, but GitHub Pages
was never enabled for the repository, so the link returned 404. The page
is now hosted on the website at ccswitch.io/deplink.html; the manual
(zh/en/ja), the four READMEs and the site owner guide point there.
The generator inlines its favicon and logo so the same file works both in
the repository and on the website. Manual 5.3 gains a pointer to the site
owner guide, and its usage steps list the Skill repository type.
* feat(i18n): lead the connection mode help with each mode's strengths
Direct now says CC Switch stays out of the request path for the most
native experience, Routing lists hot-switching providers, failover and
format conversion, and Aggregation says models from several providers
can be switched seamlessly inside the client. The no-failover caveat
for Aggregation stays in its dedicated notes.
* feat(usage): show first-token time in stats and estimate it without routing
The routing service has always recorded first-token time, but the usage
page only surfaced it in a hover tip and the request detail panel.
Provider and model stats gain a First token column with the median over
successful streaming requests through the routing service. The median
keeps an occasional slow request (queueing, cold start) from pulling the
number up. The request log table gains a First token column after Speed.
Without routing, first-token time is now derived from session logs and
shown with ≈:
- Claude Code: when a reply starts with a thinking block, the block's
write time minus thinkingDurationMs (timed from content_block_start to
content_block_stop) gives the moment output began.
- Codex: newer rollouts record started_at_ms on item_completed; the
earliest reasoning or agent message item of a request marks its start.
Replies that open with text or a tool call yield no estimate. A real
log replay derived 9,586 Claude Code and 10,406 recent Codex values,
with medians of 1.95s and 2.69s (routed Codex: 2.6s).
The estimate is stored in first_token_ms, so exact and estimated values
are now told apart by data_source instead of a NULL first token. The
estimated speed still divides by the whole duration, since only some
rows have a first token. Rows imported before this change are not
backfilled.
* docs(deeplink): note that New API and Sub2API ship an import button
Site owners running New API or Sub2API already have an "Import to CC
Switch" button in the key list. Say so up front, and point out that New
API's link carries no usage script, so users see no balance after import.
* fix(codex): move sessions from the retired cc-switch-official bucket back to openai
From v3.17 to v3.20, using the official account through local routing
wrote model_provider = "cc-switch-official", so those sessions were
recorded under that provider id. v4.0.0 stopped writing the table and
removes a leftover one, but Codex resumes a thread with the provider it
was recorded under, so opening those sessions now fails with "Model
provider `cc-switch-official` not found" (#7948). No earlier migration
covered this id: both existing ones predate it.
On startup, sessions recorded under cc-switch-official are moved to the
built-in openai bucket, in the state DB and in each rollout's
session_meta line (compressed rollouts included). config.toml is not
touched. openai is built in, so it always resolves. These sessions used
the official login and their table was named "OpenAI", so Codex already
treated them as OpenAI (remote compaction, web search); moving them
changes the bucket, not the behavior.
The target is openai regardless of the unified session history setting.
The migration runs before the unify migration, so with the setting on
they continue into custom through the normal path and are recorded in
its restore ledger. Moving them straight to custom would leave them
there after the setting is turned off, where custom becomes the dormant
table pointing at the local proxy.
The migration is skipped without recording completion when config.toml
or a profile still selects cc-switch-official (a hand-restored table in
use), or when a state DB cannot be locked (WSL paths from Windows):
rewriting only the rollouts would not make the sessions resumable.
Completion is recorded per Codex config directory. Backups go to the
existing session group migration backup folder, whose description no
longer says third-party.
Refs #7948
* docs(deeplink): add English and Japanese site owner guides
Translate the site owner integration guide into English and Japanese,
quoting UI labels from the app's own locale files and using each
language's Sub2API template fallback message. The three versions link to
each other. Manual 5.3 (en/ja) and the English, German and Japanese
READMEs now point to the guide in their own language.
* fix(usage): left-align every usage table column and rebalance request log widths
Numeric columns were right-aligned while text columns were left-aligned,
so headers and cells followed two rules on one page. All columns in the
request log, provider, model and pricing tables now align to the start;
the row actions column in the pricing table stays at the end.
Also give first/last cells the same 8px inset as their headers, and
lower the provider/model share of the request log from 40% to 32% so
the spare width reaches the numeric columns instead of the text ones.
* feat(providers): keep uploaded icons in a named "My Icons" library
Uploading an icon used to attach the image to the one provider being
edited, shown as a lone "Custom icon" strip above the built-in grid. It
had no name, could not be searched and had to be uploaded again for
every provider that wanted it.
The icon picker now has two groups, filtered by the same search box:
- My Icons: the first tile uploads an image. After it is resized, a
dialog asks for a name (the file name by default); "Save and Use"
stores it in the library and selects it. Library icons show their
names, can be picked by any provider in any app, and can be renamed or
deleted from the buttons that appear on hover. Uploading an image that
is already in the library reuses the existing entry. A current custom
icon that is not in the library (for example one from an import link)
shows as "Current icon" and can be saved, named after the provider.
- Built-in Icons, as before.
Clicking an icon now selects it and closes the picker, so the "Done"
button is gone; "Clear icon" next to the search box removes the icon.
The library lives in the settings table under `custom_icons`, which is
already cloud-synced. Providers still store the image itself, not a
library id, so renaming or deleting a library entry never changes a
provider that uses it, and a provider shows its icon on a device whose
library differs. Adding to the library decodes the PNG fully like
saving a provider does, caps the library at 100 icons and names at 64
characters. SQL import and cloud sync drop library entries whose image
is invalid, alongside the existing provider and universal provider
cleanup; unknown fields on the remaining entries are kept.
The naming dialog stops its submit event from propagating: React events
bubble through portals, so without it saving a name would also submit
the provider form the picker is rendered in.
The user manual's icon section (2.3, zh/en/ja) describes the new flow.
* docs(manual): describe My Icons in the add-provider icon section
Section 2.1 still said the icon area lets you pick a preset icon and
customize its color. There has been no color control for a while (the
color comes from the built-in icon's metadata), and icons can now be
uploaded to My Icons. Point 2.1 at the full description in 2.3, and
drop "and color" from the icon row of the 2.3 field table.
* chore(release): v4.0.10
* docs(release): add v4.0.10 release notes
* fix(ui): panel flicker (#8201)
* fix(ui): prevent full-page panel flicker
* fix(workspace): cancel pending note reads before deletion
* feat: add uninstall support for tools, including UI and backend integration
* feat: add manual uninstall support with UI integration and localization
* feat: enhance tool uninstall process with new commands and UI updates
- Added localized strings for manual uninstall hints and commands in Japanese, Traditional Chinese, and Simplified Chinese.
- Introduced a new API method `prepareToolUninstall` to generate uninstall plans.
- Created a `ToolUninstallConfirmDialog` component to confirm uninstallation and display relevant commands.
- Implemented uninstall command methods for various package managers including npm, pnpm, bun, and Homebrew.
- Updated tests to cover new uninstall functionality and ensure proper command visibility and error handling.
* feat: enhance npm uninstall command for Windows with path compatibility and add related tests
* feat: update uninstall command for Windows to ensure path compatibility in tests
* fix(uninstall): resolve WSL installs in the version check's shell
With no WSL shell preference, uninstall ran `sh -c`, which skips
.bashrc/.zshrc/$ENV, while version detection runs `$SHELL` with -lic,
falling back to -lc and -c. Tools initialised there (nvm and the like)
were shown as installed but could not be uninstalled, or the probe
picked another copy on PATH.
Share the auto-mode flag order with the version check. The read-only
probe retries the flags in the same order and reports the flag that
found the tool; removal runs with exactly that flag and never retries.
uninstall runs the very process the re-derived plan describes.
---------
Co-authored-by: Hulk <happyhls@gmail.com>
Co-authored-by: Jason <farion1231@gmail.com>
Co-authored-by: NestorRay <63111566+NestorRay@users.noreply.github.com>
Opening "Config directory" from an app page's menu now scrolls the App configuration settings to that app's entry with a short ease-out and flashes its outline twice. Scrolling stops as soon as the user takes over (wheel, touch, pointer, scroll keys or scrollbar), is skipped under reduced motion, and only moves the settings content pane.
npm 12 blocks Claude Code's postinstall by default and still exits 0, leaving the 500-byte placeholder at bin/claude.exe (Windows reports it as incompatible). Pass --ignore-scripts=false --include=optional --allow-scripts=@anthropic-ai/claude-code to every Claude npm install and update fallback, including the copyable install commands on the Apps page.
Open the bottom-bar tooltips upward and the expanded collapse-button tooltip to the left, so the Apps tooltip no longer covers the Settings button. Add an optional disableHoverableContent prop to HoverTip (closes on trigger leave and ignores pointer events) and enable it for all sidebar tooltips.
Keep the provider name from overlapping the failover switch and route settings button. The lead text still truncates first; the value only truncates when it alone exceeds the row, and a title shows the full text on hover.
* fix(tool): improve tool action handling and user feedback for ongoing installations
* fix(about): enhance tool upgrade handling to preserve WSL parameters across remounts
* refactor: update OpenCode configuration handling and enhance JSONC support
- Refactored OpenCode configuration reading to use `read_opencode_config_from_path` for improved error handling.
- Added tests to ensure that OpenCode JSONC provider and MCP workflows preserve comments during import and export.
- Updated localization files to reflect changes in OpenCode configuration directory description, now supporting both JSON and JSONC formats.
- Introduced a new `jsonc_document.rs` module for format-preserving JSONC/JSON5 editing, including functionality for parsing, applying changes, and validating output.
- Enhanced existing tests to cover various edge cases in JSONC handling, ensuring robustness against invalid configurations and preserving comments.
* test(opencode): 添加对 Unicode 行注释的处理测试
* fix(opencode): 添加供应商和 MCP 服务配置格式错误的警告日志
Run each Windows tool lifecycle script from its own temp directory so concurrent calls can no longer overwrite or delete each other's .bat file.
Add a backend ToolLifecycleCoordinator: a global execution lock serializes all install/update writes (pnpm/bun share one global manifest, and concurrent 'add -g' silently drops one side's entry), and a per-tool try-lock rejects duplicate submissions even after the About page remounts. Locks move into the blocking task so a cancelled caller cannot release them while the installer is still running.
The About page now locks per tool instead of globally, queues multi-install confirmation plans, ignores double clicks on the confirm dialog, and shows the full error text in a tooltip.
* feat: Enhance OpenCode provider configuration and import functionality
- Added support for built-in provider defaults in OpenCode configuration.
- Updated OpenCode provider options to allow omitting npm and model definitions.
- Improved import logic for OpenCode providers from live config, ensuring existing credentials are respected.
- Introduced tests for credential handling and built-in provider editing.
- Enhanced UI components to reflect changes in provider configuration and selection.
- Added localization for new built-in defaults feature.
* refactor(tests): enhance test environment isolation and settings management
* Refactor OpenCode provider handling and validation
- Removed TestSettingsGuard to simplify settings management during tests.
- Enhanced validation in handleDuplicateProvider to ensure npm and model definitions are provided for non-OMO providers.
- Updated OpenCodeFormFields to conditionally allow built-in defaults based on props.
- Improved ProviderForm to manage existing OpenCode overrides and prevent incomplete copies from being added.
- Added comprehensive tests for OpenCode provider duplication and validation scenarios.
- Introduced new error messages for better user feedback on provider requirements.
- Created opencode_tests.rs to cover various scenarios for OpenCode provider imports and updates.
---------
Co-authored-by: Jason <farion1231@gmail.com>
* feat: Add new AI models and update presets
- Introduced new models in piModelCatalog including:
- DeepSeek V4.1 Flash
- Step 5 Preview
- Step 3.7 Flash
- Claude Opus 5.5
- Claude Fable 5.1
- GPT-6 variants (Sol, Luna, Astra)
- Gemini 3.8 Flash
- MiMo V2.6 variants (Pro, Flash, Pro UltraSpeed)
- Updated piProviderPresets to include new models and their configurations.
- Enhanced piThinkingProfiles with new response mappings for GPT-6 Astra and other models.
- Adjusted tests to reflect new models and their expected behaviors in PiProviderForm and other configurations.
- Updated reasoning level presets for Xiaomi MiMo models to include new categories.
- Added new test cases for xAI OAuth provider presets to validate new model configurations.
* fix: 保留历史定价并修正供应商预设
* fix: 补回 MiMo Codex 官方系统提示词
* feat(pricing): 添加新 Anthropic 和 OpenAI 定价
* fix(pricing): drop alias and pre-billing rows, dedupe Opus 5.5
- Remove the duplicate claude-opus-5-5 row now that #7600 seeds it.
- Drop gpt-daybreak-{red,blue}-latest and chat-latest: rolling aliases
whose price follows whichever model they currently point to.
- Drop gpt-rosalind-research: OpenAI starts billing it on 2026-10-05 and
access is limited to the trusted-access program, so seeding it now
would bill usage from the free period.
- Keep the Astra release details in the GPT-6 comment and note why the
Daybreak aliases stay out next to gpt-5.6-cyber.
- Cover gpt-5.5-pro (no cache discount) and a dated gpt-4o-mini snapshot
in the upgrade backfill test; the latter must resolve to gpt-4o-mini,
not the shorter gpt-4o row.
---------
Co-authored-by: Jason <farion1231@gmail.com>