fix: keep New Tab drafts through update and quit
Fixes the New Tab draft loss Leo reported after an update/relaunch: "Also, when I updated, it removed my draft in one of the composer things."
New Tab drafts were only sent to the native unsent store from the replacement/unmount callback. A normal quit/update could close the WebView without that callback, and the store only carried text. This adds ordinary edit writes plus a pagehide fallback, stores text and attachment metadata together, and restores both through the native seed/handshake. Existing non-empty records are never replaced by an empty seed.
The red regression covers an ordinary New Tab edit before quit, then a build-A to build-B relaunch restoring text and attachment order and a later B write surviving another relaunch. Swift coverage also keeps the legacy text-only file format readable.
Non-goals: QuickComposer standalone drafts and local queued-message edits remain separate follow-ups.
Verification: git diff --check (pass). Fleet Swift and browser tests should run in CI; this GCP lane has no Swift or Bun toolchain.
agent-identity footer
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes New Tab drafts being lost after an app update or quit, attachments included, for both the current and Classic New Tab. Drafts are now persisted on every edit and flushed on pagehide — reading the field's latest DOM value so a final keystroke and a cleared draft are captured — giving native quit a durable record even when the WebView closes without unmounting, and text and attachment metadata restore together through the native handshake.
- A late-arriving native seed only fills an untouched composer field; a person's typing always wins, and a reconnect omitting the one-shot seed leaves restored state in place.
- Text-only writes preserve the stored attachment list, so an attachment-aware write is never clobbered by a later text-only one.
- Adopts older per-build text-only draft files and legacy daemon
composerDraftfields without overwriting newer state. - Leaves QuickComposer standalone drafts and local queued-message edits as follow-ups.