feat: implement API key resolution and live model listing for providers
All checks were successful
CI — Test & Build / Test & Build (push) Successful in 59s

This commit is contained in:
john kevin asprec
2026-07-13 13:56:48 +08:00
parent 50df1b5d93
commit f7fcd41341
5 changed files with 467 additions and 35 deletions

81
RECOMMENDATIONS.md Normal file
View File

@@ -0,0 +1,81 @@
# LexAI — Improvement Recommendations
Prioritized findings from a full read of the codebase (2026-07-13). Grouped by theme;
each item notes rough effort (S/M/L) and why it matters.
## 🔒 Security & privacy
1. **Narrow host permissions (M).** The manifest requests `<all_urls>` host permission and
injects the content script into every frame of every site — including banking, email, and
internal apps. Consider `activeTab` + on-demand injection, or a user-configurable
allowlist. This is also the #1 thing that slows Chrome Web Store review.
2. **The encryption is obfuscation, not protection (M).** `encKey` sits in
`chrome.storage.local` right next to `apiKeyEnc`; anyone who can read storage can decrypt.
Be honest in the UI ("stored locally, obscured") or derive the key from something not
co-located (e.g. `chrome.storage.session` for the key, WebCrypto, or a passphrase). At
minimum, don't over-promise "encrypted" security to users.
3. **Strip debug logging from production (S).** `content.ts` logs selection text and element
values (`[LexAI captureForButton]`, `[LexAI Replace]`, etc.) to the page console — visible
to the host page. Gate behind a `__DEV__`/`import.meta.env.DEV` flag.
## 🧹 Code quality & maintainability
4. **Collapse the duplicated provider layer (M).** Each provider exists twice —
`callOpenAI`/`callOpenAIWithPrompt`, etc. — 8 near-identical functions. Refactor to one
`callProvider(config, messages | systemPrompt, text)` with a small per-provider adapter
describing `{ url, headers(config), body(model, system, text), extract(data) }`. Cuts
`background.ts` roughly in half and removes the "update both copies" trap noted in CLAUDE.md.
5. **Extract shared UI/styling (M).** The Catppuccin palette and button styles are re-declared
inline across content.ts, Options.tsx, Popup.tsx. Move colors/spacing into a shared
`src/ui/theme.ts` (and reusable style factories) so a palette change is one edit.
6. **Remove dead dependencies (S).** `zustand` is installed but no store exists; `tailwindcss`
+ `autoprefixer` are present but inactive. Either wire them up or drop them to shrink the
install and remove confusion.
7. **Centralize provider/model config (S).** The provider list, default models, and endpoints
live in both `Options.tsx` (UI) and `background.ts` (calls). Put them in one shared module
so the picker and the caller can't drift.
## ✅ Testing (biggest gap)
8. **Unit tests don't test real code (M).** `tests/unit/background.test.ts` only exercises the
`chrome.storage` mock — it never imports `getSystemPrompt`, `decryptApiKey`, or the provider
router. Extract those pure functions and test them directly (prompt normalization,
`fix``grammar`, encrypt→decrypt round-trip, provider routing, error extraction).
9. **Fix or quarantine the e2e tests (S).** `tests/e2e/extension.test.ts` hard-codes
`chrome-extension://[EXTENSION_ID]/...` — it cannot pass. Resolve the extension ID at
runtime (read it from the service-worker target) or mark the suite `.skip` until fixed so
CI green means something.
10. **Add a content-script DOM test (L).** The selection→snapshot→replace logic is the app's
riskiest code and has zero coverage. A jsdom or Playwright test over textarea and
contenteditable replace paths would catch regressions the current tests can't.
## ✨ Product / UX
11. **Make `max_tokens` adaptive (S).** It's hard-coded to `1024` everywhere; "Expand" on a
long paragraph will truncate mid-sentence. Scale with input length or expose it in settings.
12. **Add response streaming (L).** Non-streaming means the user stares at "thinking…" for the
full latency. Streaming tokens into the modal is the single biggest perceived-speed win.
13. **Accessibility (M).** Toolbar/modal buttons lack `aria-label`s, focus management, and
keyboard navigation; the modal doesn't trap focus. Add roles/labels and Esc/Tab handling
(Esc is partially handled already).
14. **React error boundaries + graceful storage failures (S).** Options/Popup call
`createRoot(...).render()` with no error boundary; a throw yields a blank page.
## 🚀 Build / release
15. **Pin the toolchain (S).** Add an `.nvmrc`/`engines` field for Node 22 to match CI, and a
`package.json` `packageManager` field. Local `npm run *` currently fails with no
`node_modules` and no version guard.
16. **Version bump is a two-file manual step (S).** `version` must be edited in both
`package.json` and `wxt.config.ts`. Add a script (or read one from the other) so a release
can't ship mismatched versions — this has already caused churn in the git history.
17. **CI clones instead of checking out (S).** Both Gitea workflows `git clone` the repo into
`/tmp` rather than using the checked-out workspace, and disable TLS verification
(`http.sslVerify false`). Worth revisiting for speed and security once the runner setup
allows a normal checkout.
## Suggested order
Quick wins first: **3, 6, 9, 11, 15, 16** (all S, mostly independent). Then the structural
refactors **4, 5, 8**, which make everything after them easier. Tackle **1/2** (permissions +
key story) before any serious Chrome Web Store push. Save **10, 12, 13** for a focused Phase 2.