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
fix(cc-switch-import): adopt five P1 findings from multi-role review
- Corrupt/unparseable profile.json now ABORTS the import (ok:false +
reportSwallowed) instead of merging into an empty base and wiping
user-created proxy_ profiles; non-object JSON shapes abort the same way.
- Client success is decided strictly on resp.ok && data.ok === true; the
403 local-only gate and 400 exception paths now carry ok:false, so they
can no longer render as a green "Imported 0, updated 0" toast.
- mergeImportedProfiles seeds the built-in max profile at the front when
missing (mirrors proxyProfilesPost's invariant; a fresh install importing
first no longer loses the Default option) and preserves id-less entries.
- The node:sqlite-unavailable error now names the real requirement
(Node >= 22.5 with --experimental-sqlite, or >= 23.4) and ProxyModal maps
it to a dedicated localized message ui.proxy.ccswitchNodeUnsupported
(x18 locales); degradation contract pinned via _setDatabaseSyncForTest.
- New test/api-ccswitch-import.test.js covers the previously-untested HTTP
surface with a fixture SQLite db: 403 gate writes nothing, ok:false
contract, first-import max seeding + 0o600 + credential-free SSE refresh
broadcast, preserve/prune merge semantics, corrupt-file abort leaves the
file byte-identical, off-host GET masking never leaks the plaintext key.
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
@@ -4,6 +4,7 @@
4
4
5
5
- 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).
6
6
- 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.
7
+
- 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.
7
8
- 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).
0 commit comments