A stored key carried no record of which provider it belonged to. Options
saves {provider, model} without the key whenever the field is blank (which
it always is after a save, since it shows the encrypted badge instead), so
switching provider left the previous provider's key attached to the new one.
Every call then failed with that provider's own "Invalid API Key" while the
UI still showed a key as configured.
- types.ts: new `keyProvider` storage field, added to CONFIG_STORAGE_KEYS
- background.ts: keyProviderMismatch() guards the chat, COPY_AS and
stored-key LIST_MODELS paths; absent keyProvider (pre-upgrade) is allowed
- Options.tsx: stamps keyProvider on every save; drops the encrypted badge
and requires a new key when the saved one belongs to another provider or
is rejected; save-time guard messages are now actually rendered (they were
gated on modelsStatus === 'error' and never drew, so Save looked dead)
- providers.ts: providerLabel(); settings hint appended to 401/403 only;
listModels reports keyRejected and labels errors with the display name
- Anthropic: send anthropic-dangerous-direct-browser-access on the chat path
Docs: CLAUDE.md version-bump rule corrected — wxt.config.ts reads
pkg.version, so package.json is the only place to edit.
typecheck clean, 58/58 tests, build clean (281.72 kB, manifest 1.0.2).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Added a new "Prompt Builder" tab in the Popup for generating AI prompts with customizable parameters.
- Introduced new state variables for managing prompt styles, personas, formats, and models.
- Enhanced the Options page to fetch and display models based on the provided API key.
- Updated the actions and types to include the new 'prompt' action and its associated parameters.
- Implemented migration logic for legacy plaintext API keys to encrypted storage.
- Updated the getSystemPrompt function to incorporate prompt parameters for better instruction generation.
- Added tests for the new functionality, including context menu entries and prompt generation logic.
Encrypt (Options) and decrypt (background) now share one module; wire
format unchanged. Tests include fixtures proving values encrypted by the
old inline Options code still decrypt, plus tamper/wrong-key cases. The
module documents the honest threat model (key co-located with ciphertext
= obfuscation, not encryption).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- src/lib/types.ts: message contract (both ANALYZE_TEXT shapes preserved),
config/response types, storage-key constants.
- src/lib/messaging.ts: single safeStorageGet/safeStorageSet/safeSendMessage/
isExtensionValid implementation replacing the three divergent copies in
Options, Popup, and content. Content script keeps its refresh-toast
behavior via an onContextInvalidated callback.
- New '@lib' import alias (wxt force-overwrites '~' and '@' to srcDir, so
those cannot point at ./src); wired in wxt.config, tsconfig, vitest.
- tests/unit/messaging.test.ts: 14 unit tests over the wrappers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Uninstall zustand, tailwindcss, autoprefixer, tweetnacl-util (all
unused); README no longer advertises Tailwind/Zustand.
- Fix stale 'Tone' -> 'Explain' copy in Options.
- Add .nvmrc/engines/packageManager (Node 22 to match CI).
- wxt.config.ts reads manifest version from package.json so the two
can never drift.
- Ignore *.zip build artifacts.
- Skip the two e2e specs with literal [EXTENSION_ID] placeholders
(cannot pass; TODO references the e2e-ID-resolution task).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- LEXAI-13: TweetNaCl secretbox encryption for API keys in Options + background
- getOrCreateEncKey() generates per-device 32-byte key stored in chrome.storage.local
- Keys saved as nonce+ciphertext (base64) under apiKeyEnc
- Backward compat: falls back to plaintext apiKey if no encrypted key found
- Lock icon 🔒 shown in Options label when key is encrypted
- LEXAI-11: Right-click context menu with Fix, Rephrase, Shorten, Expand, Tone
- Registered via onInstalled in background service worker
- Sends lexai-context-menu message to content script
- Content script listener added at bottom of main()
- LEXAI-12: Tone analysis button added to floating toolbar (teal #2dd4bf)
- Analysis-only: showModal called with null originalText = no Replace button
- Tone system prompt updated to pure analysis (no rewrite)