Skip to content

Commit 6a02667

Browse files
jitrcclaude
andcommitted
chore: bump version to 0.3.0, update PROGRESS.md and README for AI feature
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5f8a4d0 commit 6a02667

5 files changed

Lines changed: 44 additions & 8 deletions

File tree

PROGRESS.md

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# MailSweep — Progress & Plan
22

33
**Last updated:** 2026-02-25
4-
**Status:** All 6 phases implemented + extensive post-phase enhancements + full code review complete. App running. ~4,800 lines of Python. 56/56 tests passing. Published on GitHub. Release v0.2.0.
4+
**Status:** All 6 phases + AI-powered analysis & reorganization implemented. App running. ~6,200 lines of Python. 74/74 tests passing. Published on GitHub. Release v0.2.0.
55

66
---
77

@@ -30,13 +30,18 @@ mailsweep/ ← project root
3030
│ ├── imap/
3131
│ │ ├── connection.py ← connect(), find_trash_folder(), list_folders()
3232
│ │ └── oauth2.py ← Gmail XOAUTH2, Outlook MSAL, token refresh
33+
│ ├── ai/
34+
│ │ ├── providers.py ← LLM abstraction: OpenAI-compat + Anthropic (stdlib HTTP)
35+
│ │ └── context.py ← DB→markdown context builder for LLM
3336
│ ├── workers/
3437
│ │ ├── scan_worker.py ← FETCH ENVELOPE+SIZE+BODYSTRUCTURE, batched
3538
│ │ ├── qt_scan_worker.py ← QObject wrapper (moveToThread), incremental
3639
│ │ ├── detach_worker.py ← FETCH→strip→APPEND→DELETE→EXPUNGE
3740
│ │ ├── backup_worker.py ← RFC822→.eml→DELETE→EXPUNGE
3841
│ │ ├── delete_worker.py ← Gmail-safe delete on background thread
39-
│ │ └── incremental_scan.py ← get_new_deleted_uids(), CONDSTORE check
42+
│ │ ├── incremental_scan.py ← get_new_deleted_uids(), CONDSTORE check
43+
│ │ ├── ai_worker.py ← background LLM chat (moveToThread)
44+
│ │ └── move_worker.py ← IMAP MOVE (RFC 6851) with copy+delete fallback
4045
│ └── ui/
4146
│ ├── main_window.py ← QMainWindow, splitter layout, all wiring
4247
│ ├── account_dialog.py ← add/edit account, OAuth2 on background thread
@@ -45,12 +50,14 @@ mailsweep/ ← project root
4550
│ ├── filter_bar.py ← sender/subject/date/size/attachment filters
4651
│ ├── treemap_widget.py ← squarify + QPainter, hover, click-to-filter
4752
│ ├── progress_panel.py ← QProgressBar + status + Cancel
48-
│ ├── settings_dialog.py ← batch size, max rows, save dir
49-
│ └── log_dock.py ← live log viewer, per-level colour, dockable
53+
│ ├── settings_dialog.py ← batch size, max rows, save dir, AI settings
54+
│ ├── log_dock.py ← live log viewer, per-level colour, dockable
55+
│ └── ai_dock.py ← AI chat dock: provider selector, chat history, apply moves
5056
└── tests/
5157
├── test_db.py ← 22 tests: CRUD, queries, stats, message_id matching
5258
├── test_scan_worker.py ← 17 tests: mock IMAP, BODYSTRUCTURE parser, message_id
53-
└── test_mime_utils.py ← 11 tests: strip, save, path traversal
59+
├── test_mime_utils.py ← 11 tests: strip, save, path traversal
60+
└── test_ai.py ← 18 tests: LLM providers, context builder, AI queries
5461
```
5562

5663
---
@@ -65,6 +72,7 @@ mailsweep/ ← project root
6572
| 4 | Detach attachments + backup-delete | ✅ done |
6673
| 5 | Gmail + Outlook OAuth2 | ✅ done |
6774
| 6 | Incremental scan, settings, log dock, packaging spec | ✅ done |
75+
| 7 | AI-powered email analysis & reorganization | ✅ done |
6876

6977
---
7078

@@ -104,6 +112,19 @@ Fix: `COPY` UIDs to `[Gmail]/Trash` before `\Deleted`+`EXPUNGE`. Applied to inli
104112
Detach worker doesn't need this — it APPENDs a replacement message, so the old one should be removed.
105113
`find_trash_folder()` in `connection.py` detects Trash across providers (Gmail, Outlook, Apple Mail, generic).
106114

115+
### AI-Powered Analysis (Phase 7)
116+
LLM integration via stdlib HTTP (`urllib.request`) — zero new dependencies.
117+
- **Providers:** OpenAI-compatible (Ollama, OpenAI, Groq, Together) + Anthropic native API
118+
- **Context builder:** Reads SQLite DB → markdown summary (folder tree with stats, top senders per folder,
119+
cross-folder sender overlap, dead folder detection). Capped at ~8K tokens.
120+
- **AI dock:** `QDockWidget` with chat history, provider/model selector, quick-action buttons
121+
("Analyze folders", "Find misfilings", "Find duplicates"), and "Apply Suggestions" for MOVE operations
122+
- **Move worker:** IMAP MOVE (RFC 6851) with `COPY`+`DELETE`+`EXPUNGE` fallback, batched by source folder,
123+
updates local DB cache after each move
124+
- **Threading:** `AiWorker` uses `@pyqtSlot` + `moveToThread` pattern (params via constructor, not lambda)
125+
to keep UI responsive during LLM calls
126+
- **Settings:** Provider/URL/model persisted in `settings.json`; API key stored in system keyring
127+
107128
---
108129

109130
## Bugs Fixed Post-Implementation
@@ -160,6 +181,11 @@ Detach worker doesn't need this — it APPENDs a replacement message, so the old
160181
| **Sender email dedup** | Sender treemap/summary groups by extracted email, not full "Name \<email\>" string |
161182
| **Message-ID matching** | `message_id` from ENVELOPE used for cross-folder dedup, unlabelled detection, and "View Headers → Labels" |
162183
| **Force Full Rescan** | Actions menu option to re-fetch all message metadata, bypassing incremental cache |
184+
| **AI Assistant** | LLM chat dock for mailbox analysis — Ollama/OpenAI/Anthropic, zero new deps (stdlib HTTP) |
185+
| **AI folder analysis** | Context builder: folder tree, top senders, cross-folder overlap, dead folder detection |
186+
| **AI move suggestions** | LLM outputs `MOVE:` lines → user confirms → IMAP move worker executes |
187+
| **IMAP move worker** | RFC 6851 MOVE with copy+delete fallback, batched by source folder, DB cache update |
188+
| **AI settings** | Provider/URL/model in settings dialog + keyring for API key |
163189

164190
---
165191

@@ -240,6 +266,10 @@ Outlook token refresh fix, README/LICENSE/.gitignore added, pyproject.toml metad
240266
## Git Log
241267

242268
```
269+
5f8a4d0 feat: add AI-powered email analysis and reorganization
270+
2b552f4 feat: add AppImage build to release workflow
271+
994e9fa fix: build Linux binary on ubuntu-22.04 for GLIBC 2.35 compat
272+
0b9d67d chore: bump version to 0.2.0, update PROGRESS.md for release
243273
52a2a44 refactor: remove schema migrations, inline all columns and indexes
244274
8fbdba4 feat: add Force Full Rescan option in Actions menu
245275
2817424 feat: add message_id for cross-folder matching, fix unlabelled detection

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ bulk attachment extraction, detach, backup, and delete operations.
2121
- **Incremental scan** — rescan only fetches new/changed messages using UIDVALIDITY
2222
- **OAuth2 support** — Gmail (XOAUTH2) and Outlook (MSAL), plus password/app-password auth
2323
- **Filter bar** — filter by sender, subject, date range, size range, attachment presence
24+
- **AI assistant** — LLM-powered mailbox analysis (Ollama, OpenAI, Anthropic) — find misfilings, dead folders, sender overlap; apply AI-suggested IMAP moves with one click
2425

