Commit Graph

2257 Commits

Author SHA1 Message Date
saladday 06e9cdf7f6 fix(common-config): merge arrays as union instead of replacing
Common config snippets with array fields (e.g. permissions.deny) were
silently overwriting provider-specific entries instead of merging them.
This changes deepMerge to append only new elements (deduplicated by
bidirectional subset equality), deepRemove to strip one element per
source item, and isSubset to use bipartite matching so each source
element claims a distinct target element.

On the Rust side, the live backfill path now uses a new
json_deep_remove_preserving_original_arrays that receives the original
provider settings and only removes entries injected by the snippet,
preserving entries the provider already had. Type-mismatch guards in
both the object and array branches restore the original value when a
snippet changes a key's type.

Fixes #6141
2026-08-07 14:38:43 -04:00
misaka_myu 413c09e079 fix(codex): respect user-owned model_catalog_json when generating catalog (#6087)
The Some arm of set_codex_model_catalog_json_field unconditionally overwrote model_catalog_json with the cc-switch-owned filename, discarding any user-provided custom catalog path or filename. This mirrors the ownership check already present in the None arm: only claim the pointer when it is absent or already cc-switch-owned, leaving user-managed external catalog files untouched.

Add tests covering both full-path and relative-filename user-owned catalogs in the Some arm.
2026-08-06 16:19:04 +08:00
Jason 43eaf07355 docs(release): add v3.19.2 release notes v3.19.2 2026-08-06 12:21:00 +08:00
Jason 425e932b7f chore(release): v3.19.2 2026-08-06 12:21:00 +08:00
Jason baf07a2701 perf(usage): batch Codex session inserts and preload sync cursors
Full Codex usage reimport (triggered by SQL backup import of pre-v16
backups, cursor mismatch after cross-machine restore, or manual rebuild)
pegged one CPU core for minutes on large corpora. Measured on a real
corpus (1920 rollout files / ~1.7GB / 82k billable events, macOS,
release build):

- full reimport on a disk-backed database: 36.3s -> 11.1s (~3.3x)
- the write path accounts for most of the win: per-event autocommit
  under journal_mode=delete paid one full journal create/fsync/delete
  cycle per row; Windows pays ~4.6ms per fsync (per #6122
  measurements), so the absolute win there is an order of magnitude
  larger

Changes:

1. sync_single_codex_file writes token events in batched transactions
   (1000 events per commit), releasing the connection lock between
   batches so UI queries can interleave. The sync cursor advances
   inside the same transaction as the final batch, so a crash can
   never leave the cursor ahead of the data; batches committed before
   a crash are covered on rescan by the existing request_id PK +
   fingerprint dedup.
2. CodexSyncPass preloads all session_log_sync cursors once per pass
   (the archived-sessions suffix inheritance query used substr, could
   not use an index, and ran a full table scan per archived file) and
   caches model pricing lookups per pass instead of one SELECT per
   event.
3. The three dedup queries and the insert statement use
   prepare_cached; the two dynamically assembled dedup SQL strings are
   built once via LazyLock.

Behavioral equivalence verified by replaying the real corpus before
and after the change: all 82k imported rows byte-identical across all
exported columns, with identical import/skip/suspected-duplicate
counts. The replay harness is kept as an ignored test
(replay_real_codex_corpus) for future changes on this path.
2026-08-06 09:50:14 +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
Jason 290b65c03b chore(sponsors): point Sponsor button to GitHub Sponsors profile 2026-08-04 23:32:39 +08:00
Jason 0cb6e01410 fix(ui): keep header actions visible when all apps are enabled
With every app tab, the profile switcher and the takeover toggles shown,
the header overflowed and clipped the add-provider button. Restructure
the header right side so primary actions live in a fixed shrink-0
cluster, and make AppSwitcher width-aware: apps that no longer fit
collapse into a "more" popover, with the active app always kept visible.
2026-08-04 23:32:39 +08:00
Jason 5b697abc03 chore(sponsors): move Qiniu right after AIGoCode in preset order
Reorders the Qiniu preset entry to sit directly after AIGoCode across all
eight in-app preset files. Pure block move, no field changes; README sponsor
tables are unaffected since Qiniu is not listed there.
2026-08-04 23:30:45 +08:00
zayoka 40b6376b2a fix(skills): build readme_url from the resolved source directory (#6119)
* fix(skills): build readme_url from the resolved source directory

For skills.sh installs, `skill.directory` is just the skillId (the
innermost directory name) and the search-result readme_url is the bare
repo URL, so the persisted doc link lost the real nested path
(e.g. skills/developertools/solutions/<name>) and 404'd (#6111).

- install: derive the doc path from the resolved source directory
  (repo-relative, SKILL.md-anchored) ahead of the stale readme_url
  extraction and the directory-name fallback.
- update_skill: same derivation, so records written by older versions
  self-heal on the next update instead of re-assembling the broken
  path from the stale readme_url. repo_branch already follows
  used_branch.
- New choose_doc_path / doc_path_for_source helpers with regression
  tests; dropping the resolved-path priority fails the tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(skills): harden nested source resolution

* fix(skills): refresh repaired source metadata

* refactor(skills): keep nested readme fix install-only

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: YUZHEthefool <2804776511@qq.com>
2026-08-04 23:26:12 +08:00
zayoka 668bbda916 perf(backup): batch dump INSERTs and restore preserved tables in one transaction (#6122)
* perf(backup): batch dump INSERTs and restore preserved tables in one transaction

Backup import was pathologically slow for databases with large log
tables. Measured on a database with 26k log rows (Windows, debug build):

- local file import (import_sql_string): 28.0s -> 0.39s (~71x)
- WebDAV/S3 sync import (import_sql_string_for_sync): 118.9s -> 0.33s
  (~360x)
- export: 367ms/15.4MB -> 193ms/3.9MB (column list no longer repeated
  per row)

Root causes, isolated with a phase-level benchmark (kept in the test
suite as ignored perf harnesses):

1. dump_sql emitted one INSERT statement per row. The restore side
   parses/prepares/finalizes every statement individually, so import
   cost scaled with statement count, not data volume. A control run on
   an in-memory database was equally slow, proving this is CPU-bound
   parsing, not disk I/O; journal/synchronous pragmas made no
   difference. dump_sql now emits multi-row VALUES batches of 200 rows
   (~200x fewer statements; SQLite has supported multi-row VALUES since
   3.7.11, and both old and new formats import through the same generic
   execute_batch, so dumps remain cross-version compatible).

2. restore_tables re-inserted preserved local tables (proxy logs,
   stream check logs, usage rollups) with one implicit autocommit
   transaction per row against the disk-backed staging database - one
   fsync per row, ~4.6ms each on Windows. All restores now run in a
   single transaction with the INSERT prepared once per table, which
   also makes a mid-restore failure roll back atomically instead of
   leaving a half-restored table.

Regression tests:
- dump_sql_batches_rows_into_multi_row_inserts pins the batch shape
  (450 rows -> exactly 3 INSERT statements; fails if reverted to
  per-row)
- multi_row_dump_round_trips_special_values round-trips quotes,
  newlines, commas, CJK, emoji, BLOB storage class, and NULL through
  export+import
- existing authorizer / genuine-export / sync-preserve tests still pass

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(backup): preserve SQL dump compatibility

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: YUZHEthefool <2804776511@qq.com>
2026-08-04 23:04:13 +08:00
Kim Ma 59a2bd1040 fix(usage): handle interleaved Codex token counters (#5854)
* fix(usage): handle interleaved Codex token counters

* fix(usage): dedupe replayed Codex token snapshots

* fix(usage): avoid stale cross-source snapshot dedupe
2026-08-04 16:42:33 +08:00
zayoka 6b8f36431b fix(security): cap scripts, file reads, and proxy bodies; surface deeplink usage fields (#5919)
* fix(security): harden usage script execution and Grok session log collection

Three hardening fixes in v3.19.0 code:

1. **usage_script: cap JS runtime resources and execution time**
   `execute_usage_script` used a vanilla `Runtime::new()` with no limits,
   so a malicious or buggy script delivered via deeplink or synced DB could
   hang the backend thread forever with `while(true)`. Add
   `create_script_runtime()` enforcing a 5-second interrupt handler, 16 MiB
   memory limit, and 256 KiB stack limit. Regression test confirms an
   infinite-loop script is rejected within seconds instead of blocking.

2. **Grok session log: skip oversized files**
   `sync_single_grok_file` loaded the entire `updates.jsonl` into memory
   with no size cap. Add a 50 MiB limit and skip files that exceed it.

3. **Grok session log: bound directory traversal**
   `collect_files_named` recursed without depth limits and followed
   symlinks, so a symlink cycle under `~/.grok/sessions` caused a stack
   overflow. Add a 16-level depth limit and skip symlinks entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ui): show hidden usage access token and user id in deeplink provider import dialog

The provider import confirmation dialog parsed usageAccessToken and
usageUserId from ccswitch:// URLs and persisted them in
ProviderMeta.usage_script, but never rendered them. Users could not see
these credentials before approving the import.

- Add i18n keys for usageAccessToken/usageUserId in all locales.
- Render both fields in the usage script section; mask the access token
  like usageApiKey.
- Add a regression test verifying the dialog displays the masked token
  and the user id.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(security): bound Codex model catalog and proxy response bodies

Two issues were found while auditing security boundaries:

1. **Codex model_catalog_json arbitrary file read**
    only checked the filename and
   accepted any absolute path. A malicious  could
   point CC Switch at an external file (e.g. ) or a huge
   file to exhaust memory.

   - Require the resolved path to stay inside
     using a new  helper (lexical, no filesystem calls).
   - Treat Unix-style absolute paths as absolute on Windows.
   - Cap catalog reads at 32 MiB.

2. **Unbounded proxy response bodies / compression bombs**
   Non-streaming responses and error responses were read with
    and fully decompressed without any byte
   limit, allowing a malicious upstream to OOM the backend.

   - Add  with a 128 MiB ceiling.
   - Reject oversized bodies and oversized decompressed payloads with
     .
   - Map the new error variant into the Codex proxy error response.

Regression tests cover: absolute-path containment, traversal rejection,
oversized catalog file, oversized buffered/streamed proxy responses.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ci): set up pnpm via Corepack instead of pnpm/action-setup v6

pnpm/action-setup v6 installs pnpm through a two-step self-installer:
it bootstraps the latest pnpm (11.7.0) via npm, then downloads the
pinned version (10.12.3) from the npm registry to switch. When that
second tarball fetch failed (error 23), the self-installer still
reported "done" and crashed with ENOENT on @pnpm/linux-x64's
package.json, failing the CI setup step.

Replace the action with Node 20's bundled Corepack and pin the version
once via package.json's packageManager field, so setup performs a
single exact-version download with no floating bootstrap. This also
lets release.yml drop its Windows ARM64 special case, since Corepack
has no arch restrictions, and pins the same version for local dev.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(security): close review gaps in proxy body caps, deeplink dialog, catalog path

Address maintainer review on the security PR:

- Proxy: bound the four remaining unbounded forwarder read paths
  (non-2xx error body, failover pre-read, both 2xx error-envelope
  validators) with bytes_with_limit + bounded decompression.
- Proxy: bytes_with_limit now accumulates Hyper/Reqwest/Streamed bodies
  chunk-by-chunk and aborts mid-stream instead of collecting the full
  body before comparing; Buffered keeps the post-hoc check.
- Proxy: decompression is budgeted at the decoder (Read::take on
  gzip/deflate/zstd, bounded brotli reader) via decompress_body_with_limit,
  so bombs are cut off at the byte budget instead of after full expansion,
  including stacked-encoding intermediates.
- Deeplink: show the usage section whenever any usage field is present,
  matching build_provider_meta persistence — a deeplink carrying only
  usageAccessToken/usageUserId no longer imports credentials invisibly.
- Codex catalog: after the lexical containment check, canonicalize the
  existing file and re-verify containment so symlinks inside ~/.codex
  cannot escape the config dir; the path_is_within doc comment no longer
  oversells the lexical check as symlink-safe.
- Grok sync: comment now matches the skip-all-symlinks behavior and each
  skip is logged, so sessions behind a symlink are diagnosable.
- Docs: CONTRIBUTING notes the packageManager pnpm pin and Corepack flow.

Regression tests follow the same methodology as round 1: reverting a
guard fails the corresponding test (server write-count assertions prove
the mid-stream abort; a truncated gzip stream distinguishes TooLarge
from read-to-end errors; symlink escape is rejected only after the
canonicalize re-check).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 15:44:08 +08:00
Thefool 9f19d8fdf6 feat(management): add searchable lists and bulk app toggles (#5967)
* feat(management): add searchable lists and bulk app toggles

* test(management): cover search and bulk toggle workflows

* fix(management): await refresh after app toggles

* fix(management): await collection refreshes

* fix(management): prevent stale concurrent writes
2026-08-04 14:55:10 +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
SaladDay 492245dcb9 feat(codex-oauth): show per-account usage in Auth Center (#4887)
* feat(codex-oauth): show per-account usage in Auth Center

Each ChatGPT (Codex OAuth) account under Settings → 认证 now displays its
own subscription usage — reset countdowns and per-window progress bars —
directly in the account list, instead of usage only being visible on the
active provider card.

- Add useCodexOauthQuotaByAccountId(accountId) and refactor
  useCodexOauthQuota to delegate to it (shared query key → cache reuse)
- Add CodexOauthAccountQuota, a thin per-account wrapper that reuses the
  existing SubscriptionQuotaView expanded layout (same look and 5-state
  handling as provider cards), with a light spinner on first load
- Render it under each account row in CodexOAuthSection; fetch once when
  the Auth Center opens, manual refresh available (no polling)

Copilot is intentionally left out — same as before, this is Codex-only.

* refactor(codex-oauth): stable async loading placeholder for account usage

The account header (login + badges + actions) already renders independently
of the usage query — the quota is fetched async via Tauri invoke + React
Query, so the account never waits on it. Make that visually obvious and
jump-free: while the usage loads, show a spinner inside a placeholder shaped
like the final quota card (same rounded-xl / border / bg-card), so the card
morphs smoothly into the data instead of popping in from an empty gap.

* fix(codex-oauth): scope account quota to auth center

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-08-03 21:47:49 +08:00
Jason 0e604b75bd feat(sponsors): surface Kimi first top-up bonus in README and presets
Kimi is running an API top-up promotion (distinct from the Kimi Code
subscription): new users who complete their first successful top-up get 10%
of the amount back as API credit, capped at CNY 1,000.

In the four READMEs, add a dedicated bonus paragraph between the K3 intro and
the Kimi Code subscription line, so the API and subscription paths each keep
their own call to action. All platform links in the Kimi header block now
carry the campaign track_id: README_ZH uses the mainland platform.kimi.com
tracker, while the en/ja/de READMEs use the global platform.kimi.ai one. The
kimi.com/code subscription links are unchanged.

In the app, give the six Kimi presets (claude, claudeDesktop, codex, opencode,
openclaw, hermes) a partnerPromotionKey so the offer shows under the API key
link, and add the matching string in the zh/en/ja/zh-TW locales. The Kimi For
Coding presets are deliberately left alone — the promotion does not apply to
the subscription. Promotion display is decoupled from isPartner, so this adds
no gold partner star to Kimi.

The English and Japanese strings say "CNY ¥1,000" rather than "¥1,000", since
a bare yen sign reads as JPY in those locales and would understate the offer
by roughly 20x.
2026-08-03 21:34:28 +08:00
Jason 4d3e2c3524 chore(sponsors): update RunAPI in-app promo to first top-up discount
The in-app partnerPromotion.runapi string still advertised the retired
"register and contact support for CNY 14 free credit" offer, while all four
READMEs had already moved to the first-top-up discount. Align the zh, zh-TW,
en and ja strings with the README wording: 9 折 in Chinese, 10% off in
English and Japanese.
2026-08-03 21:34:28 +08:00
Jason 996d512f6e chore(sponsors): drop NekoCode partner from README, presets and i18n
Remove the NekoCode sponsor row from the four README files (en, zh, ja, de)
and the provider preset across all seven preset files that carried it
(claude, claudeDesktop, codex, opencode, openclaw, hermes, grokBuild; there
was never a gemini preset). Also drop the matching partnerPromotion.nekocode
string in the zh/en/ja/zh-TW locales.

The nekocode icon stays registered in src/icons/extracted, since icon names
are persisted on existing provider records and removing it would blank out
the icon for users who already imported the preset. Historical CHANGELOG and
release-notes entries are left untouched.
2026-08-03 21:34:28 +08:00
Jason 9db9c56fda fix(proxy): report dropped Chat tool calls instead of faking completion
When a third-party gateway returns tool calls without a function name,
the Chat -> Responses transform silently discarded them and still marked
the turn as `completed`. Codex then saw a successful turn with nothing
left to do and ended its agent loop without any error, turning a
diagnosable upstream failure into a silent stall.

- Emit `response.failed` (streaming) or a transform error (non-streaming)
  when every tool call in a turn was dropped and none remains usable.
  Gated on `status == "completed"` so that `finish_reason: length`
  truncation keeps its own `incomplete` semantics, matching the existing
  Anthropic streaming path.
- Log all three drop sites with structured, content-free fields (call_id
  presence, argument byte counts, finish reason) so the upstream defect
  can finally be diagnosed from real traffic.
- Treat whitespace-only function names as missing, and resolve tool keys
  conservatively when upstream omits the required `index` field.

Turns that still contain a valid tool call, text-only turns and truncated
turns are unaffected. Adds 13 tests.

Refs #4341
2026-08-03 21:34:28 +08:00
makoMakoGo eb356e15bd fix(skills): resolve source dir by SKILL.md anchor instead of name (#4153)
* fix(skills): resolve source dir by SKILL.md anchor instead of name

resolve_skill_source_dir previously guessed the source dir via root.join(name).is_dir() without verifying SKILL.md, misjudging same-name non-skill dirs (e.g. the ast-grep plugin wrapper dir in ast-grep/agent-skill) and causing install failure #4141.

Now anchors on SKILL.md: direct + SKILL.md check -> root manifest explicit skills[] -> fallback by name -> root fallback. Adds 5 layout tests.

Closes #4141

* fix(skills): drop speculative manifest resolver path

resolve_via_manifest (parsing root .claude-plugin/marketplace.json &
plugin.json explicit skills[]) is inert for the actual #4141 case: the
real ast-grep/agent-skill marketplace.json declares no skills[] array,
so the manifest branch never produces a candidate. The #4141 fix is
delivered entirely by resolve_skill_source_dir step 1's SKILL.md anchor
plus the pre-existing find_skill_dir_by_name DFS.

Keeping the manifest path would pull npx-skills package-parity semantics
(pluginRoot / source / remote-object source / skills[] / "./"-validation
/ ...) into a bug hotfix, with no real manifest proving it is not dead
code. Drop it to keep this PR a focused #4141 hotfix.

- remove SkillMarketplaceMetadata / SkillManifestPlugin /
  SkillMarketplaceManifest, resolve_via_manifest, sanitize_manifest_path
- narrow resolve_skill_source_dir to 3 steps
  (direct+SKILL.md -> by-name DFS+SKILL.md -> root+SKILL.md -> None)
- replace the two synthetic manifest tests with a negative case:
  same-name wrapper dir without SKILL.md and no inner skill -> None

cargo test --lib resolve_skill_source_dir: 7 passed
cargo clippy --lib: clean
2026-08-03 19:05:51 +08:00
mhy1227 f38722a440 feat(pricing): seed Qwen3.8 Max built-in model pricing (#6053)
* feat(pricing): seed Qwen3.8 Max built-in model pricing

Add insert-if-absent row for qwen3.8-max at 2/6 USD per Mtok input/output with 0.20 cache read.

* fix(pricing): set qwen3.8-max cache write to 2.50

Align cache_write with official explicit context-cache rate (125 percent of input). cache_read stays 0.20 (10 percent hit).

* fix(pricing): correct qwen3.8-max cache read price

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-08-03 17:57:24 +08:00
Xu Lei 13ea497ab0 fix(proxy): improve GitHub Copilot compatibility with modern Claude Code (#5832)
* 修复 Copilot 与新版 Claude Code 的兼容问题

* docs(proxy): correct Copilot placeholder rationale to the real mechanism

Claude Code (verified on 2.1.220) does not format-validate ANTHROPIC_API_KEY
against sk-ant-*: in headless mode the placeholder is sent upstream as-is.
The actual failure mode is the interactive custom-API-key approval prompt,
which defaults to "No (recommended)" — following the default ignores the
key and lands users in "Not logged in". Also drop the #3289 citation,
which describes a missing-placeholder scenario, not key validation.

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-08-03 10:26:22 +08:00
mao qinghui 8383076791 fix(hermes): use SOUL.md instead of AGENTS.md for Hermes prompt filename (#5779)
* fix(hermes): use SOUL.md instead of AGENTS.md for Hermes prompt filename

* test(hermes): add regression test for SOUL.md prompt filename

---------

Co-authored-by: mmm-05610 <maoqh@users.noreply.github.com>
Co-authored-by: Jason <farion1231@gmail.com>
2026-08-02 22:02:06 +08:00
Jason ebbf141fc7 chore(sponsors): drop Unity2.ai partner from README, presets and i18n
Remove the Unity2.ai sponsor entry from the four README files (en, zh, ja,
de) and the provider preset across all eight preset files (claude, codex,
gemini, opencode, openclaw, hermes, claudeDesktop, grokBuild). Also drop
the matching partnerPromotion.unity2 string in the zh/en/ja/zh-TW locales.

Historical CHANGELOG and release-notes entries are left untouched.
2026-08-01 11:39:58 +08:00
Jason fbf52cff73 docs(release): correct the v3.19.1 pointer to the DeepSeek routing guide
The Usage Guides entry told readers the guide's DeepSeek sections no
longer applied to this release. That was true when v3.19.1 shipped, but
the guide has since been rewritten for it, so the warning now steers
people away from an accurate document.

Replace it with what the guide actually says: presets created after
3.19.1 connect directly, while providers saved earlier and
deepseek-v4-pro still need routing. Also drop MiniMax from the
Chat-format list — it moved to native Responses too — and name Zhipu GLM
instead.

The published release body on GitHub was updated to match.
2026-08-01 10:29:39 +08:00
Jason a4bba43f73 docs(guides): update Codex DeepSeek routing guide for v3.19.1
The guide used DeepSeek as its Chat-format example, which stopped being
accurate once the preset moved to native Responses. It is not obsolete,
though: a provider saved before 3.19.1 keeps its stored apiFormat and
still carries the "needs routing" badge, and deepseek-v4-pro has no
official Codex integration yet, so Chat + routing remains its only path.

Rather than swap in a different provider, open with a check for which
case the reader is in (badge present/absent/no-routing-support) plus a
three-row table for DeepSeek specifically. The title and filename stay
put — six published release notes and three sibling guides link here.

Also in this pass:

- Drop the screenshot of the old boolean "needs local routing mapping"
  toggle; that control is now Advanced Options -> Upstream Format, a
  three-way select. The image file stays, since the official-auth
  preservation guide still references it.
- Document the Anthropic Messages format, previously unmentioned.
- Fix the Chat-provider list: DeepSeek and MiniMax both moved to
  Responses, so name Kimi, Zhipu GLM, SiliconFlow and ModelScope.
- Note that converting an existing provider keeps the official catalog's
  capabilities (freeform apply_patch, GPT-5 harness, low/high/max,
  web_search) but that its stored contextWindow of 1000000 overrides the
  official 1048576, with two ways to fix it.
- Record the direct connection's prerequisites: Codex CLI 0.144.0+ and a
  ~75 KB catalog file.
- Add a usage-attribution section: the provider dimension collapses into
  Codex (Session), while the model dimension still separates rows.
- Reference DeepSeek's official Codex integration and Responses API docs.

All UI terms are taken from the locale files so they match what the app
actually renders in each language.
2026-08-01 10:29:32 +08:00
Jason 28529620f4 docs(release): add v3.19.1 release notes v3.19.1 2026-07-31 22:30:36 +08:00
Jason b3a20e58b0 chore(release): v3.19.1 2026-07-31 22:30:28 +08:00
Jason 58dd376dc4 feat(codex): add Tencent Hunyuan TokenHub preset with native Responses
Official TokenHub Codex docs (cloud.tencent.com/document/product/1823/133532)
confirm hy3 speaks the Responses API natively; the mandatory
disable_response_storage=true is already emitted by the config
generator. Models hy3/hy3-preview are text-only with a 256k context
window. Endpoint candidates include the official backup domain, while
the intl site is excluded because API keys are region-scoped.
2026-07-31 19:12:58 +08:00
Jason 56a66eea36 feat(codex): switch Volcengine Agentplan preset to native Responses
Official Codex docs (volcengine.com/docs/82379/2556056, updated
2026-07) confirm the Coding Plan endpoint /api/coding/v3 supports the
Responses API, so the preset no longer needs local route conversion.
BytePlus stays on Chat routing until the international-site docs are
verified. Also document the billing pitfall: the pay-as-you-go /api/v3
endpoint must never appear in plan-subscription endpoint candidates.
2026-07-31 19:12:58 +08:00
Jason 8ae1ce8558 feat(codex): add DeepSeek native Responses support with official catalog mirror
- Switch the DeepSeek preset to openai_responses and align context
  windows with the official catalog (1048576)
- Mirror DeepSeek's official models.json verbatim for native /responses
  providers on deepseek.com hosts, keeping the official GPT-5 harness
  and freeform apply_patch registration self-consistent
- Make catalog spec displayName/contextWindow explicit-only (Option) so
  local defaults no longer clobber official vendor values
2026-07-31 19:12:58 +08:00
Jason f42534ed26 fix(pricing): sync seeded model prices with vendor list prices
- deepseek-chat / deepseek-reasoner: now legacy aliases of V4 Flash,
  0.27/1.10 & 0.55/2.19 -> 0.14/0.28 (cache read 0.0028)
- minimax-m3: 0.60/2.40 -> 0.30/1.20 (official standard tier)
- gpt-5.6-luna -80% (1/6 -> 0.20/1.20) and gpt-5.6-terra -20%
  (2.50/15 -> 2/12) per OpenAI's 2026-07-30 price cut; sol unchanged
- seed 8 new models: bare claude-{opus,sonnet}-4-6, gemini-3.5-flash-lite,
  kimi-k2.7-code-highspeed, glm-5-turbo, glm-5v-turbo, gpt-5.3-codex-spark,
  qwen3.6-flash
- repair guards for existing installs, dual guards on GPT-5.6 rows to
  cover pre-v3.19 DBs that missed the cache-write backfill
2026-07-31 19:12:58 +08:00
Jason e3f80a98f3 fix(codex): clear stale auth on official switch 2026-07-31 19:12:58 +08:00
Jason f07edc7680 fix(settings): make Grok Build upgrade work from the GUI
`grok update` discovers and installs releases by spawning `npm view` and
`npm i -g`, even for xAI's native install — 0.2.112 moved the self-update
path onto npm distribution, so the binary now needs node on PATH.
Lifecycle scripts run under a non-login `bash -c` inheriting launchd's
narrow PATH, where npm and node are invisible, so upgrading grok failed
with a bare `Error: No such file or directory (os error 2)`.

Inject the login shell's real PATH into run_tool_lifecycle_silently,
closing the asymmetry between probing (`$SHELL -lic`, which reads .zshrc)
and execution (non-login bash). Read it through `/usr/bin/env` rather
than `echo $PATH`: fish stores PATH as a list and would emit
space-separated segments, while env always prints the child's real
environment. This also revives the install chain's bare `npm i -g`
fallback, which could only ever exit 127 under the narrow PATH.

Chain the official installer after native Grok's self-update. An npm
fallback would share both of the primary's failure modes — no node, or a
registry mirror missing the tarball — and fail alongside it; the
installer is the only node-free path and lands in the same ~/.grok/bin.
It also rewrites `[cli] installer` back to `internal`, healing users whom
the install-time npm fallback had switched onto npm distribution.
2026-07-31 19:12:58 +08:00
mhy1227 a354f08a3d fix(i18n): add 9 missing translation keys to all locales (#5960)
* fix(i18n): add missing grokBuild translation keys to all locales

providerForm.requiredFields and failover.tooltip.takeoverRequired were
missing from all four locale files (en, zh, zh-TW, ja). The Grok Build
provider form validation toast and the failover tooltip fell back to
hardcoded Chinese defaultValue, which leaked simplified Chinese into
zh-TW and zh-Hant UI even though fallbackLng is set to en.

Add the two keys to every locale so each language shows its own
translation.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(i18n): add 6 more missing translation keys to all locales

A broader scan found six more keys referenced in code with hardcoded
Chinese defaultValue but missing from all four locale files (en, zh,
zh-TW, ja):

- provider.duplicateLiveIdsLoadFailed (App.tsx provider duplicate toast)
- codexConfig.noCommonConfigToApply (useCodexCommonConfig snippet error)
- claudeDesktop.route.stopBlockedByTakeover (ClaudeDesktopRouteToggle warning)
- notifications.proxyReasonClaudeDesktop (useProviderActions proxy reason)
- proxy.server.stopped / proxy.server.stopFailed (useProxyStatus toasts)

Add proper per-language translations to all locales, matching the
existing sibling-key style (e.g. proxy.server.started/startFailed uses
the same {{detail}} interpolation).

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(i18n): add missing unpriced translations

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
2026-07-31 18:18:32 +08:00
Komi 4bfb3fc30d fix(usage): dedupe Claude Desktop proxy and session logs (#5951) 2026-07-31 15:00:18 +08:00
Thefool c49cf96a16 fix(grokbuild): complete proxy and deep-link integrations (#5677)
* fix(grokbuild): complete proxy integration

* fix(deeplink): preview GrokBuild configs safely

* test(app): stabilize provider integration suite

* fix(grokbuild): address review feedback

* fix(grokbuild): resolve remaining review findings

* fix(grokbuild): use native sessions and harden previews
2026-07-31 14:56:42 +08:00
Leo b884595a23 fix(i18n): prevent zh-TW tool management fallbacks (#5943)
Complete the Traditional Chinese strings for the About-page tool manager and align the install/update hint with the current supported tools. Add locale coverage that requires every tool-management label and preserves interpolation variables across all four translations.

Constraint: The About tool manager was extended across three commits without matching zh-TW entries.
Rejected: Rely on i18next fallback text | leaves the Traditional Chinese UI partially English and hides future locale drift.
Confidence: high
Scope-risk: narrow
Directive: Update toolManagementLocales.test.ts whenever the About tool manager adds a translatable label.
Tested: pnpm typecheck; pnpm format:check; 7 locale tests; 575 Vitest tests; zero missing zh-TW settings keys
Not-tested: Manual visual inspection of the About page
Related: e3df86587, ea604a182, 014c82d28
2026-07-31 12:23:36 +08:00
SaladDay 4317bd9981 refactor: remove redundant proxy query paths (#5928) 2026-07-31 08:52:22 +08:00
SaladDay 3c1154bed9 refactor: remove superseded dead code (#5916) 2026-07-30 22:32:10 +08:00
Jason c0ff89b9b2 docs(changelog): sync 3.19.0 security section with the release notes v3.19.0 2026-07-30 12:02:34 +08:00
Jason 3b9d059343 docs(release): add v3.19.0 release notes 2026-07-30 12:01:38 +08:00
Jason 6b13d01825 chore(release): v3.19.0 2026-07-30 09:29:54 +08:00
Jason f5f4281d06 refactor(ui): always show icon-only app switcher, drop auto-compact
The toolbar app switcher used a ResizeObserver-based overflow detection
(useAutoCompact) to collapse app labels when space ran out. With the
number of managed apps growing, the labels are collapsed in practice
anyway, so remove the mechanism and render icons only. Buttons now carry
title/aria-label so app names remain discoverable via tooltip and
accessible to screen readers.
2026-07-30 08:52:48 +08:00
ayanamislover 56fb46c093 perf(codex): cache parent rollout timelines across fork cutoffs (#5626)
* perf(codex): cache parent rollout timelines

* fix(codex): harden parent timeline cache

* fix(codex): tighten replay cache invalidation

---------

Co-authored-by: Ayanami <ay@nami.ltd>
Co-authored-by: SaladDay <92240037+SaladDay@users.noreply.github.com>
2026-07-29 23:49:46 +08:00
Jason 30409878bd chore(presets): add PackyCode backup endpoints
Add three fallback endpoints alongside the primary www.packyapi.ai across
the five preset files that support endpointCandidates:

  https://cf.api.fan
  https://slb-v1.api.fan
  https://www.packyapi.com

The /v1 suffix follows each file's existing convention rather than the
literal values supplied: bare domains for the Anthropic-native presets
(Claude Code, Claude Desktop, Gemini), /v1 for Codex and Grok Build.
Candidates are consumed as complete base URLs by the endpoint picker and
the speed test, so they must sit at the same path level as the primary.

www.packyapi.com is the pre-b0482320 domain, kept here deliberately as a
fallback -- not a leftover of that migration.

OpenCode, OpenClaw and Hermes have no endpointCandidates field in their
interfaces and are untouched.
2026-07-29 17:09:29 +08:00
Jason bfb767ae17 chore(presets): align Code0 and Qiniu Gemini defaults to 3.6 Flash
Both presets pinned gemini-3.1-pro-preview while the other Gemini presets
had moved to gemini-3.6-flash. Note this is a tier change rather than a
version bump: there is no 3.6 Pro release and 3.5 Pro is still limited to
partner testing, so the current baseline is a flash-tier model.

The gemini-3.1-pro-preview row in the built-in pricing seed is kept so
historical usage keeps its cost.
2026-07-29 16:40:31 +08:00
Jason dbb265956e feat(presets): add A6API sponsor preset across all supported apps
Add the A6API aggregator preset to Claude Code, Claude Desktop, Codex,
Gemini CLI, OpenCode, OpenClaw, Hermes and Grok Build, placed after
NekoCode in the sponsor ordering. Base URLs follow the per-client
convention: no /v1 suffix for the Anthropic-native and Gemini endpoints,
/v1 for the OpenAI-compatible ones. Model defaults mirror NekoCode.

Also add the four-locale promotion copy, the sponsor row in all four
READMEs and the icon index entry.

The supplied artwork was resized before landing: the icon was a 1024x1024
PNG base64-wrapped in an SVG shell (652K, the largest entry in iconUrls
and shipped in every build), now a 256x256 PNG at 60K; the banners were
16:9, the only ones deviating from the 2.406 project standard, now
cropped to 1280x532.
2026-07-29 16:40:23 +08:00