feat: add LexAI status bar and suggestion panel
Some checks failed
CI — Test & Build / Test & Build (push) Has been cancelled

- Implemented a status bar item for LexAI with dynamic status updates (ready, processing, notReady).
- Created a suggestion panel for displaying and interacting with AI-generated suggestions.
- Added functionality for accepting, regenerating, and discarding suggestions within the suggestion zone.
- Introduced configuration options for writing style, prompt patterns, personas, and formats.
- Integrated progress indicators for long-running tasks and improved user feedback.
- Established TypeScript configuration for the vscode package.
This commit is contained in:
john kevin asprec
2026-08-13 18:06:45 +08:00
parent fc19ead0a7
commit 8bc529ef2d
84 changed files with 10025 additions and 662 deletions

View File

@@ -1,72 +1,62 @@
# Architecture — LexAI
# Architecture
> The current system and its important boundaries. Update in the same change that alters behavior; log the reason in `DECISIONS.md`.
> The current system and its important boundaries. Describe what *is*, not aspirations.
## System at a glance
- **Shape:** Browser extension (Chrome, Manifest V3) with three cooperating contexts message-passed over `chrome.runtime`. No backend.
- **Stack:** WXT `^0.20` (wraps Vite), React 18 + TypeScript (Options/Popup pages only), tweetnacl/tweetnacl-util for key encryption, Zustand installed but unused.
- **Data stores:** `chrome.storage.local` (provider, model, `apiKeyEnc`, `encKey`, legacy plaintext `apiKey`). No server, no DB.
- **Hosting / deploy:** Chrome Web Store. Build output `.output/chrome-mv3/`.
- **Build / release:** Gitea CI (`.gitea/workflows/`)typecheck → test → build → zip to Gitea registry; `v*.*.*` tag → Chrome Web Store deploy.
- **Shape:** dual client surfaces (Chrome MV3 extension + VS Code extension) sharing portable LLM core; no LexAI backend
- **Stack:** TypeScript; Chrome via WXT ^0.20 + React 18; VS Code via `packages/vscode` (esbuild bundle); Node 22
- **Data stores:** Chrome `chrome.storage.local` (encrypted key + prefs); VS Code Secret Storage (API key) + `lexai.*` settings
- **Hosting / deploy target:** Chrome Web Store (Gitea CI); VS Code Marketplace not wired yet (local VSIX / extension host)
- **Build / release:** Chrome `npm run build``.output/chrome-mv3/`; VS Code `npm run vscode:build``packages/vscode/out/extension.js`
## Component map
```text
entrypoints/content.ts (content script, injected into <all_urls>)
• Detects selection: textarea/input (selectionStart/End) vs contenteditable/DOM (Range API)
• Renders floating toolbar + result modal + toasts (inline-styled, appended to document.body)
• Snapshots selection state BEFORE any async call; Replace uses the snapshot
• Sends { type: 'ANALYZE_TEXT', payload: {text, action, style} } to background
shared: src/lib/{providers,actions,types} (+ crypto/messaging Chrome-only)
entrypoints/background.ts (service worker — the LLM proxy)
• onMessage: ANALYZE_TEXT and COPY_AS (returns true to keep async channel open)
• Reads provider/apiKey/apiKeyEnc/encKey/model from chrome.storage.local
• Decrypts key (tweetnacl secretbox), routes to the correct provider fetch
• Registers right-click context menus (action × style) on install
Chrome:
content.ts ──ANALYZE_TEXT──> background.ts ──fetch──> provider API
options/popup (React) ──storage──> chrome.storage.local
entrypoints/options/Options.tsx (React settings page)
• Provider + model + API key form; encrypts key → apiKeyEnc/encKey in storage
entrypoints/popup/Popup.tsx (React toolbar popup)
• Standalone text box → same ANALYZE_TEXT flow; shows config status; links to Options
VS Code:
extension.ts (commands/menus) ──callProvider──> provider API
│ ▲
└── secrets / settings ────────┘
```
| Component | Responsibility | Owns (paths) | Talks to | Notes |
| --- | --- | --- | --- | --- |
| content script | selection, toolbar/modal UI, replace | `entrypoints/content.ts` | background via messages | DOM-timing-sensitive; snapshot before await |
| background SW | LLM proxy, key decrypt, routing, context menus | `entrypoints/background.ts` | provider APIs, storage | only context allowed to fetch providers |
| options page | provider/model/key config + encrypt | `entrypoints/options/Options.tsx` | storage | React |
| popup | standalone analyze + status | `entrypoints/popup/Popup.tsx` | background via messages | React |
| shared utils | reference notes, future shared code | `src/utils/**` | — | see REFERENCE_NOTES.md |
| Shared core | Actions, prompts, provider adapters | `src/lib/providers.ts`, `actions.ts`, `types.ts` | Provider HTTPS APIs | No Chrome/VS Code imports |
| Chrome content | Selection, toolbar/modal, replace | `entrypoints/content.ts` | Background via messaging | DOM timing; `data-lexai` |
| Chrome background | Decrypt key, call providers, menus | `entrypoints/background.ts` | `chrome.storage`, providers | CORS + key isolation |
| Chrome Options/Popup | Settings + standalone analyze | `entrypoints/options`, `popup` | Storage + background | React; inline styles |
| VS Code extension | Commands, context menu, replace | `packages/vscode/src/**` | SecretStorage, settings, providers | Bundles `@lib` via esbuild |
| Chrome crypto/messaging | tweetnacl key path; safe chrome wrappers | `src/lib/crypto.ts`, `messaging.ts` | `chrome.*` | Not used by VS Code |
## Boundaries and contracts
- **CORS/key boundary:** Content script and popup **must not** call provider APIs. All provider `fetch` and key handling live in `background.ts`. Route through `ANALYZE_TEXT` / `COPY_AS`.
- **Message contract:**
- `ANALYZE_TEXT` accepts **both** `{ payload: {text, action, style} }` and flat `{ text, action, style }` — keep both if you touch the handler.
- `action``grammar | rephrase | shorten | expand | explain`. Context menu/popup emit `fix`, normalized to `grammar` by `getSystemPrompt`.
- The `onMessage` listener **must `return true`** to keep the async channel open; removing it silently breaks every response.
- **Provider layer:** Each provider is duplicated — `callX` (system prompt from action) and `callXWithPrompt` (arbitrary prompt, used by COPY_AS). Request-shape changes usually need both. (Known smell — see DECISIONS + TASKS.)
- **DOM guard:** Every injected node carries `data-lexai="true"`; handlers check `closest('[data-lexai="true"]')` to avoid self-triggering. `z-index: 2147483647` keeps UI above host pages.
- **Trust boundaries:** page DOM (Chrome) and editor buffer (VS Code) are untrusted text; API key never logged; only users chosen provider receives text/key
- **Message contract (Chrome):** `ANALYZE_TEXT` (payload + flat), `COPY_AS`, `LIST_MODELS` — see `src/lib/types.ts`
- **VS Code commands:** `lexai.{fix,rephrase,shorten,expand,explain,prompt,setApiKey,clearApiKey,showStatus}`
- **Internal imports:** VS Code may import `@lib/providers|actions|types` only — not `crypto` / `messaging`
- **External dependencies:** OpenAI, Anthropic, Groq, OpenRouter chat + models endpoints
## Data model (essentials)
- **Storage keys:** `provider`, `model`, `apiKeyEnc`, `encKey`, `apiKey` (legacy plaintext, back-compat only).
- **Sensitive data:** the LLM API key. Prefer the encrypted path; never log it; never transmit except to the user's selected provider. Don't drop the plaintext fallback without a migration.
- **Config:** provider, model, writing style, keyProvider
- **Sensitive:** API key — Chrome encrypted blob + encKey; VS Code Secret Storage
- **Legacy:** Chrome plaintext `apiKey` fallback until migrated
## Cross-cutting concerns
- **Config/secrets:** provider list + default models + endpoints currently duplicated across `Options.tsx` and `background.ts` (drift risk — see TASKS).
- **Observability:** intentional `[LexAI …]` console logs in content.ts replace path (should be gated behind a DEV flag — see TASKS).
- **Testing:** Vitest (jsdom) unit + Playwright e2e. Unit tests currently exercise the `chrome.storage` mock rather than importing real handlers; e2e has `[EXTENSION_ID]` placeholders and won't pass as-is (see TASKS/EVALS).
- **Authn/z:** none (BYO key)
- **Observability:** console debug in Chrome replace path (pre-release); VS Code notifications
- **Feature flags:** none
- **Config:** Chrome storage schema; VS Code `contributes.configuration` `lexai.*`
## Known constraints and debt
## Open architectural risks
- Tailwind inactive; all UI is inline style objects (WXT PostCSS never wired). Do not assume Tailwind classes work.
- No shadow DOM; UI injected directly into `document.body`, isolated only by `data-lexai` + max z-index.
- Version bump is a manual two-file edit (`package.json` + `wxt.config.ts`).
---
*Record non-obvious choices in `DECISIONS.md`; keep exposure current in `attacksurface.md`.*
- Chrome and VS Code settings are not synced
- VS Code v1 has no Prompt Builder / Copy As / floating toolbar
- Relocating Chrome into `packages/chrome` deferred — root remains the WXT app