Skip to content

Latest commit

 

History

History
114 lines (87 loc) · 7.76 KB

File metadata and controls

114 lines (87 loc) · 7.76 KB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog.

[Unreleased]

[0.4.2] - 2026-02-28

Fixed

  • mxctl --version now reports the correct version at runtime (was stuck at 0.3.0 since the rename)
  • Consolidated duplicate get_headers() / get_raw_headers() code in system.py
  • Moved delayed inline imports to module level in actions.py (subprocess, sys, get_gmail_accounts)
  • Fixed ARCHITECTURE.md stale claim: "Six" → "Five" pragma:no cover guards

[0.4.1] - 2026-02-27

Added

  • Public Python API — new mxctl.api module with 56 importable functions for programmatic access to Apple Mail. All command internals refactored to separate data retrieval from CLI presentation. External projects can now from mxctl.api import get_messages, read_message without any CLI or argparse dependency.

Changed

  • README cleanup — removed personal email from examples, trimmed redundant sections, tightened AI workflow documentation (488 → 434 lines)

[0.4.0] - 2026-02-25

Added

  • ai-setup command — interactive wizard to configure Claude Code, Cursor, or Windsurf to use mxctl; detects existing config files, previews the snippet before writing, supports --json
  • ai-setup --print flag — dump the raw snippet to stdout for piping into Ollama Modelfiles, Aider prompts, system prompt files, or clipboard
  • "Pointing Your AI Assistant to mxctl" section in README — mxctl ai-setup walkthrough plus manual snippet for Claude Code, Cursor, Windsurf, and local AI tools

[0.3.0] - 2026-02-24

Changed

  • Renamed projectmy-apple-mail-cli is now mxctl ("mail control")
  • Flattened CLImy mail inbox is now mxctl inbox (removed mail subcommand layer)
  • Config path — moved from ~/.config/my/ to ~/.config/mxctl/ with automatic one-time migration
  • Version bump — 0.2.0 → 0.3.0 (breaking: new binary name and command structure)
  • Package name — Python package renamed from my_cli to mxctl
  • GitHub repoJscoats/my-apple-mail-cliJscoats/mxctl

Added

  • Published to PyPIpip install mxctl now works
  • 100% test coverage — 655 tests across 20 test files (up from 422), measured with pytest-cov
  • 5 demo GIFs — main commands, init wizard, AI triage, batch delete, newsletter unsubscribe (all scripted with fictional data)
  • Feature comparison table — "Why Not X?" section with mxctl vs mutt vs Gmail API vs raw AppleScript
  • Automated release workflowrelease.yml creates GitHub Release with changelog on tag push
  • Pre-commit hooks — ruff check + ruff format run on every commit
  • Dependabot — weekly updates for pip and GitHub Actions dependencies
  • pytest-cov — coverage reporting in CI and locally
  • Ruff config[tool.ruff] in pyproject.toml with 7 rule sets (E, F, W, I, UP, B, SIM)
  • PyPI classifiers — 12 classifiers and 7 keywords for discoverability
  • Centered README header — styled <h1> with 5 badges (PyPI, CI, Python, coverage, license)
  • README table of contents — 14 sections linked

[0.2.0] - 2026-02-22

Added

  • top-senders command — rank senders by frequency with --limit N, --json, and optional mailbox filter
  • batch-delete --from-sender EMAIL flag — delete by sender across all mailboxes, combinable with --older-than
  • NOREPLY_PATTERNS centralized in config.py — single source of truth used by triage, process-inbox, clean-newsletters, and weekly-review
  • TEMPLATES_FILE path centralized in config.py — imported by templates.py and compose.py
  • File locking (_file_lock) applied to all JSON state reads and writes — config.json, state.json, mail-undo.json, mail-templates.json
  • 30 new tests covering templates CRUD, draft error paths, and batch dry-run edge cases (196 total)

Fixed

  • Silent output failures — three cmd_mailboxes, _list_rules, and weekly-review AppleScript strings were plain strings instead of f-strings; FIELD_SEPARATOR was passed as literal text causing commands to silently return empty results
  • batch-delete indexed iteration bug — list shifts after each delete causing skips and crashes
  • batch-delete Gmail All Mail error — individual deletions wrapped in try/end try so one IMAP failure doesn't abort the whole batch
  • batch-delete message IDs now logged only after a successful delete (previously logged before, so failed deletions appeared in the undo log)
  • batch-move — no error resilience; inner loop now wrapped in try/end try matching batch-delete pattern
  • batch-move--limit only exited inner loop, allowing more messages to be processed than requested; outer loop now also checks limit
  • batch-move and batch-delete — dry-run reported total matching count instead of effective count when --limit is set
  • cmd_not_junk — hardcoded "Junk" mailbox name broke on Gmail accounts; now uses resolve_mailbox() for [Gmail]/Spam translation
  • cmd_move — source and destination mailbox names not translated for Gmail accounts; resolve_mailbox() now applied to both
  • triage, process-inbox, clean-newsletters, weekly-review — noreply pattern matching ran against full sender string including display name; now uses extract_email() to match against email address only
  • compose.py — template file read in cmd_draft had no JSON error handling; corrupt file now produces a friendly error
  • compose.py — template file read now uses _file_lock (previously read outside locking protocol)
  • _file_lock — file handle leaked on each failed retry attempt; fixed with with open(...) context manager
  • setup.py cmd_init — config written with bare open() bypassing _file_lock; now uses _save_json()
  • _load_json — reads were not locked (writes were); now symmetric
  • list command now accepts -m/--mailbox flag (was positional-only, inconsistent with all other commands)
  • inbox and triage now accept -a / --account to scope results to a single account
  • Gmail mailbox name mapping — init now asks which accounts are Gmail; Spam, Trash, Sent, Archive etc. auto-translate to [Gmail]/... equivalents
  • accounts --json returning empty [] instead of account data
  • die() return type corrected to NoReturn
  • Raw \x1F/\x1FEND\x1F literals in AppleScript strings replaced with FIELD_SEPARATOR/RECORD_SEPARATOR constants throughout
  • Removed dead code: unused _convert_dates, account_iterator, single_message_lookup functions; unused variable assignments in todoist_integration.py and system.py

[0.1.0] - 2026-02-21

Added

  • First-run setupinit wizard for account detection and optional Todoist token configuration
  • Account managementinbox, accounts, mailboxes, create-mailbox, delete-mailbox, empty-trash, count for scripting and status bars
  • Message operationslist, read, search, mark-read, mark-unread, flag, unflag, move, delete, open for GUI access
  • AI-powered featuressummary, triage, context, find-related, process-inbox
  • Batch operations with undobatch-read, batch-flag, batch-move, batch-delete, undo
  • Analyticsstats, digest, show-flagged, weekly-review, clean-newsletters
  • Compose & templatesdraft with template support, reply, forward, templates subcommands
  • Integrationsto-todoist for sending emails as Todoist tasks, export for Mbox format
  • System toolscheck, headers, rules, junk, not-junk
  • Multi-account support with three-tier account resolution
  • --json output mode on every command
  • Comprehensive test suite (166 tests)
  • Zero runtime dependencies (Python stdlib only)