remove the email residue the extraction left in the platform
a sweep for remnants after 2026-08-18. nothing was broken - no dangling import, symbol, route or permission key anywhere in src/ - but the platform was still speaking the plugin's vocabulary in a dozen places. the one that mattered is live code rather than prose: ChatPanelWrapper hardcodes workspace.id === 'email' to send context: 'email', which is the frontend half of the pair whose backend half (resolveEmailCwd) carries a fifteen-line justification. the two ends now both say so, including that adding a SECOND id there is the signal the platform needs a real way for a plugin to declare a chat context. the rest: two dead imports left by removing the settings section, an empty 'Email' type-section header, a protocol.ts section header with no members naming the plugin's SSE design, and a queue comment pointing at sidecar/email/sync-runner.ts - a path in another repository now. CLAUDE.md, AGENTS.md and working-on-officer.md described email as a platform feature, an app permission and a pm2 process. those are the files a fresh agent reads first, so they were the highest-risk staleness in the tree. TODO.md's whole Email section moved to the plugin's own repository. it held OPEN items pointing at sidecar/email/store.ts, which is exactly how a leftover list sends someone to edit files that do not exist. the delete-account dialog promised it would remove email accounts and playlists. both tables belong to plugins now, so that cascade only happens where the plugin is installed - it now says 'anything an installed plugin keeps for them' instead of naming two it cannot guarantee. imapflow and mailparser STAY in package.json. the plugin has no package.json of its own and resolves from the platform's node_modules, so removing them would break the installed plugin's sidecar. the fix is giving plugins their own dependency manifest, not deleting these. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -132,49 +132,11 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
||||
|
||||
## Email
|
||||
|
||||
- [x] **Gmail-style search operators** (done 2026-07-24, `0e5b91e`). `parseEmailQuery` +
|
||||
`searchEmails` in `sidecar/email/store.ts` parse: `from:`/`to:`/`subject:`/`body:` → FTS5 column
|
||||
filters; `has:attachment`, `is:unread`/`is:read`, `label:X`, `before:`/`after:YYYY-MM-DD` → SQL
|
||||
`WHERE` on `emails`; quoted values → exact phrases; free text → prefix-AND full-text; unknown
|
||||
`op:val` falls back to free text. Structured-filters-only queries skip the FTS join. Validated
|
||||
on the real 18k-mail DB. Search box placeholder hints at operators.
|
||||
- [x] **`OR`** (done 2026-07-24, `85d38fb`). Query splits on top-level uppercase `OR` into branches;
|
||||
each branch is a self-contained condition (`id IN (FTS subquery)` + its SQL filters) and
|
||||
branches are OR'd — so OR works across full-text _and_ structured filters. Verified on the 18k
|
||||
DB (`from:github OR from:deepgram` = 90+7 = 97 exactly).
|
||||
- [ ] **Remaining:** parenthesised grouping (nesting `(a OR b) c`), `in:sent/inbox/spam/trash`
|
||||
(folder scope), and relative dates (`newer_than:7d`). Grouping needs a recursive parser.
|
||||
- [ ] **Group search results into threads too.** Folder views group by conversation (`ee11c94`), but
|
||||
`/email/search` still returns one row per message. Apply the same `thread_id` collapse to the
|
||||
FTS result set so search matches Gmail's grouped results.
|
||||
Email became a plugin on 2026-08-18 (`plugins/email/`, `gitea.officer.dev/plugins/email`). Its work queue
|
||||
went with it — the open items pointed at `sidecar/email/store.ts`, a path in another repository, which is
|
||||
exactly the way a leftover list sends someone to edit files that are not there.
|
||||
|
||||
- [x] **Conversation threading** (done 2026-07-24, `ee11c94`). `thread_id` column on `emails`:
|
||||
header-based for new mail (`id` = `sha1(Message-Id)`, so `References[0]` hashes to the root's
|
||||
id — `computeThreadId` in `sidecar/email/store.ts`), subject+counterpart backfill for already-synced mail.
|
||||
`/messages` collapses to one row per thread (window fn) with count/unread; `/thread/:id` +
|
||||
`/thread/:id/read`; reader renders a collapsible stack. Verified on synthetic + 18k real DB.
|
||||
- [ ] **Upgrade old mail to exact threading.** One-time full re-fetch to capture `References` for
|
||||
already-synced mail — replaces the subject+counterpart fallback (which can over-merge recurring
|
||||
same-subject mail from one sender). Heavy/network-bound; opt-in.
|
||||
- [ ] **Store the RFC `Message-Id` header** on ingest so replies can set a real `In-Reply-To`
|
||||
(currently reply threading leans on subject/participants; `id` is a local hash, not the header).
|
||||
|
||||
- [x] **Compose/reply/send** (done 2026-07-24). Gmail SMTP send with contacts autocomplete, rich
|
||||
contenteditable body (inline images at the caret via paste/drag-drop, Bcc), single close button.
|
||||
- [x] **`busy_timeout` on the email db** (done 2026-07-24, `9527e0b`). API + email sidecar share
|
||||
`emails.db`; wait out a concurrent writer instead of 500-ing with "database is locked".
|
||||
|
||||
- [ ] **Multiple views in the Email screen (tabs).** The screen grows beyond the current mailbox into
|
||||
several switchable views:
|
||||
- [ ] **Sender/domain management view.** Left panel: controls to group mail **by sender** or **by
|
||||
domain** (room for more grouping axes later). From a group, run bulk actions on that
|
||||
sender/domain: **unsubscribe + mark irrelevant**, **delete all mail** from it, **block/ignore
|
||||
future incoming**, etc. Think "inbox cleanup / triage" — operate on a whole sender at once. - Needs: aggregate query (count/size per sender + per domain), a block/ignore list the
|
||||
sync/IDLE path honors on incoming, an unsubscribe action (List-Unsubscribe header / link),
|
||||
and bulk delete over a sender/domain.
|
||||
- [ ] **Chat view.** The existing AI email-assistant flow — likely stays roughly as-is, just lives
|
||||
as one of the tabs (main view).
|
||||
- Open question: tabs vs. some other view switcher; which view is default.
|
||||
Anything still owed to the mail client belongs in that repository's own TODO.
|
||||
|
||||
## Transmission
|
||||
|
||||
|
||||
Reference in New Issue
Block a user