You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
authored and
王超
committed
ui(cc-switch-import): side-by-side ProxyModal footer buttons, drop import hint line
Replace the two stacked full-width dashed buttons with a flex row —
"Import from cc-switch" on the left, "+ Add proxy" on the right, each
half-width. Remove the explanatory hint line under the import button and
its now-unused ui.proxy.ccswitchImportHint i18n key (x18 locales).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: history.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,7 @@
14
14
- feat(proxy): **Import providers from cc-switch** — reads AI provider credentials (baseURL/authToken/model mappings) from the local [cc-switch](https://github.com/farion1231/cc-switch) Tauri app's SQLite database and auto-generates cc-viewer proxy profiles. Cross-platform path detection probes `~/.cc-switch/cc-switch.db` **first on every platform** (cc-switch hardcodes this path via `get_app_config_dir()` in its `config.rs` on mac/linux/windows; the Tauri identifier does not affect the DB path), with platform-specific Tauri app-data paths (`~/Library/Application Support/cc-switch/`, `%APPDATA%\cc-switch\`, `~/.local/share/cc-switch/`) kept only as low-priority legacy fallbacks so a stale leftover there can never shadow the real DB. Opens `cc-switch.db` in **read-only** mode (no SQLITE_BUSY lock when cc-switch is running), queries the `providers` table for `app_type='claude'` rows, and maps `settings_config.env` → cc-viewer profile fields (`ANTHROPIC_BASE_URL`→`baseURL`, `ANTHROPIC_AUTH_TOKEN`/`ANTHROPIC_API_KEY`→`apiKey`, `ANTHROPIC_MODEL` + the three family-model fields, ignoring the `_NAME` suffixed variants; `CLAUDE_CODE_EFFORT_LEVEL`→`effort` so a user's effort toggle is not silently dropped on import). Codex providers are skipped (incompatible auth format). Imported profiles get a `ccs_` id prefix and `source: 'cc-switch'` marker; a `mergeImportedProfiles` pure function updates existing `ccs_` entries (credential refresh) and appends new ones while **leaving user-created `proxy_` profiles untouched** — deleted-from-cc-switch entries are pruned. New `server/lib/ccswitch-import.js` (pure functions, fully unit-tested against the real db); `GET /api/ccswitch-providers` (preview, masked off-host) + `POST /api/ccswitch-import` (local-only merge + SSE `proxy_profile` broadcast); a "从 cc-switch 导入" button in ProxyModal. 4 new `ui.proxy.ccswitch*` i18n keys × 18 locales; `test/ccswitch-import.test.js` (25 cases incl. live-db integration + cross-platform path-priority injection).
15
15
- fix(cc-switch-import): **the import reported a misleading `providers table not found`** whenever the DB was unreadable. The `sqlite_master` existence query's inner `catch {}` swallowed the real error (e.g. `file is not a database` for a corrupt/non-SQLite `cc-switch.db`) and collapsed every failure into the generic message, so the user could not tell a corrupt file from a genuine schema mismatch. The catch is removed — a throw now propagates to the existing outer catch, which surfaces `query failed: <real message>`; the genuine table-missing case reports `providers table not found in <resolved path>` (naming the file so a stale leftover at a probed path is distinguishable from the real cc-switch DB). Tests: a non-SQLite file asserts the error is *not* the masked string and exposes the real cause; a valid-but-tableless DB asserts the distinct `providers table not found in <path>` message.
16
16
- fix(cc-switch-import): **five P1 findings from a 6-role review adopted.** (1) A corrupt/unparseable existing `profile.json` no longer wipes user-created proxies: the import previously swallowed the parse error, merged into an empty base, and overwrote the file with only `ccs_` entries — it now ABORTS with `ok:false` (`reportSwallowed('ccswitch-import.read-existing')`), and a parse to a non-object shape aborts the same way; the on-disk file is left byte-identical. (2) The client no longer misreports 403/400 as success: those response shapes carry no `imported`/`updated` counters, so the old `data.imported === 0` heuristic fell through to the green "Imported 0, updated 0" toast — success is now decided strictly on `resp.ok && data.ok === true`, and every server error path (403 gate, 400 exception) carries `ok:false`. (3) `mergeImportedProfiles` now upholds the same `max`-invariant as `proxyProfilesPost`: the built-in Default is seeded at the front when missing (a fresh install importing before ever saving a proxy used to write a list with no Default option), and existing id-less entries are preserved instead of silently dropped. (4) The Node floor mismatch is surfaced instead of silent: `node:sqlite` needs Node ≥ 22.5 (`--experimental-sqlite`) / ≥ 23.4 unflagged while the project floor is 20.14 — the unavailable-runtime error now names the requirement and ProxyModal maps it to a dedicated localized message (`ui.proxy.ccswitchNodeUnsupported` × 18 locales) instead of the misleading "cc-switch not detected"; the degradation contract is pinned by a test via the new `_setDatabaseSyncForTest` hook (CI runs Node 24, so the sqlite suites are exercised there). (5) The two HTTP endpoints — previously untested — get route coverage in `test/api-ccswitch-import.test.js` (fixture SQLite db under an injected HOME, no real cc-switch needed): local-only 403 gate writes nothing, `ok:false` contract on 400, first-import max seeding + `0o600` + credential-free SSE `refresh` broadcast, re-import preserve/prune semantics, corrupt/non-object `profile.json` abort leaves the file untouched, and off-host GET masking never leaks the plaintext key.
17
+
- ui(cc-switch-import): ProxyModal footer buttons are now side-by-side — "从 cc-switch 导入" on the left, "+ 添加代理" on the right (each half-width) instead of stacked full-width rows; the explanatory hint line under the import button is removed together with its now-unused `ui.proxy.ccswitchImportHint` i18n key (×18 locales).
17
18
- fix(cc-switch-import): **a stale/empty leftover `cc-switch.db` at a platform-specific probe path could shadow the real DB**. `candidateDbPaths()` probed `~/Library/Application Support/cc-switch/`, `%APPDATA%\cc-switch\`, and `~/.local/share/cc-switch/`*before*`~/.cc-switch/cc-switch.db`, but cc-switch never writes to those Tauri app-data paths — a leftover file there was matched first and yielded `providers table not found`. `~/.cc-switch/cc-switch.db` is now the primary probe on all platforms; the platform paths are demoted to legacy fallbacks. `candidateDbPaths()` was refactored to accept an injectable `{plat, home, env}` and exported as `_candidateDbPathsForTest` so the win32/darwin priority ordering is exercised on any test host (previously zero coverage on non-linux branches); new cross-platform tests assert the primary path wins and a stale legacy file cannot shadow it, using a neutral home value (no hardcoded username).
Copy file name to clipboardExpand all lines: src/i18n.js
-1Lines changed: 0 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -11517,7 +11517,6 @@ const i18nData = {
11517
11517
"uk": "Додати проксі"
11518
11518
},
11519
11519
"ui.proxy.ccswitchImport": { "zh": "从 cc-switch 导入", "en": "Import from cc-switch", "zh-TW": "從 cc-switch 匯入", "ko": "cc-switch에서 가져오기", "ja": "cc-switchからインポート", "de": "Von cc-switch importieren", "es": "Importar de cc-switch", "fr": "Importer depuis cc-switch", "it": "Importa da cc-switch", "da": "Importér fra cc-switch", "pl": "Importuj z cc-switch", "ru": "Импорт из cc-switch", "ar": "استيراد من cc-switch", "no": "Importer fra cc-switch", "pt-BR": "Importar do cc-switch", "th": "นำเข้าจาก cc-switch", "tr": "cc-switch'ten içe aktar", "uk": "Імпорт із cc-switch" },
11520
-
"ui.proxy.ccswitchImportHint": { "zh": "读取本地 cc-switch 的供应商配置,自动生成代理选项(仅 Claude 类型,用户自建代理不受影响)", "en": "Reads local cc-switch providers and generates proxy options (Claude type only; user-created proxies are preserved)", "zh-TW": "讀取本地 cc-switch 的供應商設定,自動產生代理選項(僅 Claude 類型,使用者自建代理不受影響)", "ko": "로컬 cc-switch 공급자를 읽어 프록시 옵션을 생성합니다 (Claude 타입만, 사용자가 만든 프록시는 유지됨)", "ja": "ローカルの cc-switch プロバイダを読み取りプロキシオプションを生成します (Claude 型のみ、ユーザー作成プロキシは保持)", "de": "Liest lokale cc-switch-Anbieter und erstellt Proxy-Optionen (nur Claude-Typ, benutzerdefinierte Proxys bleiben erhalten)", "es": "Lee los proveedores locales de cc-switch y genera opciones de proxy (solo tipo Claude, los proxies del usuario se conservan)", "fr": "Lit les fournisseurs locaux cc-switch et génère des options de proxy (type Claude uniquement, les proxies utilisateur sont conservés)", "it": "Legge i provider locali di cc-switch e genera opzioni proxy (solo tipo Claude, i proxy dell'utente sono conservati)", "da": "Læser lokale cc-switch-udbydere og genererer proxy-indstillinger (kun Claude-type, brugeroprettede proxys bevares)", "pl": "Odczytuje lokalnych dostawców cc-switch i generuje opcje proxy (tylko typ Claude, proxy użytkownika są zachowane)", "ru": "Читает локальных провайдеров cc-switch и создаёт опции прокси (только тип Claude, пользовательские прокси сохраняются)", "ar": "يقرأ مزودي cc-switch المحليين وينشئ خيارات الوكيل (نوع Claude فقط، يتم الاحتفاظ بوكيلات المستخدم)", "no": "Leser lokale cc-switch-leverandører og genererer proxy-alternativer (kun Claude-type, brukeropprettede proxyer bevares)", "pt-BR": "Lê provedores locais do cc-switch e gera opções de proxy (apenas tipo Claude, proxies do usuário são preservados)", "th": "อ่านผู้ให้บริการ cc-switch ในเครื่องและสร้างตัวเลือกพร็อกซี (ประเภท Claude เท่านั้น พร็อกซีที่ผู้ใช้สร้างจะถูกคงไว้)", "tr": "Yerel cc-switch sağlayıcılarını okur ve proxy seçenekleri oluşturur (yalnızca Claude türü, kullanıcı tarafından oluşturulan proxy'ler korunur)", "uk": "Читає локальних провайдерів cc-switch і створює опції проксі (лише тип Claude, проксі користувача зберігаються)" },
"ui.proxy.ccswitchNodeUnsupported": { "zh": "导入不可用:当前 Node.js 缺少内置 SQLite 模块(需 Node ≥ 23.4,或 22.5+ 并加 --experimental-sqlite)", "en": "Import unavailable: this Node.js runtime lacks the built-in SQLite module (requires Node ≥ 23.4, or 22.5+ with --experimental-sqlite)", "zh-TW": "匯入不可用:目前 Node.js 缺少內建 SQLite 模組(需 Node ≥ 23.4,或 22.5+ 並加 --experimental-sqlite)", "ko": "가져오기를 사용할 수 없음: 현재 Node.js 런타임에 내장 SQLite 모듈이 없습니다 (Node ≥ 23.4 필요, 또는 22.5+ 및 --experimental-sqlite)", "ja": "インポート不可: この Node.js ランタイムには組み込み SQLite モジュールがありません (Node ≥ 23.4、または 22.5+ と --experimental-sqlite が必要)", "de": "Import nicht verfügbar: dieser Node.js-Laufzeit fehlt das eingebaute SQLite-Modul (erfordert Node ≥ 23.4 oder 22.5+ mit --experimental-sqlite)", "es": "Importación no disponible: este entorno de Node.js carece del módulo SQLite integrado (requiere Node ≥ 23.4, o 22.5+ con --experimental-sqlite)", "fr": "Importation indisponible : ce runtime Node.js ne dispose pas du module SQLite intégré (nécessite Node ≥ 23.4, ou 22.5+ avec --experimental-sqlite)", "it": "Importazione non disponibile: questo runtime Node.js non ha il modulo SQLite integrato (richiede Node ≥ 23.4, o 22.5+ con --experimental-sqlite)", "da": "Import utilgængelig: denne Node.js-runtime mangler det indbyggede SQLite-modul (kræver Node ≥ 23.4, eller 22.5+ med --experimental-sqlite)", "pl": "Import niedostępny: to środowisko Node.js nie ma wbudowanego modułu SQLite (wymaga Node ≥ 23.4 lub 22.5+ z --experimental-sqlite)", "ru": "Импорт недоступен: в этой среде Node.js нет встроенного модуля SQLite (требуется Node ≥ 23.4 или 22.5+ с --experimental-sqlite)", "ar": "الاستيراد غير متاح: بيئة Node.js هذه تفتقر إلى وحدة SQLite المدمجة (يتطلب Node ≥ 23.4، أو 22.5+ مع --experimental-sqlite)", "no": "Import utilgjengelig: denne Node.js-kjøretiden mangler den innebygde SQLite-modulen (krever Node ≥ 23.4, eller 22.5+ med --experimental-sqlite)", "pt-BR": "Importação indisponível: este runtime Node.js não possui o módulo SQLite integrado (requer Node ≥ 23.4, ou 22.5+ com --experimental-sqlite)", "th": "นำเข้าไม่ได้: รันไทม์ Node.js นี้ไม่มีโมดูล SQLite ในตัว (ต้องใช้ Node ≥ 23.4 หรือ 22.5+ พร้อม --experimental-sqlite)", "tr": "İçe aktarma kullanılamıyor: bu Node.js çalışma zamanında yerleşik SQLite modülü yok (Node ≥ 23.4 veya --experimental-sqlite ile 22.5+ gerekir)", "uk": "Імпорт недоступний: у цьому середовищі Node.js немає вбудованого модуля SQLite (потрібен Node ≥ 23.4 або 22.5+ з --experimental-sqlite)" },
11523
11522
"ui.proxy.ccswitchImportFail": { "zh": "导入失败(未检测到 cc-switch 或读取出错)", "en": "Import failed (cc-switch not detected or read error)", "zh-TW": "匯入失敗(未偵測到 cc-switch 或讀取錯誤)", "ko": "가져오기 실패 (cc-switch를 감지하지 못했거나 읽기 오류)", "ja": "インポート失敗 (cc-switchが検出されないか読み取りエラー)", "de": "Import fehlgeschlagen (cc-switch nicht erkannt oder Lesefehler)", "es": "Importación fallida (cc-switch no detectado o error de lectura)", "fr": "Échec de l'importation (cc-switch non détecté ou erreur de lecture)", "it": "Importazione fallita (cc-switch non rilevato o errore di lettura)", "da": "Import mislykkedes (cc-switch ikke fundet eller læsefejl)", "pl": "Import nieudany (nie wykryto cc-switch lub błąd odczytu)", "ru": "Ошибка импорта (cc-switch не обнаружен или ошибка чтения)", "ar": "فشل الاستيراد (لم يتم اكتشاف cc-switch أو خطأ في القراءة)", "no": "Import mislyktes (cc-switch ikke funnet eller lesefeil)", "pt-BR": "Falha na importação (cc-switch não detectado ou erro de leitura)", "th": "นำเข้าล้มเหลว (ไม่พบ cc-switch หรือข้อผิดพลาดในการอ่าน)", "tr": "İçe aktarma başarısız (cc-switch algılanamadı veya okuma hatası)", "uk": "Помилка імпорту (cc-switch не виявлено або помилка читання)" },
0 commit comments