M3: Home — composer, live history, Copy/Open/Delete (ENG-257) #21

Merged demi.dev
targeting main from stoopkidddd/eng-257-m3-home-composer-live-history-copyopendelete
Merged opened by and assigned to demi.dev
targeting main from stoopkidddd/eng-257-m3-home-composer-live-history-copyopendelete

Linear: https://linear.app/engineereddev/issue/ENG-257

What's in this PR (all under apps/web/):

  • home/: composer (auto-growing textarea, Enter/Shift+Enter, live detectLink indicator, collapsible title, target picker from GET /api/devices with online state, Send pending/success/error, encrypted-size check), optimistic send (UUIDv7 → encryptPush → POST /api/pushes) reconciled with the server echo.
  • history/: reducer (insert, dedupe, delete, ordering), paginated decrypted history with infinite scroll, type icon/title/body clamp/source/relative time, "Can't decrypt this push", Copy with feedback, Open (target=_blank rel="noopener noreferrer"), inline-confirmed Delete.
  • live/ws.ts: hello with since, ready/replay_done/resync, ping→pong, silence watchdog, full-jitter backoff, reconnect on online and visibility, 4401 → sign out; applies push, push_deleted, device_*.
  • ?push=<id> deep link (load or fetch, scroll, highlight, focus Copy). Empty, offline and error-with-retry states.

Verify (lead, rebased on 62b77a1):

  • pnpm install --frozen-lockfile → exit 0
  • mise run check:web → exit 0 (Tests 68 passed (68); build OK)
  • mise run e2e:web → exit 0 (16 passed: two-context live delivery, targeting, clipboard, Open attributes, delete propagation, offline replay, optimistic reconcile, pagination, decrypt failure, deep link, retry, axe)
  • Screenshots (not committed): home-empty, home-items, home-offline, home-error in light/dark/mobile.
  • No pneumo-e2e-* containers left.

Deviations:

  • The target picker shows "online"/"offline" text in native <option>s instead of coloured dots (native select accessibility).
  • The ENG-252 navigation e2e no longer asserts zero /api/health//api/me requests on nav; it still asserts no document reload and Back/Forward.

🤖 Generated with Claude Code

Commits 2

M3: Restore composer focus and prove reconnect replay (ENG-257)
M3: Add Home composer and live encrypted history (ENG-257)