Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, with entries grouped by release date.
[v0.3.9] - 2026-03-28
Changed
- Updated the LLM Configuration tab UI (
outlook_mail_extractor/screens/config/llm_tab.py) to show an in-app AI mail-reading privacy warning and disclaimer directly below the LLM settings actions. - Added localized warning/disclaimer copy for both
zh-TWanden-USinoutlook_mail_extractor/locales/zh-TW.yamlandoutlook_mail_extractor/locales/en-US.yamlso the legal/privacy notice follows the selected UI language. - Updated git ignore/tracking hygiene by untracking local release helper scripts (
scripts/release_pypi.ps1,scripts/sync_guides.ps1) and adding them to.gitignore. - Updated
event_tableExcel writing (outlook_mail_extractor/plugins/event_table.py) to retry when files are locked by Excel, with configurable retry count/delay (excel_write_retries,excel_write_retry_delay_seconds) and explicit lock warning logs during retries. - Updated
event_tableconfig samples (config/plugins/event_table.yaml.sample,outlook_mail_extractor/resources/config_samples/plugins/event_table.yaml.sample) to expose the new Excel lock-retry settings in both runtime config and_uischema.
Fixed
- Fixed
event_tablelock contention handling so locked.xlsxwrites now returnretriable_failedwithcode="excel_file_locked"and a clear actionable message instead of a generic unexpected error. - Fixed malformed
uv.lockcontent that brokeuv run/test execution by restoring a valid[[package]]entry formailslide.
[v0.3.8] - 2026-03-27
Added
- Added terminal window title handling via
outlook_mail_extractor/terminal_title.py, with Windows Console API support (SetConsoleTitleW) and ANSI fallback for TTY terminals. - Added config-driven terminal title override via
terminal_titleinconfig/config.yaml(default:Mailslide) for both CLI (mailslide) and TUI (mailslide-tui) startup flows. - Added terminal-title regression tests in
tests/test_terminal_title.pycovering Windows, ANSI, and config fallback behavior.
Changed
- Updated config samples (
config/config.yaml.sample,outlook_mail_extractor/resources/config_samples/config.yaml.sample) to document the new optionalterminal_titlekey.
[v0.3.7] - 2026-03-27
Added
- Added packaged Guide documentation resources under
outlook_mail_extractor/resources/docs/(GUIDE.md,GUIDE.en.md) so installed/tool environments can render Guide content without repository-local markdown files. - Added
scripts/sync_guides.ps1to sync/check rootGUIDE*.mdfiles against packaged docs resources, with-CheckOnlymode for CI/release validation. - Added Guide loading regression coverage in
tests/test_usage_screen.pyfor packaged-resource fallbacks in bothen-USandzh-TWlocales.
Changed
- Changed Guide tab content loading (
outlook_mail_extractor/screens/usage.py) to fall back to packaged docs viaimportlib.resourceswhen filesystem Guide/README candidates are unavailable. - Changed package data configuration (
pyproject.toml) to includeresources/docs/*.mdin built distributions. - Changed PyPI release preflight (
scripts/release_pypi.ps1) to enforce Guide resource sync before tests/build.
[v0.3.6] - 2026-03-27
Added
- Added a Home-tab run-status ASCII animation above the jobs table (
outlook_mail_extractor/screens/home.py) with a two-frame loop that switches every 0.5 seconds while jobs are executing. - Added packaged config-template resources under
outlook_mail_extractor/resources/config_samples/**and runtime seeding utilities (config_templates.py) souv toolinstalls can initialize config files without relying on repository-localconfig/files. - Added a dedicated TUI entrypoint module (
outlook_mail_extractor/tui.py) and script commandmailslide-tuifor tool-install execution (uv tool install mailslide+mailslide-tui). - Added release automation/docs artifacts for PyPI-first distribution, including
scripts/release_pypi.ps1,tasks/release_checklist_pypi.md, andMANIFEST.in(prune tests) to keep source distributions lean. - Added job-execution path-normalization tests and service coverage (
tests/test_job_execution_service.py) for plugin output-path resolution behavior. - Added plugin-editor path-resolution tests in
tests/test_plugin_config_editor.pyto cover absolute-path rendering forpathfields with/without runtime base directory context. - Added Windows DPAPI-backed secret storage for
llm-configAPI keys viaoutlook_mail_extractor/secrets.py, writing encrypted key material toconfig/llm-api-key.bininstead of plaintext YAML. - Added PyPI-based app update checks (
outlook_mail_extractor/services/update_check.py) with startup delayed-check behavior (20s), plus About-tab update status display and a manual "Check Updates" action. - Added config-schema migration scaffolding (
outlook_mail_extractor/config_migration.py) so legacy configs are upgraded in-place (v0 -> v2) with timestamped backups andjobs[].batch_flush_enableddefault backfill.
Changed
- Changed runtime path defaults for packaged/tool mode to user data directories (via
platformdirs, withMAILSLIDE_DATA_DIRoverride), while preserving repo-root behavior for explicit source-mode runtime contexts. - Changed CLI default
--configpath resolution to use runtime context (runtime.paths.config_file) instead of hardcodedconfig/config.yaml. - Changed docs (
README*,GUIDE*, task plans/checklists) to make PyPI/uv toolthe primary distribution path and de-emphasize GitHub Releases as a release channel. - Changed About-tab
Initialize Configfeedback to use Textualnotify(...)toast messages instead of inline status replacement, so users can reliably see setup results. - Changed Home-tab
Preserve RE/FWtoggle default toON(while keeping the existing one-click toggle behavior) so first-run execution preserves reply/forward context by default. - Changed docs (
README*,GUIDE*) to explicitly document HomePreserve RE/FWdefault-on behavior. - Changed README language filenames so English is now
README.mdand Traditional Chinese isREADME.zh-TW.md(previouslyREADME.en.mdandREADME.md). - Changed LLM config save/load flow to keep
api_keyblank inconfig/llm-config.yaml, transparently loading from DPAPI secret storage when available and scrubbing legacy plaintext keys before backup writes. - Changed update notifications to use
notify(...)when newer PyPI stable versions are detected, guiding users to upgrade withuv tool upgrade mailslide. - Changed
load_configto auto-run config migration before validation and persistconfig_versionback toconfig/config.yamlafter successful migration.
Fixed
- Fixed Home-tab run animation alignment/rendering so the ASCII block is right-aligned as a single block (without shifting the jobs table) and literal
[@]characters render correctly instead of being interpreted as Rich markup. - Fixed plugin output-file discoverability in
uv toolruntime by resolving relativeoutput_dir/output_filevalues against the active config directory (not process CWD), preventing writes to unexpected locations. - Fixed plugin success observability for writable outputs by attaching output path details to
summary_file/event_tablesuccess results. - Fixed first-run initialization UX by adding an explicit restart reminder toast after creating config files from About > Initialize Config.
- Fixed plugin-config editor path-field clarity by converting relative
output_dir/output_filevalues to absolute paths (based on activeconfigdirectory) before editing/saving, so users can see and persist exact output locations.
[v0.3.5] - 2026-03-27
Changed
- Updated both README language variants (
README.md,README.en.md) with a clear AI-processing warning to avoid sending emails containing personal privacy data or business confidential information. - Updated both README language variants to explicitly recommend using local models when handling sensitive emails.
- Added an explicit disclaimer in both README files stating that the project is provided as-is and project authors are not liable for data breaches or confidential information leakage caused by user inputs or model services.
- Updated i18n default behavior to use
en-USas the base language while auto-detecting Windows UI locale on first run; when locale resolves to Traditional Chinese, the app now defaults tozh-TWif no explicit/configured language is set. - Updated plugin config examples to English-first content across built-in plugin samples (
add_category,move_to_folder,create_appointment,event_table,summary_file,write_file), including system prompts, profile descriptions, JSON example values, and_uilabels/messages. - Updated language-sensitive tests to accept bilingual validation messages where applicable and added coverage for first-run system-language fallback in TUI language initialization.
[v0.3.4] - 2026-03-27
Changed
- Updated
event_tableExcel schema field name fromoutlook_linktooutlook_open_command, and changed output behavior from clickable deep links/launcher files to plain PowerShell open commands for better compatibility in locked-down environments. - Updated
event_tableopen-command generation to use PowerShell-EncodedCommandand robust Outlook COM search logic based on subject/received time traversal across stores/folders instead of relying on unstableEntryID/protocol handlers. - Updated default open-command matching window to subject + received time (within 1 day) and added optional sender matching control.
Added
- Added
open_command_match_senderplugin config (and_uischema field) forevent_tableso users can optionally require sender matching when resolving mails fromoutlook_open_command. - Added
EmailDTO.store_idandEmailDTO.internet_message_idextraction plumbing in core email extraction to support cross-store identification and future fallback matching strategies. - Added/updated
event_tabletests to cover encoded PowerShell command output and sender-match toggle behavior.
[v0.3.3] - 2026-03-27
Fixed
- Fixed Home/Job execution logs so runtime messages now follow the selected UI language (
ui_language) instead of staying hardcoded in Traditional Chinese.
Changed
- Migrated job-run related log messages to i18n keys across runtime modules (
job_execution,core,llm_dispatcher,logger) and added matchingzh-TW/en-USlocale entries. - Updated i18n test expectations in
tests/test_i18n.pyto align with current app branding/copy (app.title,app.subtitle).
Added
- Added
tests/test_job_log_i18n.pyregression coverage to verify log message localization changes when switching betweenzh-TWanden-US.
[v0.3.2] - 2026-03-26
Changed
- Renamed project/package distribution branding from
outlook-mail-extractortomailslidein package metadata, UI title strings, and README documents. - Replaced CLI command references with
mailslideand removed the legacyoutlook-extractscript entry from packaging. - Updated About screen repository URL to
https://github.com/linax777/mailslide. - Added Phase 1 import-path compatibility by introducing
mailslidepackage re-exports while keepingoutlook_mail_extractoravailable during migration.
Licensing
- Declared package licensing metadata as
GPL-3.0-or-laterand updated user-facing license text to match the existing GPLv3 license file.
[v0.3.1] - 2026-03-26
Added
- Added Phase 1 architecture split modules:
outlook_mail_extractor/llm_dispatcher.py,outlook_mail_extractor/plugin_runner.py, andoutlook_mail_extractor/move_policy.pyto isolate LLM dispatch, plugin execution normalization/error wrapping, and move-target policy decisions. - Added plugin lifecycle hooks (
begin_job/end_job) to support job-scoped buffering and flush workflows for writable plugins. - Added optional parser-level HTML artifact reuse (
parse_email_html(..., use_cache=True)) so body extraction and table parsing can share one HTML parse per email. - Added metrics logging payloads for observability: per-mail summary (
METRIC mail_summary) and per-job summaries (METRIC job_summary,METRIC job_execution) including elapsed time, LLM call counts, and plugin status distributions. - Added UI schema evaluator registry APIs (
register_rule_evaluator,get_rule_evaluator,list_rule_evaluators) to support extensible rule wiring without editing the core evaluator map. - Added optional dynamic plugin discovery support via top-level config
plugin_modules(runtime import for custom plugin modules). - Added new tests for Phase 1/2 behavior, including
tests/test_llm_dispatcher.py,tests/test_plugin_runner.py,tests/test_move_policy.py, parser HTML parse bundle coverage, plugin batch-flush workflows, and runtime rule-registry registration.
Changed
- Refactored
EmailProcessororchestration to call shared dispatch/execution/policy helpers instead of duplicating shared/per-plugin/no-LLM branches, while preserving existing external behavior. - Updated
EmailProcessor.extract_email_datato parse HTML once and reuse parsed artifacts for cleaned body and table extraction. - Updated
event_tableandsummary_fileoutput strategy from immediate per-mail writes to default job-level batch flush (configurable per job withbatch_flush_enabled, defaulttrue, with fallback switch-off support). - Updated changelog/version consistency by aligning package
__version__withpyproject.tomland documenting current config/runtime knobs in samples and README. - Updated workspace hygiene by ignoring
*.bakfiles to reduce backup-noise in local working trees.
[v0.3.0] - 2026-03-24
Added
- Added English documentation file
README.en.mdwith installation, TUI/CLI usage, configuration examples, plugin overview, localization notes, and localllama.cppsetup. - Added cross-language navigation links at the top of both README files (
README.md<->README.en.md) so users can switch languages quickly. - Added usage-screen tests in
tests/test_usage_screen.pyto verify language-based README resolution and fallback behavior. - Added key-based i18n runtime (
outlook_mail_extractor/i18n.py) with gettext catalog loading and YAML fallback dictionaries forzh-TWanden-US. - Added CLI language override
--lang(zh-TW/en-US) and config-levelui_languagesupport inconfig/config.yaml(.sample). - Added Language modal in TUI (hotkey
L) with radio-button selection, persisted language updates toconfig/config.yaml, and immediate UI recompose on language switch. - Added Babel i18n tooling (
babel.cfg, localepot/pofiles,scripts/i18n.ps1) and README instructions for extract/init/update/compile workflows. - Added i18n/config tests (
tests/test_i18n.py,tests/test_config_ui_language.py,tests/test_app_language.py) and extended schema tests forlabel_key/message_keysupport.
Changed
- Migrated major TUI/CLI surfaces to translation keys, including app shell/tab labels, Home/About/Schedule/Usage pages, Configuration tabs, Main Config workflows, and key modal/error notifications.
- Updated
_uischema handling to support localized key fields (label_key,message_key) with backward-compatible fallback to rawlabel/messagetext. - Updated Plugin/Main config editor rendering and rule evaluation paths to resolve translated schema labels/messages at runtime.
- Updated packaging metadata to include locale resources and Babel dev dependency.
- Updated Guide tab content loading (
outlook_mail_extractor/screens/usage.py) to read README by active app language:en-USprefersREADME.en.mdwith fallback toREADME.md, whilezh-TWcontinues usingREADME.md.
[v0.2.8] - 2026-03-24
Added
- Added per-job
manual_review_destinationrouting support so emails with no LLM action outcome are moved to a dedicated manual-review folder. - Added high-risk core tests to cover move routing for LLM success ->
destination, non-action ->manual_review_destination, and plugin failure ->manual_review_destination. - Added a new
修改 Jobaction in Main Configuration_uischema so users can update existing jobs from the form-driven workflow instead of editing YAML manually. - Added modal/form test coverage for job edit helpers and add/edit payload handling, including
manual_review_destinationfield mapping.
Changed
- Updated orchestrator move logic to route mails based on LLM plugin result statuses:
SUCCESSgoes todestination, whileSKIPPED/FAILED/RETRIABLE_FAILEDcan be routed tomanual_review_destination. - Updated config sample/UI schema and README job fields to document and expose
manual_review_destinationin TUI and YAML workflows. - Updated Main Configuration tab to support editing the selected job through a dedicated modal, reusing the structured job form fields (
name/account/source/destination/manual_review_destination/limit/plugins) and reducing direct YAML edits.
[v0.2.7] - 2026-03-24
Changed
- Updated
event_tableoutput from CSV to Excel (.xlsx) and changed default output path tooutput/events.xlsx. - Updated
event_tablefixed schema to include Outlook message identifiers and deep-link fields:email_entry_idandoutlook_link. - Updated
config/plugins/event_table.yaml(.sample)UI schema and validation rule from.csvto.xlsxoutput checks. - Updated README plugin documentation for the new Excel-based event table workflow and Outlook classic open-link behavior.
Added
- Added
EmailDTO.entry_idand wired message extraction to include OutlookEntryIDin core processing. - Added Excel hyperlink writing in
event_tableso each row includes a clickableoutlook:<EntryID>link (Open in Outlook) for opening the matching mail in Outlook classic. - Added
openpyxlruntime dependency and lockfile update for Excel read/write support. - Added/updated tests covering Excel output headers/rows, hyperlink generation, append behavior, timezone datetime parsing, and UI schema rule support for
output_file_xlsx.
[v0.2.6] - 2026-03-23
Changed
- Changed LLM plugin orchestration default to
per_plugin, so each LLM-enabled plugin now gets its ownllm_client.chat(...)call and response parsing path, avoiding cross-pluginactioncollisions when multiple plugins are enabled in one job. - Added backward-compatible legacy mode
share_deprecatedthat restores shared single-response behavior for migration scenarios, with explicit runtime warnings that this mode can causeaction_mismatch/skippedoutcomes across mixed-action plugins. - Added
llm_modesupport at both config scopes (config.llm_modedefault +job.llm_modeoverride), with runtime resolution and alias mapping from legacy values (shared,shared_legacy) toshare_deprecated. - Updated job execution wiring to pass global
llm_modedefaults into processor dispatch while allowing per-job overrides without changing existing plugin config loading behavior. - Updated
config/config.yaml.sampleand README documentation to describellm_mode, recommended default usage (per_plugin), and deprecation guidance for shared-response mode.
Added
- Added config validation rules for
llm_modevalues in both top-level config and per-job settings, including backward-compatible acceptance of legacy alias values. - Added high-risk orchestration tests covering per-plugin independent LLM calls,
share_deprecatedsingle-call behavior, and alias compatibility (shared->share_deprecated) intests/test_core_high_risk.py.
[v0.2.4] - 2026-03-23
[v0.2.5] - 2026-03-23
Added
- Added plugin prompt profile support so a single plugin config can define multiple prompt variants (
prompt_profiles) withdefault_prompt_profile, and each job can select a profile viaplugin_prompt_profiles. - Added prompt-profile handling tests in
tests/test_core_high_risk.pycovering profile precedence, default fallback, missing-profile fallback warnings, shorthand profile values, and config immutability. - Added
yamlfield-type tests for plugin editor payload collection, including valid parse, empty input handling, and invalid YAML errors.
Changed
- Updated plugin runtime prompt resolution to apply profile-specific prompt overrides before plugin instantiation, while preserving legacy
system_promptbehavior as final fallback. - Updated
config/config.yaml.sampleandconfig/plugins/add_category.yaml.sampleto document and demonstrate prompt-profile configuration. - Extended prompt-profile sample/UI schema coverage to all built-in LLM plugins (
move_to_folder,create_appointment,event_table,summary_file), so Plugin Configuration modal now shows the same OptionList-based profile editor for each of them. - Updated Plugin Configuration modal UX for
prompt_profilesediting: replaced raw YAML-only workflow with an OptionList-based profile switcher and per-profile detail editor (version,description,system_prompt). - Added profile management controls in Plugin Configuration modal (
+ 新增/- 刪除) to create and remove prompt profiles interactively while enforcing at least one remaining profile. - Updated
config/config.yaml.sampleto showplugin_prompt_profilesunder each job (per-job scope) and removed the misleading top-level example. - Updated README with a dedicated "同 Plugin 多 Prompt(Prompt Profiles)" section describing profile structure, job-level selection, and resolution order.
[v0.2.4] - 2026-03-23
Fixed
- Fixed Plugin Configuration tab file discovery so backup files (
*.yaml.bak) are no longer treated as editable plugin entries, preventing phantom*.yamlrows that failed with "file not found" when opened.
Changed
- Added a new Plugin tab action button
🧹 清理備份to remove stale plugin backup files (config/plugins/*.yaml.bak) and refresh the plugin list in place. - Extended plugin-config tests to cover both backup-file filtering in the plugin list and backup cleanup behavior.
[v0.2.3] - 2026-03-21
Fixed
- Fixed reply/forward body cleanup so metadata header lines are consistently removed from multi-layer threads (
From/Sent/Date/To/Cc/Subjectand寄件者/已傳送/寄件日期/收件者/收件人/副本/主旨) even when preserving RE/FW thread content. - Fixed reply-thread trimming behavior to keep meaningful older body text instead of dropping everything after the first separator block in common reply chains.
Changed
- Expanded parser header pattern matching to cover colon-spacing and mixed Chinese/English variants such as
副本(CC)andDate:for more stable LLM input cleanup. - Added parser debug observability by logging pre/post cleanup body lengths during email extraction to help verify noise-reduction impact.
- Added/updated parser tests for multi-layer metadata stripping and date-header variants; current parser suite now validates this cleanup path with
uv run pytest -q tests/test_parser.py.
[v0.2.2] - 2026-03-20
Highlights
- Refactored the large monolithic
screens.pyinto a modularoutlook_mail_extractor/screens/package while keepingfrom outlook_mail_extractor.screens import ...imports backward-compatible. - Improved maintainability of schema-driven configuration UI by extracting shared YAML write/backup and validation-message helpers used across main/LLM/plugin config tabs.
- Simplified
PluginConfigEditorModalinternals by splitting dynamic form rendering and payload collection into smaller focused methods without changing runtime behavior.
Changed
- Reorganized UI screens into dedicated modules (
about,home,schedule,usage, config tabs, and modals) and removed the legacy single-fileoutlook_mail_extractor/screens.pyimplementation. - Added config-tab helper modules for consistent YAML serialization/atomic write+backup behavior and reusable rule failure preview formatting.
- Kept existing TUI workflows and tests stable through refactor with no user-facing feature regression.
[v0.2.1] - 2026-03-19
Highlights
- Added a schema-driven configuration editing workflow in the TUI so config samples can define action buttons, field metadata, and validation rules while runtime configs remain user-editable YAML.
- Improved job authoring UX by replacing direct empty-row insertion with a modal add-job form that validates required fields before updating config content.
- Added the new
summary_fileplugin to support LLM-generated summary rows appended to a CSV output file.
Changed
- Extended
config/*.yaml.sampleandconfig/plugins/*.yaml.samplewith_uimetadata blocks for future form generation and centralized validation behavior. - Updated the Configuration tab layout to prioritize the jobs list and editable config area, with schema action buttons for validate/save/add/remove/reset.
- Switched add-job plugin selection to Textual
SelectionListdriven by plugin options declared in config schema. - Updated the Plugin Configuration tab to support schema-driven modal editing (
str/int/bool/select/textarea/path/list[str]/multiselect), with field-level validation and_ui.validation_rulesexecution before save. - Added plugin-config save safeguards: remove reserved metadata keys before write, and auto-create
<plugin>.yaml.bakwhen overwriting an existing file. - Refined
response_json_formatediting UX: keepaction/start/endlocked as fixed template keys while allowing other JSON example fields to be edited safely as structured inputs. - Removed the unused LLM
providerruntime setting from config/UI samples and status display, since execution already uses OpenAI-compatibleapi_basedirectly. - Updated README with
_uimetadata guidance andsummary_fileplugin usage examples. - Hardened Main Config save flow in the TUI to validate editor payloads before write (
_ui.validation_rulesplus runtimevalidate_config), preventing invalid YAML objects from overwritingconfig/config.yaml. - Added Main Config backup+atomic write behavior (
config.yaml.bak+ temp-file replace), aligning safety guarantees with existing LLM/plugin editor writes. - Improved Main Config remove-job UX to delete the selected row when available (with fallback to last item) and updated the notification to show both removed row number and job name.
Added
- Added
outlook_mail_extractor/ui_schema.pyhelpers for loading schema metadata, flattening field definitions, evaluating validation rules, generating list-item defaults, and stripping reserved keys. - Added
load_plugin_ui_schemaand Plugin Configuration TUI wiring to load plugin_uischemas fromconfig/plugins/*.yaml.samplewith read-only fallback when schema is missing. - Added
config/plugins/summary_file.yaml.sample,outlook_mail_extractor/plugins/summary_file.py, andtests/test_summary_file_plugin.pyfor the summary CSV plugin workflow. - Added
tests/test_ui_schema.pycoverage for schema field flattening, rule evaluation, default list-item generation, reserved-key stripping, and plugin schema loading. - Added
tests/test_plugin_config_editor.pycoverage for modal payload mapping/validation and plugin config file backup-write behavior. - Added
tests/test_main_config_editor.pycoverage for Main Config editor payload validation and backup/atomic write behavior.
[v0.2.0] - 2026-03-19
Highlights
- Completed architecture improvement milestones PR-1 through PR-7, including service extraction, typed error layering, structured plugin results, capability-based plugin dispatch, DTO/action-port boundaries, and runtime-context dependency injection.
- Unified CLI/TUI behavior through shared execution and preflight services, reducing duplicated UI business logic and improving consistency.
- Improved testability and maintainability by replacing hardcoded paths/global state with injectable runtime dependencies and by expanding automated test coverage.
Fixed
- Fixed
event_tableCSV schema handling by making column definitions code-fixed and ignoring user-providedfieldsoverrides, with a warning log for deprecated config keys. - Fixed
event_tabledatetime parsing to accept ISO8601 timestamps with timezone offsets (for example+08:00) and UTCZsuffixes. - Fixed
create_appointmentdatetime parsing to accept ISO8601 timezone timestamps and normalize them to Outlook-COM-safe naive datetimes before appointment creation.
Changed
- Introduced
JobExecutionServiceto own config-driven job orchestration, and refactoredcore.process_config_fileinto a thin compatibility wrapper while aligning CLI/TUI execution paths to the shared service. - Added plugin capability-based dispatch (
requires_llm,can_skip_by_response,moves_message) so orchestrator behavior is declared by plugin capabilities instead of hardcoded plugin names. - Updated built-in plugins to declare capabilities and moved appointment skip logic (
create=false) into thecreate_appointmentplugin via a response-based skip hook. - Added
mypyto the dev dependency group, installed typing stubs (types-pyyaml,types-pywin32), and introduced project mypy config (includingpycronmissing-stub override) so static typing checks can run in CI/local workflows. - Applied targeted typing improvements in core/services/tests to make
uv run mypy .pass without changing runtime behavior. - Added plugin tests covering timezone datetime handling in both
event_tableCSV export andcreate_appointmentcalendar creation flows. - Removed the legacy
outlook_worker.pycompatibility script because the project now usesoutlook_mail_extractor.__main__as the single CLI entry point. - Updated
.gitignoreand git tracking so local workflow notes (AGENTS.md,DEVELOPER.md,tasks/) stay untracked. - Introduced application-level error layering (
AppError,DomainError,InfrastructureError,UserVisibleError) and aligned core processing error handling to preserve typed failures while wrapping unknown exceptions as infrastructure-level errors. - Introduced structured plugin execution results via
PluginExecutionResultandPluginExecutionStatus(success,skipped,failed,retriable_failed) to improve plugin observability and diagnostics. - Updated
EmailProcessororchestration to normalize both legacyboolplugin returns and new structured results, preserving backward compatibility while standardizing plugin logs and result metadata. - Migrated built-in plugins (
create_appointment,move_to_folder,add_category,event_table,write_file) to return structured execution outcomes with explicit status codes/messages. - Added a shared
PreflightCheckServicefor validating enabled jobs against Outlook account/source availability, and refactored TUI pre-run + About checks to use this common service. - Added CLI preflight validation before job execution (with
--skip-preflightescape hatch) so command-line runs now catch account/source config issues early. - Added unit tests for preflight validation behavior (
tests/test_preflight_service.py) and cleaned related UI lint warnings while wiring the new service. - Introduced
EmailDTOandMailActionPortto separate domain email data from Outlook COM side effects, and addedOutlookMailActionAdapteras the infrastructure implementation. - Refactored
EmailProcessorand built-in plugins to use the action port boundary instead of hidden_message/_accountfields, so plugin behavior can be tested with fake ports without COM dependencies. - Updated plugin/core tests to validate the new DTO + action-port flow and preserve existing processing behavior.
- Introduced runtime dependency wiring via
RuntimeContext/RuntimePathsand updated CLI/TUI flows to consume injected paths, logger manager, and client factory instead of hardcoded module-level paths. - Refactored logger state into an injectable
LogSessionManagerwhile keepingLoggerManageras a backward-compatible static facade. - Extended
core.process_config_fileandJobExecutionServicedependency injection points (runtime paths + logger + factories/loaders), reducing monkeypatch needs in tests.
[2026-03-18]
Fixed
- Fixed OpenAI-compatible endpoint joining in the LLM client by using a relative
chat/completionspath, so configuredapi_basepaths (for example/v1) are no longer dropped. - Fixed LLM API base handling by normalizing
api_base(trim + single trailing slash), preventing malformed URL joins across local providers such as LM Studio. - Fixed LLM HTTP error reporting to include server-side error details and request URL context, making
400and upstream timeout (504) diagnosis actionable in UI/CLI logs. - Fixed Home-tab execution controls by adding a dedicated stop button that cancels the running worker and restores run/stop button states cleanly after cancellation or completion.
- Fixed job execution flow so
destinationmoving still works when no LLM client is available and no-LLM plugins (such aswrite_file) still execute instead of exiting early. - Fixed duplicate move behavior by skipping final
destinationmoving whenmove_to_folderhas already moved the message. - Fixed config-relative loading by resolving
llm-config.yamlandplugins/from the provided--configdirectory first, with fallback to defaultconfig/paths. - Fixed parser reply-history behavior so
preserve_reply_thread=Truenow keeps reply metadata lines instead of removing them unconditionally. - Fixed parser style handling for tags with non-string
styleattributes to avoid attribute access/type-check issues during HTML cleanup.
Changed
- Added
pytestto the dev dependency group and lockfile souv run pytestworks without temporary dependency flags. - Added a new
event_tableplugin that reuses appointment-style LLM extraction and appends event rows to a single CSV table (output/events.csv) instead of creating Outlook calendar items. - Added
config/plugins/event_table.yaml.sampleand README documentation for configuring CSV output path and column order. - Updated the About screen version label to
0.1.7. - Updated
.gitignoreto keep user-localconfig/*.yamlandconfig/plugins/*.yamlignored while allowingtests/to be tracked in git.
[2026-03-17]
Fixed
- Fixed the
outlook-extractconsole entry point so the CLI runs correctly instead of returning an un-awaited coroutine. - Fixed
--no-moveso CLI runs can extract mail data without moving processed messages. - Fixed cleanup in the processing pipeline to avoid masking the original exception when Outlook or LLM setup fails early.
- Fixed calendar creation to resolve the default Calendar folder from the configured Outlook account instead of the global default mailbox.
- Fixed the scheduler lifecycle in the Textual UI to stop duplicate interval timers from accumulating and to shut them down cleanly on unmount.
- Fixed the scheduler shutdown crash caused by
_schedule_timerbeing initialized on the wrong screen class. - Fixed job message limiting so
limitnow counts actual mail items only, while folders with no mail items complete normally without raising errors. - Fixed Outlook account resolution to use strict store-name matching, so invalid account names are detected reliably instead of being accepted by ambiguous COM lookup behavior.
- Fixed the no-LLM plugin execution path (e.g.,
write_file) so processed messages are still moved to the configured destination folder. - Fixed an
UnboundLocalErrorin the no-LLM path by initializingerror_msgbefore early return branches.
Changed
- Improved email body extraction to prefer cleaned HTML content when available, preserve paragraph structure, and trim quoted reply history before sending content to the LLM pipeline.
- Updated parser body cleanup to remove reply/forward metadata header lines from content (
From/Sent/To/Cc/Subjectand寄件者/已傳送/收件者/副本/主旨) to reduce body noise and length. - Improved parser cleanup with high-confidence signature and newsletter footer stripping to reduce noise in extracted email bodies.
- Improved forwarded-message parsing so short
FW:/Fwd:/轉寄comments keep the forwarded body instead of truncating everything after the first forwarded header block. - Added parser coverage for forwarded-message extraction and standard reply-thread trimming behavior.
- Improved first-run onboarding in the TUI so missing
config/config.yamlnow redirects users to theAbouttab, shows initialization guidance, and disables job execution until setup is completed. - Improved validation in the
Abouttab so system checks now verify enabled jobs'accountandsourcesettings before execution. - Improved job execution so configured
destinationfolders are created automatically when missing, which helps first-time runs on new hosts. - Changed parser defaults to preserve RE/FW thread content unless explicitly disabled via
preserve_reply_thread=False. - Added a Home-tab toggle control for preserving RE/FW content during parsing and wired it through to the processing pipeline.
- Replaced the Home-tab switch widget with a visible ON/OFF toggle button to avoid terminal layout visibility issues.
- Added configurable
body_max_lengthsupport inconfig.yaml(global default plus per-job override) so body truncation length can be tuned by environment. - Updated config validation to enforce positive-integer
body_max_lengthvalues. - Updated
config/config.yaml.samplewith documentedbody_max_lengthexamples. - Updated
.gitignoreto ignore localtests/andtasks/directories.