1# Peach — Project Status23**Generated:** 2026-04-19 4**Version:** 1.0.4 5**Type:** Chrome Extension (Manifest V3)67---89## Build Status1011| Check | Status |12|-------|--------|13| TypeScript | ✅ Passing (`tsc --noEmit`) |14| Unit Tests | ✅ 6/6 passing (vitest) |15| Vite Build | ✅ Built (`dist/`) |16| Extension ID | `peach-browser` |1718---1920## Architecture2122```23src/24├── background/ Service worker (vault + message handling)25│ ├── entry.ts Entry point26│ ├── aes.ts Background-only AES helpers to avoid popup bundle leakage27│ ├── vault.ts Vault CRUD + crypto ops (in-memory key)28│ ├── messages.ts Message handler bridge29│ ├── clipboard.ts Auto-clear clipboard after 30s30│ └── alarms.ts Auto-lock after 15 min idle31├── content/ Injected into all pages32│ ├── index.ts Detects forms, injects 🍑 icon33│ ├── detect.ts Field detection (username/password)34│ ├── fill.ts Field filling via setNativeValue35│ ├── inject.ts Autofill selector UI (shadow DOM)36│ └── save.ts Detects form submits, prompts to save37├── popup/ Extension popup UI (Solid.js)38│ ├── App.tsx Root component, view router39│ ├── views/ Lock, Vault, Entry, Add, Settings, Import, Export, Generator40│ └── components/ TOTP, Ring, Pip, Generator41├── crypto/ Zero-knowledge crypto42│ ├── argon2.ts Key derivation (Argon2id via WASM)43│ ├── aes.ts AES-256-GCM encrypt/decrypt44│ ├── totp.ts TOTP generation (otpauth)45│ └── crypto.test.ts46└── shared/ Shared types, domain extraction, import parsers47```4849---5051## Feature Inventory5253### Vault Core54- [x] Create vault with master password (min 8 chars)55- [x] Unlock vault (Argon2id → AES-GCM)56- [x] Lock vault (zero key from memory)57- [x] Auto-lock on idle / alarm58- [x] Popup/background message timeout path for service worker unavailability59- [x] Reopen popup shows unlock or active vault instead of falling back to first-run create state60- [x] Detail-first PeachV2 popup shell with slide-in overlays for list, settings, new entry, and generator6162### Entry Management63- [x] Add entry (title, username, password, URL, notes, TOTP)64- [x] Edit entry65- [x] Soft delete entries (`deletedAt`) with filtered active views66- [x] Search/filter vault entries67- [x] Copy username / password (with visual/audio feedback)68- [x] Clipboard auto-clear after 30s69- [x] Stable `createdAt` / `modifiedAt` timestamps with legacy migration7071### Autofill (Content Script)72- [x] Inject 🍑 icon on detected password fields73- [x] Domain-filtered entry matching (eTLD+1)74- [x] Shadow DOM selector popup on icon click75- [x] Fill username + password on selection76- [x] Field visibility check before fill7778### Save Detection (Content Script)79- [x] Intercept form submits80- [x] Detect username + password fields81- [x] Show save/update banner (shadow DOM)82- [x] Create new entry or update existing8384### Import / Export85- [x] CSV import (PapaParse)86- [x] 1Password JSON import87- [x] Encrypted JSON export8889### Password Generator90- [x] Generate random passwords91- [x] Use in new entry flow9293### TOTP94- [x] Parse otpauth:// URIs95- [x] Display 30s countdown timer in entry view9697### UI / Visual System98- [x] Self-hosted popup fonts (`Cormorant Garamond`, `IBM Plex Mono`, `Inter`) in `public/fonts/`99- [x] Static pre-rendered lock screen HTML in popup entrypoint before Solid mounts100- [x] Archive-style chrome, ghost title, mono field rows, bottom search bar, and overlay list101102---103104## Crypto Implementation105106| Concern | Implementation |107|---------|----------------|108| Key derivation | Argon2id (hash-wasm) — 3 iterations, 64MB memory |109| Encryption | AES-256-GCM — fresh nonce per write |110| Auth tag | 128-bit GCM tag, stored alongside ciphertext |111| AAD | Version byte `0x01` prevents downgrade |112| Key zeroing | `Uint8Array.fill(0)` on lock |113114---115116## Test Status117118**TEST_CHECKLIST.md has 22 manual tests defined, 0 marked complete.**119120Recommended manual tests before daily driving:1211. Vault create/unlock/lock cycle1222. Entry CRUD + persistence across locks123 Includes popup close/reopen while the background may still be alive or already suspended1243. Autofill on github.com (domain filter, manual trigger, visible fill)1254. TOTP display and countdown1265. Password generator1276. Import CSV / Export encrypted backup1287. Clipboard auto-clear (30s wait)1298. Auto-lock on idle1309. Save credential detection on form submit13110. Wrong password → shake animation, clean error132133**Release blockers to verify before daily driving:**134- [ ] No wrong domain filled135- [ ] No silent autofill (icon click required)136- [ ] No fill into hidden fields137- [ ] Vault locks cleanly (key zeroed)138- [ ] Import/export round-trips correctly139- [ ] No console.log in crypto paths140141---142143## Known Gaps144145| Gap | Status |146|-----|--------|147| HIBP breach check | Defined in types (`breach` field) but not implemented |148| Backup restore test | Checked as release blocker, not automated |149| Unit tests for content script | None |150| Unit tests for vault CRUD | Basic create + soft-delete coverage added; broader CRUD coverage still missing |151| E2E / Playwright tests | Manual checklist still primary, but `test-extension.mjs` now exercises extension loading, vault creation, entry save, and popup reopen persistence |152153---154155## Dependencies156157| Package | Purpose |158|---------|---------|159| `hash-wasm` | Argon2id WASM implementation |160| `otpauth` | TOTP code generation |161| `papaparse` | CSV import |162| `tldts` | eTLD+1 domain extraction |163| `webextension-polyfill` | Cross-browser extension API |164| `solid-js` | Popup UI framework |165| `vite-plugin-solid` | Solid.js Vite integration |166| `@crxjs/vite-plugin` | CRX packaging for Vite |167| `vitest` | Unit testing |168169---170171## Security Considerations172173- Vault is stored encrypted in `chrome.storage.local`174- Master password never stored — derived key held in memory only while unlocked175- Service worker restart = vault locks (expected MV3 behavior)176- Background bundle is isolated from popup-only chunks so MV3 service worker startup no longer crashes on `document` access177- Popup boot now waits for `HAS_VAULT` / `IS_UNLOCKED` before choosing create vs unlock, preventing false first-run screens after reopen178- Popup fonts are now self-hosted instead of loaded from Google Fonts at runtime179- Content script runs on all URLs but autofill requires explicit user click180- Shadow DOM used for selector/banner to avoid page CSS conflicts181182---183184## Build Instructions185186```bash187npm run dev 188npm run build 189npm run typecheck 190npm test 191```192193To load in Chrome: `chrome://extensions` → Developer mode → Load unpacked → `dist/`