chore: prepare automation loop for Plan 2 (M8–M20)

- Add PLAN2.md with 116 tasks across M8–M20 with testing gates
- Populate loop/plan.md with all new tasks (30-attempt retry policy)
- Update loop/prompt.md to enforce glass design system and PLAN2.md
- Fix PassphraseDialog to use glass-card/gradient-button design system
- Fix crypto.randomUUID fallback for non-secure contexts
- Fix dev.sh to skip proxy startup if port 3141 already in use
- Fix PWA manifest for Android A2HS (purpose:any, display_override, id)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-03 22:29:18 +00:00
co-authored by Claude Opus 4.6
parent 69c32dce1c
commit 9f6158ddd2
8 changed files with 703 additions and 132 deletions
+158 -71
View File
@@ -1,97 +1,184 @@
# Evening Run — 2026-03-03
# AIUI Plan 2 — Automated Loop Task List
> **Format**: Use `- [ ]` for incomplete, `- [x]` for complete. Enable autonomous mode with `CLAUDE_AUTONOMOUS=1` when running.
> **Format**: `- [ ]` = pending, `- [x]` = done.
> Make at least 30 attempts on any difficult task before moving on. Loop reads this file. Specs are in `PLAN2.md`. Design rules are in `loop/prompt.md`.
## Scope
## M8: Chat UX Polish
Execute the full AIUI product roadmap from PLAN.md. Work through milestones M1→M7 in priority order. For each task: read the detailed spec from PLAN.md, develop the feature, run tests, fix issues, verify with `pnpm test && pnpm lint && pnpm typecheck`, commit, and move on.
- [ ] **M8.1** — Message editing & regeneration (pencil icon on hover, re-send clears subsequent messages)
- [ ] **M8.2** — Conversation branching (fork from any message, branch switcher pill, each branch stored in IDB)
- [ ] **M8.3** — Reply-to threading (quoted excerpt in input, thread line visual, prepend `> quote` to message)
- [ ] **M8.4** — Conversation search (`Cmd+F` glass panel, real-time highlight, up/down to jump between matches)
- [ ] **M8.5** — Auto-title generation (background AI call after first exchange, silently replaces "New Chat")
- [ ] **M8.6** — Context window visualiser (slim progress bar, token estimate, orange → red > 80%)
- [ ] **M8.7** — Conversation export (Markdown / JSON / plain text, File System Access API + `<a download>` fallback)
- [ ] **M8.8** — Import conversations (drag-and-drop JSON, AIUI format + Claude.ai export format, merge into IDB)
- [ ] **M8.9** — Long-press / right-click context menus (messages + content cards, `ContextMenu.vue` glass-card)
- [ ] **M8.10** — Scroll position memory (restore per conversation ID, works with virtual scroller)
- [ ] **TEST:M8** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Instructions for Claude
## M9: AI Experience
Read `PLAN.md` for detailed specs on each task below. Follow the Session Protocol in Part 3 of PLAN.md. For each task:
1. Read the detailed spec from PLAN.md (e.g., "Task M1.2" for Error Boundaries)
2. Implement the feature following the spec exactly
3. Run `pnpm typecheck && pnpm lint && pnpm test` — fix any failures
4. Commit with conventional format: `type(scope): description`
5. Update PROGRESS.md — mark the milestone item done, add session log entry
6. Mark the task done (`- [x]`) here in this file
7. Add a brief summary to the Notes section at the bottom
8. Move to the next unchecked task
- [ ] **M9.1** — Multi-model comparison mode (split-screen same prompt → 2 models, swipeable on mobile)
- [ ] **M9.2** — System prompt editor / personas (named personas, model preference, accent, per-conversation)
- [ ] **M9.3** — Prompt template library (`/` command palette, `{{variable}}` substitution, IDB-persisted)
- [ ] **M9.4** — Vision input (drag-and-drop image, base64 in message content, only when model supports vision)
- [ ] **M9.5** — Response feedback (thumbs up/down per message, stored in IDB, exported with conversations)
- [ ] **M9.6** — Token & cost estimator (badge per message, running total in context bar, model pricing table)
- [ ] **M9.7** — AI memory panel (pinned facts injected into every system prompt, encrypted IDB, max 20 items)
- [ ] **M9.8** — Model capabilities badge (Vision / Tools / Long context badges in model selector)
- [ ] **M9.9** — Temperature & params sliders (temperature, max tokens, top-P, persisted per conversation)
- [ ] **M9.10** — Stop sequence configuration (comma-separated stop sequences in advanced settings)
- [ ] **TEST:M9** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Phase 0: CI Baseline (completed)
## M10: Advanced Content Renderers
- [x] Add `eslint.config.js` (flat config) to `packages/app`
- [x] Add `eslint.config.js` (flat config) to `packages/core`
- [x] Add a minimal smoke test in `packages/core`
- [x] Run `pnpm lint` and fix reported issues
- [x] Verify `pnpm test`, `pnpm lint`, `pnpm typecheck` all pass
- [ ] **M10.1** — Full article renderer (TOC sidebar, reading time, font-size control, print mode, markdown-it)
- [ ] **M10.2** — PDF viewer (`pdfjs-dist` lazy loaded, page nav, zoom, text selection, page 1 thumbnail preview)
- [ ] **M10.3** — Map renderer (Leaflet + OpenStreetMap lazy loaded, pins for all places, cluster > 10, fullscreen)
- [ ] **M10.4** — Recipe renderer (new `recipe` content type, ingredients checklist, numbered steps, scale slider)
- [ ] **M10.5** — Event renderer (new `event` content type, countdown, ICS download, Google Calendar URL)
- [ ] **M10.6** — Math renderer (KaTeX lazy loaded, `$...$` inline + `$$...$$` block, batch render on stream end)
- [ ] **M10.7** — Mermaid diagram renderer (lazy loaded, dark theme, flowchart/sequence/gantt, pan/zoom mobile)
- [ ] **M10.8** — Audio waveform player (WaveSurfer.js lazy loaded, orange waveform, click-to-seek)
- [ ] **M10.9** — Table renderer (sortable columns, row filter, CSV export, virtualise > 500 rows)
- [ ] **M10.10** — Timeline renderer (new `timeline` content type, vertical layout, animate in during streaming)
- [ ] **M10.11** — Code runner (HTML/CSS/JS sandboxed iframe, `sandbox="allow-scripts"`, output console)
- [ ] **M10.12** — Video renderer (native `<video>`, HLS.js lazy loaded, YouTube nocookie embed fallback)
- [ ] **TEST:M10** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Phase 1: M1 — Stability & Polish
## M11: Nostr Ecosystem
- [x] **M1.2: Error Boundaries** — ErrorBoundary.vue already exists. Verify it wraps ChatPage, ChatWindow, ContentPanel sections. Add missing wrappers per PLAN.md spec.
- [x] **M1.3: Unit tests for contentExtraction** — Create `packages/app/src/__tests__/contentExtraction.test.ts`. Test all 10 extraction functions (films, songs, podcasts, books, TV, places, magazine, stripTags, boldLinks). See PLAN.md for full test list.
- [x] **M1.1: IndexedDB Persistent Storage** — Create `packages/app/src/utils/idb-storage.ts`. Modify `packages/app/src/stores/chat.ts` to persist conversations in IndexedDB. Keep dev-chats middleware as fallback. See PLAN.md Task M1.1.
- [x] **M1.4: Unit tests for useAI** — Create `packages/app/src/__tests__/useAI.test.ts`. Mock fetch/SSE. Test provider selection, context injection, sendMessage, stopGeneration. See PLAN.md Task M1.4.
- [x] **M1.5: E2E Test Expansion** — Add 8 new E2E tests to `packages/app/e2e/content-surfaces.spec.ts`: streaming response, film cards, detail view, mobile overlay, stop button, web search toggle, new conversation, panel toggle. See PLAN.md Task M1.5.
- [ ] **M11.1** — Publish Nostr notes (compose panel, sign via NIP-07, broadcast to relays, per-relay status)
- [ ] **M11.2** — Nostr DMs NIP-17 (encrypted DMs, inbox tab, contact list, store in IDB)
- [ ] **M11.3** — Relay management UI (add/remove relays, latency column, read/write toggle, import NIP-65)
- [ ] **M11.4** — Nostr profile editor (display name, bio, avatar, NIP-05, Lightning address, publish kind:0)
- [ ] **M11.5** — Zaps NIP-57 (⚡ button on notes/profiles, sat amount input, LNURL-pay flow, QR + deep-link)
- [ ] **M11.6** — NIP-05 verification badge (✓ badge, fetch from NIP-05 domain, cache 24h in IDB)
- [ ] **M11.7** — Nostr search NIP-50 (search input, send REQ with `search` to NIP-50 relays, filter by type)
- [ ] **M11.8** — Thread view (fetch root + replies via `#e` tag, render threaded tree, max 5 levels deep)
- [ ] **M11.9** — Nostr lists NIP-51 (follow/mute/pin/bookmark lists, kind:3/10000/10001/10003, add/remove)
- [ ] **M11.10** — Long-form content NIP-23 (kind:30023 articles, article renderer, discovery tab, share button)
- [ ] **TEST:M11** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Phase 2: M2 — Content Experience (UX)
## M12: Bitcoin Ecosystem
- [x] **M2.1: Markdown Rendering in Chat**`pnpm add markdown-it @types/markdown-it` in packages/app. Modify ChatMessage.vue to render markdown after stripping content tags. No raw HTML passthrough (XSS safe). Add CSS for code blocks, lists, links. See PLAN.md Task M2.1.
- [x] **M2.3: Music Source Resolution** — Fix usePlayer.ts: add queue (ShallowRef<Song[]>), currentIndex, playNext/playPrevious/addToQueue. Fix iframe playback. Update PlayerBar.vue with next/prev buttons and queue panel. See PLAN.md Task M2.3.
- [x] **M2.2: Virtual Scrolling for Chat**`pnpm add @tanstack/vue-virtual` in packages/app. Replace message v-for in ChatWindow.vue with useVirtualizer. Dynamic row heights, scroll-to-bottom during streaming, overscan 5. See PLAN.md Task M2.2.
- [x] **M2.4: Nostr Feed Integration** — Create `packages/app/src/composables/useNostr.ts`. Raw WebSocket to public relays (relay.damus.io, nos.lol, relay.snort.social). Subscribe kind:1 limit 50. Update NostrGrid.vue to use composable. Lazy-load on tab activation. See PLAN.md Task M2.4.
- [ ] **M12.1** — On-chain address display (bech32 + legacy detect, QR, mempool.space link, copy button)
- [ ] **M12.2** — Fedimint ecash display (detect token format, amount in sats, "Receive in Fedi" deep-link)
- [ ] **M12.3** — BOLT12 offers (detect `lno1...`, decoded amount, description, QR, "Pay with wallet" deep-link)
- [ ] **M12.4** — Nostr Wallet Connect NWC (NIP-47, paste connection string, check balance, pay with confirmation)
- [ ] **M12.5** — LNURL-auth login (generate LNURL-auth QR, scan with wallet, set persistent Lightning identity)
- [ ] **M12.6** — Live sat/fiat price (mempool.space `/api/v1/prices`, 60s refresh, `useBitcoinPrice` composable)
- [ ] **M12.7** — Mempool.space tx viewer (detect txid/block height, confirmations, fee rate, live WebSocket)
- [ ] **M12.8** — BOLT11 decoder card (amount, description, expiry countdown, red when < 5min, NWC pay button)
- [ ] **TEST:M12** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Phase 3: M3 — Plugin System
## M13: Content Discovery
- [x] **M3.1: Activate Plugin Registry** — Create `packages/app/src/plugins/index.ts` (bootstrap) and `claude-provider.ts` (AI provider adapter wrapping useAI). Call `initializePlugins()` in main.ts. See PLAN.md Task M3.1.
- [x] **M3.2: Renderer Plugin Registration** — Create film-renderer.ts and song-renderer.ts in `packages/app/src/plugins/renderers/`. Register via plugin system. Migrate ContentPanel.vue to look up renderers from registry (gradual — film/song first). See PLAN.md Task M3.2.
- [ ] **M13.1** — "For You" feed (frequency map from favorites + history, local only, refreshes on app open)
- [ ] **M13.2** — Content tagging (user tags on any item, stored in IDB, filter grids by tag, tag cloud in favorites)
- [ ] **M13.3** — Smart playlists (recently played, most played, by genre, by decade — computed IDB views)
- [ ] **M13.4** — Similar content (background AI call per item, 3 suggestions, cached 7 days in IDB)
- [ ] **M13.5** — Recently viewed history (last 50 items any type, "Recent" tab in content panel, stored IDB)
- [ ] **M13.6** — Content collections (user-curated mixed-type lists, mosaic thumbnail grid, shareable NIP-51)
- [ ] **M13.7** — Trending in conversations (most-referenced items across 30 days, "referenced N times" badge)
- [ ] **M13.8** — Share content to Nostr (generate note with title + AI description + tag URL, sign via NIP-07)
- [ ] **TEST:M13** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Phase 4: M4 — Social & Discovery
## M14: Plugin Marketplace
- [x] **M4.1: Social Embeds** — Create NostrEmbed.vue. Detect `nostr:note1...`, `nostr:npub1...`, `nostr:nevent1...` in ChatMessage.vue. Render as embedded cards using useNostr composable. Handle bech32 NIP-19 decoding. See PLAN.md Task M4.1.
- [x] **M4.2: Federated Search** — Create `useFederatedSearch.ts`. Add `/search` command to ChatInput.vue. Create SearchResults.vue overlay with results grouped by type (film, song, podcast, web). Keyboard navigation. See PLAN.md Task M4.2.
- [x] **M4.3: Bookmarks/Favorites** — Create `packages/app/src/stores/favorites.ts` (Pinia + IndexedDB). Create FavoriteButton.vue (heart toggle), FavoritesGrid.vue (new tab in ContentPanel). Add favorite button to FilmCard, SongCard, BookCard, etc. See PLAN.md Task M4.3.
- [ ] **M14.1** — Plugin discovery UI (fetch static registry JSON, list with name/type/author/version, install button)
- [ ] **M14.2** — Plugin settings panel (`PluginSettingsForm.vue` renders JSON Schema, stored encrypted IDB)
- [ ] **M14.3** — Plugin permissions UI (permissions dialog on install, grant/deny per capability, stored per plugin)
- [ ] **M14.4** — Plugin dev mode (`VITE_PLUGIN_DEV=true`, hot-reload from `src/plugins/dev/`, error inspector)
- [ ] **M14.5** — Built-in plugin: Wikipedia (`/wiki {query}`, Wikipedia REST API, returns `article` card)
- [ ] **M14.6** — Built-in plugin: OpenLibrary (`/book {query}`, openlibrary.org, returns `book_ext` cards)
- [ ] **M14.7** — Plugin import by URL (paste GitHub raw URL or IPFS CID, validate manifest, permissions dialog)
- [ ] **M14.8** — Plugin versioning & auto-update (check registry on start, badge when updates available, changelog)
- [ ] **TEST:M14** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Phase 5: M5 — Security & Privacy
## M15: Settings & Personalisation
- [x] **M5.1: E2E Encryption** — Create `packages/app/src/utils/crypto.ts` using Web Crypto API. AES-256-GCM encryption, PBKDF2 key derivation (100K+ iterations). Modify idb-storage.ts to encrypt/decrypt on write/read. Skip in dev mode (`VITE_DISABLE_CRYPTO=true`). See PLAN.md Task M5.1.
- [x] **M5.2: Encrypted Storage Layer** — Create PassphraseDialog.vue. Wire encryption to all stores (conversations, favorites). Session key held in memory only. Create/enter passphrase flow. See PLAN.md Task M5.2.
- [x] **M5.3: API Key Vault** — Create `packages/app/src/utils/key-vault.ts`. Encrypted IndexedDB store for API keys. Create ApiKeyManager.vue (list providers, add/remove keys, masked display, test connection). Modify useAI.ts to read from vault. See PLAN.md Task M5.3.
- [ ] **M15.1** — Accent colour picker (colour wheel + presets, updates `--color-accent` CSS var, IDB-persisted)
- [ ] **M15.2** — Glass intensity slider (Subtle/Default/Strong presets, blur + opacity CSS vars, live preview)
- [ ] **M15.3** — Font size settings (Compact 13px / Default 15px / Large 17px, sets `--font-size-base`)
- [ ] **M15.4** — Content type visibility (toggle each of 11 renderers, hidden types still extract, just not shown)
- [ ] **M15.5** — Keyboard shortcut map (list all shortcuts, click to rebind, conflict detection, IDB-persisted)
- [ ] **M15.6** — Browser push notifications (opt-in, "Generation complete" while backgrounded, SW notification)
- [ ] **M15.7** — Auto-archive old conversations (7/30/90/never slider, "Archive" IDB store, unarchive per item)
- [ ] **M15.8** — Full data export (JSON archive of all IDB stores, optional encryption, GDPR compliant)
- [ ] **M15.9** — Data wipe (two-step confirm, clears IDB + SW cache + localStorage, checkbox for API key vault)
- [ ] **M15.10** — Default conversation settings (model, persona, web search, token counts — applies to new convos)
- [ ] **TEST:M15** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Phase 6: M6 — Payments & Identity
## M16: Mobile UX Polish
- [x] **M6.1: Lightning Wallet Deep-links** — Create `packages/app/src/utils/lightning.ts` (LNURL-pay, BIP21, Lightning: URIs). Create PaymentButton.vue and LightningInvoice.vue (QR code, copy, expiry countdown). Deep-link to external wallets. See PLAN.md Task M6.1.
- [x] **M6.2: Cashu Token Support** — Create `packages/app/src/utils/cashu.ts` (parse cashuA... tokens). Create CashuToken.vue inline component. Detect in ChatMessage.vue. Display amount, mint, copy/open-in-wallet buttons. AIUI is never a wallet. See PLAN.md Task M6.2.
- [x] **M6.3: Nostr Identity (NIP-07)** — Create `packages/app/src/composables/useNostrIdentity.ts` (window.nostr API). Create NostrLogin.vue. Login/logout, npub display, event signing. Detect NIP-07 extension. See PLAN.md Task M6.3.
- [ ] **M16.1** — Bottom sheet component (`BottomSheet.vue`, gesture drag, 40%/80%/100% snap points, backdrop)
- [ ] **M16.2** — Swipe to navigate conversations (swipe left/right in chat, slide transition, 80px + 0.3 velocity)
- [ ] **M16.3** — Pull-to-refresh on content panels (glass spinner, re-fetch context, haptic on release)
- [ ] **M16.4** — Haptic feedback (`useHaptics()` composable, `navigator.vibrate()`, settings toggle to disable)
- [ ] **M16.5** — Web Share API (native `navigator.share()`, fallback glass share sheet, copy/Nostr options)
- [ ] **M16.6** — Pinch-to-zoom on images & maps (`usePinchZoom()` composable, 1×–4×, double-tap reset)
- [ ] **M16.7** — iOS PWA polish (apple-mobile-web-app meta tags, safe area insets, splash screens)
- [ ] **M16.8** — Long-press context menus mobile (500ms trigger, opens as BottomSheet, haptic on trigger)
- [ ] **M16.9** — Scroll position memory per route (session Map, works across tab switches and back navigation)
- [ ] **M16.10** — Landscape mode optimisation (50/50 split layout, minimal player bar, smooth rotate transition)
- [ ] **TEST:M16** — Run `pnpm test` and `pnpm typecheck && pnpm lint`. Fix all failures before proceeding.
## Phase 7: M7 — Platform
## M17: Accessibility & Internationalisation
- [x] **M7.1: MCP Server Integration** — Create `packages/app/src/plugins/mcp-server.ts`. Expose AIUI capabilities as MCP tools (search_films, search_songs, search_web, get_nostr_feed). Handle tool_use in useAI.ts. See PLAN.md Task M7.1.
- [x] **M7.2: Multi-provider AI Normalization** — Create adapter pattern: `adapters/types.ts` (AIAdapter interface), `claude-adapter.ts`, `openrouter-adapter.ts`, `ollama-adapter.ts`. Refactor useAI.ts to use adapters. See PLAN.md Task M7.2.
- [x] **M7.3: Tauri Desktop Build** — Create `src-tauri/` with tauri.conf.json and main.rs. Frameless window, transparent background for glass morphism, system tray, global shortcut (Cmd+Shift+A). See PLAN.md Task M7.3.
- [x] **M7.4: Offline Mode** — Create `packages/app/src/composables/useOffline.ts`. PWA cache strategies (app shell cache-first, API network-first, images stale-while-revalidate). Offline banner, disable chat input, show cached content. See PLAN.md Task M7.4.
- [ ] **M17.1** — Keyboard navigation audit (Tab order, focus trap in modals, Escape closes, arrow key grids)
- [ ] **M17.2** — ARIA audit (`aria-label` all icon buttons, `aria-live` dynamic content, dialog roles)
- [ ] **M17.3** — High contrast mode (`prefers-contrast: more` + Settings toggle, higher border/text opacity)
- [ ] **M17.4** — Automated accessibility tests (axe-core in Playwright, `pnpm test:a11y`, fail on critical)
- [ ] **M17.5** — i18n foundation (`vue-i18n`, extract strings to `en.json`, add `es.json` + `fr.json`)
- [ ] **M17.6** — RTL layout support (`dir="rtl"` for Arabic/Hebrew, logical CSS properties throughout)
- [ ] **M17.7** — Dyslexia-friendly font (OpenDyslexic WOFF2 self-hosted, Settings → Appearance → Font)
- [ ] **M17.8** — Skip navigation link (hidden "Skip to main content" visible on Tab focus, jumps to `<main>`)
- [ ] **TEST:M17** — Run `pnpm test`, `pnpm test:a11y`, and `pnpm typecheck && pnpm lint`. Fix all failures.
## Success criteria
## M18: Performance
- [x] Error boundaries prevent cascading failures
- [x] contentExtraction tests all pass
- [x] Conversations persist across page refresh (IndexedDB)
- [x] Markdown renders in chat messages
- [x] Music player has queue + next/prev
- [x] Nostr feed shows real posts
- [x] Plugin registry active at runtime
- [x] Federated search across content types
- [x] Favorites persist in IndexedDB
- [x] Encryption layer protects stored data
- [x] API keys encrypted at rest
- [x] Lightning payment deep-links work
- [x] Nostr identity login via NIP-07
- [x] Tauri desktop build scaffold ready
- [x] Offline mode shows cached content
- [x] pnpm test passes
- [x] pnpm lint passes
- [x] pnpm typecheck passes
- [ ] **M18.1** — Bundle analysis & splitting (`vite-bundle-visualizer`, identify eager loads, add route chunks)
- [ ] **M18.2** — Image lazy loading with blur-up (`loading="lazy"`, 16×16 base64 placeholder, CSS transition)
- [ ] **M18.3** — Request deduplication (`useFetch()` composable, in-flight Promise sharing, AbortController)
- [ ] **M18.4** — Web Worker for heavy tasks (`heavy.worker.ts` via Comlink, contentExtraction + crypto)
- [ ] **M18.5** — Prefetch on hover (mouseenter/touch-hold, pre-fetch detail data, 5-min short-lived cache)
- [ ] **M18.6** — Memory leak audit (`onUnmounted` cleanup for all intervals/listeners/WebSockets/observers)
- [ ] **M18.7** — Background sync queue (queue failed IDB saves, retry on `visibilitychange`, warn badge)
- [ ] **M18.8** — OPFS storage backend (SQLite WASM via `@sqlite.org/sqlite-wasm`, `VITE_STORAGE=opfs` flag)
- [ ] **TEST:M18** — Run `pnpm test`, `pnpm build`, verify gzipped bundle < 250 KB. Fix if over budget.
## M19: Developer Experience & Quality
- [ ] **M19.1** — Storybook 8 (stories for all `ui/` components, dark glass canvas, `pnpm storybook`)
- [ ] **M19.2** — Visual regression tests (Playwright screenshots for key views, fail on > 0.5% pixel diff)
- [ ] **M19.3** — Bundle size CI gate (`bundlesize`, fail if > 250 KB gzipped, PR comment with diff)
- [ ] **M19.4** — Comprehensive mock data (20+ items per content type, mock Nostr relay, mock TMDB)
- [ ] **M19.5** — E2E cross-browser matrix (Chromium + Firefox + WebKit, mobile viewports iPhone 14 + Galaxy S21)
- [ ] **M19.6** — Proxy integration tests (mock Anthropic API, assert SSE format, tool_use, error codes, disconnect)
- [ ] **M19.7** — Lighthouse CI (LCP < 3s, CLS < 0.15, scores posted as PR comment, stored in `reports/`)
- [ ] **M19.8** — Dependency audit (`pnpm audit` + `license-checker`, weekly job, block on critical vulns)
- [ ] **TEST:M19** — Run full suite: `pnpm test && pnpm test:e2e && pnpm typecheck && pnpm lint`. All must pass.
## M20: Collaboration & Sharing
- [ ] **M20.1** — Share conversation via Nostr (export as kind:30023 long-form article, sign NIP-07, optional encrypt)
- [ ] **M20.2** — Read-only conversation viewer (`/view/:nostrAddr` route, renders shared Nostr conversation)
- [ ] **M20.3** — Collaborative playlist NIP-51 (shared kind:30004 list, invite by npub, merge contributions)
- [ ] **M20.4** — Conversation templates (pre-built starters as glass cards, system prompt + first message, NIP share)
- [ ] **M20.5** — Export as audio podcast (Web Speech API TTS, WAV export via Web Audio, optional music mix)
- [ ] **M20.6** — Community content packs (import curated JSON from GitHub/IPFS, listed in plugin marketplace)
- [ ] **TEST:M20** — Run `pnpm test && pnpm typecheck && pnpm lint`. All green before proceeding.
---
## Final Sign-off
- [ ] **FINAL** — Run `pnpm test && pnpm test:e2e && pnpm typecheck && pnpm lint && pnpm build`. All pass. Update PROGRESS.md with completion summary. Tag release `v2.0.0`.
---
## Notes
(Claude will add context here for each completed task.)
(Claude adds brief completion notes here as tasks finish.)