Release 1.5.1

Bug fixes and code quality improvements:

- Fix mirror index dirtied on every sync (MirrorRecord.updatedAt in equality)
- Fix mirror URL corruption: encode calendar/source IDs before joining with ';'
  and use percentEncodedPath to prevent double-encoding
- Fix cleanup route mutating UI calendar picker selection unnecessarily
- Fix --exit flag redundancy (isCLIRun no longer implies termination)
- Remove dead SKIP_ALL_DAY_DEFAULT constant
- Replace deprecated FileHandle(forWritingAtPath:) with throwing variant
- Add EKEventStoreChanged observer for live calendar list refresh
- Extract AppLogStore into its own file (AppLogStore.swift)
- Add Block.span(start🔚) factory; replace verbose nil-field constructions
- Remove redundant MainActor.run{} wrappers inside @MainActor MirrorEngine
- Fix SettingsPayload indentation inside ContentView

All 45 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-27 15:48:08 +02:00
parent 2c319808c2
commit ad6ae396da
11 changed files with 220 additions and 120 deletions
+6 -4
View File
@@ -40,16 +40,17 @@ BusyMirror/
├── MirrorEngine.swift # EventKit mirror engine (read, deduplicate, merge, create/update/delete)
├── MirrorConfig.swift # Configuration struct passed to the engine
├── MirrorUtils.swift # URL builders, mirror detection, calendar labels
├── BlockMath.swift # Block merging, gap calculation, overlap logic
├── BlockMath.swift # Block merging, gap calculation, overlap logic (Block.span factory)
├── EventFilters.swift # Work-hours, title, and organizer filters
├── MenuBarSupport.swift # `BusyMirrorAppController` (state coordinator) + menu bar view
├── AppLogStore.swift # File-backed log store with rotation (AppLogStore enum)
├── Info.plist # LSUIElement, calendar usage descriptions
├── BusyMirror.entitlements # App sandbox + calendar access entitlement
└── Assets.xcassets/ # AppIcon set and accent color
BusyMirror.xcodeproj/ # Xcode project
BusyMirrorTests/ # Empty (no tests implemented)
BusyMirrorUITests/ # Empty (no tests implemented)
BusyMirror.xcodeproj/ # Xcode project (PBXFileSystemSynchronizedRootGroup — new .swift files are auto-included)
BusyMirrorTests/ # Unit tests: BlockMathTests, EventFiltersTests, MirrorUtilsTests (45 tests)
BusyMirrorUITests/ # UI tests (empty)
```
**Architecture note:** `ContentView.swift` handles the SwiftUI view hierarchy, settings serialization, CLI argument parsing, `launchd` scheduling, and logging. The EventKit mirror engine lives in `MirrorEngine.swift` and is invoked from `ContentView` via `makeEngine()`. Pure helper logic (block math, filters, URL utilities) has been extracted into standalone files for testability.
@@ -142,6 +143,7 @@ Scheduled runs are implemented by generating a `launchd` plist in `~/Library/Lau
| `BusyMirror/EventFilters.swift` | Work-hours, title, and organizer filters |
| `BusyMirror/BusyMirrorApp.swift` | App struct, window scene, menu-bar extra |
| `BusyMirror/MenuBarSupport.swift` | `@MainActor` app controller + menu bar SwiftUI view |
| `BusyMirror/AppLogStore.swift` | File-backed log with rotation (`~/Library/Logs/BusyMirror/`) |
| `BusyMirror/Info.plist` | `LSUIElement`, calendar usage descriptions |
| `BusyMirror/BusyMirror.entitlements` | Sandbox + calendar entitlement |
| `Makefile` | Reproducible build, sign, and package targets |