feat: Implement Prompt Builder functionality in Popup and Options
Some checks failed
CI — Test & Build / Test & Build (push) Failing after 39s
Some checks failed
CI — Test & Build / Test & Build (push) Failing after 39s
- 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.
This commit is contained in:
78
docs/DECISIONS.md
Normal file
78
docs/DECISIONS.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Decisions — LexAI
|
||||
|
||||
> Lightweight ADRs. One entry per material decision: what, why, what was rejected, when. Newest at top. Supersede rather than rewrite.
|
||||
|
||||
## Log
|
||||
|
||||
### D-2026-03-06-01 — BYO-LLM-key, no backend
|
||||
|
||||
- **Status:** accepted
|
||||
- **Context:** Hosted writing assistants cost a subscription and route user text through a third party. Target users already hold LLM API keys.
|
||||
- **Decision:** No LexAI server. The background service worker calls the user's chosen provider (OpenAI/Anthropic/Groq/OpenRouter) directly with the user's key.
|
||||
- **Alternatives considered:** A thin proxy backend (rejected: adds cost, privacy surface, and an account system); on-device browser AI only (rejected: too limited across providers — noted as a Proofly reference pattern).
|
||||
- **Consequences:** Zero server cost and strong privacy story; shifts key handling and CORS entirely into the extension; no server-side rate limiting or abuse controls.
|
||||
- **Verification:** Manual — confirm no network calls leave the extension except to the selected provider endpoint.
|
||||
- **Owner / date:** Phase 1, 2026-03-06
|
||||
|
||||
### D-2026-03-06-02 — Inline styles, no Tailwind
|
||||
|
||||
- **Status:** accepted
|
||||
- **Context:** Content-script UI must not be broken by host-page CSS; WXT PostCSS/Tailwind integration was not wired.
|
||||
- **Decision:** Style all UI with inline style objects (`Object.assign(el.style, …)` / `style={{…}}`), using a dark Catppuccin-ish palette.
|
||||
- **Alternatives considered:** Tailwind (left in devDependencies but inactive); shadow DOM + stylesheet (deferred — see D-...-03).
|
||||
- **Consequences:** Reliable rendering on any host page; palette/button styles get duplicated across content/Options/Popup (refactor tracked in TASKS #5).
|
||||
- **Verification:** Visual check on multiple sites.
|
||||
- **Owner / date:** Phase 1, 2026-03-06
|
||||
|
||||
### D-2026-03-06-03 — No shadow DOM; `data-lexai` guard instead
|
||||
|
||||
- **Status:** accepted
|
||||
- **Context:** Injected toolbar/modal could collide with host-page styles or re-trigger LexAI's own handlers.
|
||||
- **Decision:** Inject directly into `document.body`; mark every LexAI node `data-lexai="true"` and skip events whose target is `closest('[data-lexai="true"]')`; use max `z-index` (2147483647).
|
||||
- **Alternatives considered:** Shadow DOM (rejected for now: added complexity; revisit if style isolation issues appear).
|
||||
- **Consequences:** Simple and working; weaker isolation than shadow DOM; highly customized editors (e.g. Google Docs) may not accept programmatic replace.
|
||||
- **Verification:** Manual across textarea/input/contenteditable sites.
|
||||
- **Owner / date:** Phase 1, 2026-03-06
|
||||
|
||||
### D-2026-03-06-04 — Eager selection snapshot before async
|
||||
|
||||
- **Status:** accepted
|
||||
- **Context:** Focus shifts to the toolbar and the live selection is gone by the time an async provider response returns.
|
||||
- **Decision:** Capture the active element + selection offsets eagerly (on `mouseup` and on button `mousedown`) and snapshot before any `await`; Replace uses the snapshot. Handle both textarea/input (`selectionStart/End`) and contenteditable/DOM (`Range` API).
|
||||
- **Alternatives considered:** Re-reading selection after the response (rejected: selection no longer exists).
|
||||
- **Consequences:** Replace works reliably; the pattern is fragile — editing content.ts must preserve snapshot-before-await. Zero automated coverage today (TASKS #10).
|
||||
- **Owner / date:** Phase 1, 2026-03-06
|
||||
|
||||
### D-2026-03-06-05 — Dual `ANALYZE_TEXT` message shapes; `return true` listener
|
||||
|
||||
- **Status:** accepted
|
||||
- **Context:** Content script/popup send `{ payload: {...} }`; other call sites send flat `{ text, action, style }`. Async responses need the message channel held open.
|
||||
- **Decision:** The handler accepts both shapes; the `onMessage` listener returns `true`. `fix` normalizes to `grammar`.
|
||||
- **Consequences:** Flexible but must be preserved in both forms; removing `return true` silently breaks all responses.
|
||||
- **Owner / date:** Phase 1, 2026-03-06
|
||||
|
||||
### D-2026-xx-xx-06 — tweetnacl secretbox for the API key (obfuscation, not protection)
|
||||
|
||||
- **Status:** accepted — flagged for revisit
|
||||
- **Context:** Storing the raw key in `chrome.storage.local` looked bad; added tweetnacl `secretbox` encryption (`apiKeyEnc` + `encKey`).
|
||||
- **Decision:** Prefer the encrypted path; keep plaintext `apiKey` as back-compat until a migration exists.
|
||||
- **Known weakness:** `encKey` is stored next to `apiKeyEnc`, so anyone who can read storage can decrypt. This is obfuscation, not protection (RECOMMENDATIONS #2).
|
||||
- **Alternatives to consider:** derive the key from `chrome.storage.session` / WebCrypto / a user passphrase; and be honest in the UI ("stored locally, obscured"). Tracked in TASKS #2.
|
||||
- **Owner / date:** post-Phase 1
|
||||
|
||||
### D-2026-03-06-07 — Gitea CI + Chrome Web Store deploy
|
||||
|
||||
- **Status:** accepted
|
||||
- **Context:** Project hosts CI on Gitea, not GitHub Actions.
|
||||
- **Decision:** `.gitea/workflows/ci.yml` (typecheck→test→build→zip to registry) and `deploy-chrome.yml` (on `v*.*.*` tag → CWS). Telegram notifications. Version must match in `package.json` and `wxt.config.ts`.
|
||||
- **Known weakness:** workflows `git clone` into `/tmp` and set `http.sslVerify false` (RECOMMENDATIONS #17). Revisit for speed/security.
|
||||
- **Owner / date:** Phase 1, 2026-03-06
|
||||
|
||||
## Open / proposed
|
||||
|
||||
### D-PROPOSED — Narrow host permissions from `<all_urls>`
|
||||
|
||||
- **Status:** proposed (decide before serious Web Store push)
|
||||
- **Context:** Content script injects into every frame of every site, including banking/email/internal apps; also the #1 CWS review slowdown (RECOMMENDATIONS #1).
|
||||
- **Options:** `activeTab` + on-demand injection, or a user-configurable allowlist.
|
||||
- **Verification:** confirm actions still work after narrowing; measure review outcome.
|
||||
Reference in New Issue
Block a user