2526
## Installation
2627

@@ -79,6 +80,7 @@ APIs & Services > Credentials > OAuth 2.0 Client ID (Desktop app type).
7980
| **Backup** | No | Download full message as .eml file |
8081
| **Backup & Delete** | Yes | Download .eml then move message to Trash |
8182
| **Delete** | Yes | Move message to Trash (Gmail-safe) |
83+
| **AI Move** | Yes | LLM suggests moves → user confirms → messages moved via IMAP |
8284

8385
## Data Locations
8486

@@ -118,6 +120,10 @@ uv run mypy mailsweep/
118120
deletion on Gmail where `\Deleted` + `EXPUNGE` on `[Gmail]/All Mail` bypasses Trash entirely.
119121
- **Credentials** are stored in the system keychain via the `keyring` library (Secret Service on
120122
Linux, Keychain on macOS, Credential Manager on Windows). Never stored in files or logged.
123+
- **AI assistant** uses stdlib `urllib.request` to call LLM APIs (zero new dependencies). Builds a
124+
markdown context from the SQLite cache (folder tree, top senders, cross-folder overlap, dead folders)
125+
and sends it as system prompt. Supports Ollama (local), OpenAI, and Anthropic. IMAP moves use
126+
RFC 6851 `MOVE` with `COPY`+`DELETE`+`EXPUNGE` fallback.
121127

122128
## License
123129

mailsweep/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from pathlib import Path
88

99
APP_NAME = "MailSweep"
10-
APP_VERSION = "0.1.0"
10+
APP_VERSION = "0.3.0"
1111

1212
logger = logging.getLogger(__name__)
1313

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "mailsweep"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
description = "IMAP Mailbox Analyzer & Cleaner — visualize and reclaim email storage"
55
readme = "README.md"
66
license = {text = "MIT"}

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)