30 Commits
Author SHA1 Message Date
tomas.kracmarandClaude Sonnet 5 d40bc986c5 Release 1.8.2
Standard app instead of menu-bar-only: removed LSUIElement from Info.plist.
Dock icon, Cmd+Tab, and the standard app menu (Cmd+Q) are back. The
accessory-app design was making the app hard to quit reliably -- no Dock
icon and no accessible app menu meant the only way to quit was finding the
menu bar dropdown's "Quit BusyMirror" item, which was blocking updates
(old process holds the bundle open, "app in use" on replace). Menu bar
extra stays as a secondary quick-access point.

Verified via `lsappinfo` (type="Foreground", was "UIElement") since this is
an app-type change a screenshot wouldn't show either way.

All unit tests pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
v1.8.2
2026-08-27 07:20:19 +02:00
tomas.kracmarandClaude Sonnet 5 39c5cba237 Release 1.8.1
Fix Preferences window being unreachable in 1.8.0: BusyMirror is LSUIElement
(accessory), so it never gets the standard app menu that the automatic
Settings scene's Cmd+, / SettingsLink depend on. Replaced Settings{} with a
plain Window opened via openWindow(id:) -- the same mechanism already used
for the main window -- and added a "Preferences..." item to the menu bar
dropdown as a second, more discoverable entry point.

All unit tests pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
v1.8.1
2026-08-26 23:04:55 +02:00
tomas.kracmarandClaude Sonnet 5 edddf65288 Release 1.8.0
- Real Settings (Cmd+,) window via PreferencesView, hosting the pure
  @AppStorage-backed defaults that used to live in the main window's
  "General Settings" panel. Both windows share the same live values since
  they're backed by the same UserDefaults keys.
- Menu bar icon reflects idle/syncing/error state; dropdown shows last-sync
  time/result and whether auto-sync is armed, sourced from the same
  lastRunAtISO/lastRunOK/lastRunSummary keys --status reads.
- ContentView.swift split from ~2000 lines into CalendarsSectionView,
  RoutesSectionView, ScheduleSectionView, LogSectionView + a small shared
  CalendarDisplay.swift. View-layer extraction only — state ownership and
  settings persistence deliberately left alone.
- Fixed a latent revert-on-relaunch bug caught while building the Settings
  window: moving preference controls out of ContentView meant they no longer
  re-triggered saveSettingsToDefaults(), so settings.v2 could go stale and
  the next launch would silently revert a just-changed preference via the
  shared applySnapshot path. Split launch-time restore (routes + selection
  only) from Import's full restore.

All 47 unit tests pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
v1.8.0
2026-08-26 21:26:07 +02:00
tomas.kracmarandClaude Sonnet 5 08e9fe5325 Release 1.7.0
- Event-driven background sync, replacing the hourly launchd StartInterval
  poll (only fired if the Mac happened to be awake at that instant, and got
  throttled/coalesced by macOS). Once saved routes exist: registers as a
  login item (SMAppService.mainApp), removes any old launchd schedule, and
  reacts to EKEventStoreChanged (debounced ~3s), NSWorkspace.didWakeNotification,
  plus a 30-min fallback timer as a safety net. Auto-sync always writes,
  matching what the old scheduled runs did.
- This lives in BusyMirrorAppController (app-lifetime), not ContentView —
  ContentView's own EKEventStoreChanged observer is torn down when the main
  window closes, which would make auto-sync a no-op exactly when it needs to
  keep working (window closed, menu-bar-only). Confirmed via MenuBarSupport's
  existing "Sync Now" handler, which already has to reopen the window before
  it can run anything.

All 47 unit tests pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
v1.7.0
2026-08-26 18:37:23 +02:00
tomas.kracmarandClaude Sonnet 5 61cea918a6 Release 1.6.1
- Sync reminders: new "Sync reminders when mirroring" option (global and
  per-route) copies source event alarms into mirrored placeholders. CLI flag
  --sync-reminders.
- CLI polish: --help, --list-calendars, --status (all support --json).
  Scheduled/headless runs record last-run time/result/summary. Failure paths
  now exit with distinct nonzero codes (2 = no calendar access, 3 = no saved
  routes) instead of always exiting 0.
- Fix settings silently wiped on upgrade: SettingsPayload's auto-synthesized
  Codable threw on any settings blob missing a field added since (e.g. the
  new syncReminders key), failing the whole decode and letting the next
  autosave persist an empty state over real routes/filters. Custom decode
  now falls back per-field like Route already did, and loadSettingsFromDefaults
  recovers routes from the legacy routes.v1 key if settings.v2 comes back
  empty, repairing installs already hit by this.
- Roadmap: event-driven background sync (SMAppService + EKEventStoreChanged +
  wake notification) and an external MCP wrapper around the CLI queued next;
  decided against direct Google/CalDAV API integration since EventKit already
  covers it via System Settings accounts.

All 47 unit tests pass (45 existing + 2 new SettingsPayloadTests).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
v1.6.1
2026-08-26 13:10:23 +02:00
tomas.kracmarandClaude Sonnet 4.6 ad6ae396da 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>
v1.5.1
2026-05-27 15:48:08 +02:00
tomas.kracmar 2c319808c2 Release 1.5.0
- Remove non-functional markPrivate feature and Objective-C runtime hacks
- Extract mirror engine into MirrorEngine.swift
- Move calLabel to MirrorUtils.swift
- Update AGENTS.md architecture documentation
- Bump version to 1.5.0 (build 19)
v1.5.0
2026-05-27 12:51:22 +02:00
tomas.kracmar f625ecc263 Release 1.4.0
Fixes:
- Sandbox: add LaunchAgent temporary-exception entitlement
- Mirror URL: fix broken buildMirrorURL (URLComponents with ; separator)
- Cleanup: add bounds check to prevent crash on missing source
- State safety: pass MirrorConfig instead of mutating global @State
- KVC: remove misleading do-catch around setValue:forKey:
- Log cap: limit in-memory log to 2000 lines
- CLI: fix race with calendar loading
- launchCtl: separate stdout/stderr pipes

Features:
- Cancel button for long-running mirrors
- Progress indicator for multi-route runs (Route X of Y)
- Target event cache across routes

Code quality:
- Extract BlockMath, MirrorUtils, EventFilters, MirrorConfig
- Add 45 unit tests across 3 test files
- Refactor mergeGapMin to computed property
- Make log editor read-only

Build:
- Bump version to 1.4.0 (build 18)
- Add LSMinimumSystemVersion 15.5
v1.4.0
2026-05-27 11:00:18 +02:00
tomas.kracmar fe9e813583 Release 1.3.9 v1.3.9 2026-04-09 15:55:09 +02:00
tomas.kracmar cdf82b99cc Release 1.3.8 v1.3.8 2026-04-08 11:56:01 +02:00
tomas.kracmar 2912d2f52a Release 1.3.7 v1.3.7 2026-03-24 10:36:44 +01:00
tomas.kracmar a838e021a1 Docs: refresh README and roadmap 2026-03-13 09:12:19 +01:00
tomas.kracmar f81403745c Release 1.3.6 v1.3.6 2026-03-13 09:08:31 +01:00
tomas.kracmar 58d88e9fa5 Release 1.3.4 v1.3.4 2026-03-13 06:56:46 +01:00
tomas.kracmar 3ecf29f499 1.3.1: fix auto-delete of missing-source mirrors; bump version; add release notes v1.3.1 2025-10-13 11:43:01 +02:00
tomas.kracmar eb643ac74d Version update 2025-10-10 10:00:57 +02:00
tomas.kracmar df06564434 BusyMirror 1.3.0: add Mark Private option (global + per-route); version bump and release notes v1.3.0 2025-10-10 09:58:05 +02:00
tomas.kracmar 74b9949610 BusyMirror 1.2.6: always enable Mirror Now when calendars accessible; route/manual decided at runtime v1.2.6 2025-10-10 09:08:26 +02:00
tomas.kracmar 6676e62889 BusyMirror 1.2.5: Mirror Now enables for routes or manual; add computed canRunMirrorNow; version bump v1.2.5 2025-10-10 08:59:59 +02:00
tomas.kracmar d1fbd4c81f BusyMirror 1.2.4: enable Mirror Now when routes exist; version bump v1.2.4 2025-10-10 08:52:41 +02:00
tomas.kracmar 6ef0feecc1 BusyMirror 1.2.3: reliable settings autosave/restore; remember source/target; @MainActor fixes; reinit EKEventStore after grant; Makefile; changelog + release notes v1.2.3 2025-10-10 08:34:07 +02:00
tomas.kracmar aac4de3fb3 BusyMirror 1.2.1: fix calendar loading after grant, attendee status filter, main-actor; add Makefile v1.2.1 2025-10-10 07:45:59 +02:00
tomas.kracmar 8f80a5f672 Adding source events filtering 2025-09-29 18:06:34 +02:00
tomas.kracmar ae40b42e6f Bump version v1.2.0 2025-09-29 17:52:18 +02:00
tomas.kracmar 691575c554 Adding support to save routes v1.1.0 2025-09-29 15:31:11 +02:00
tomas.kracmar b931f3ba2c Fixed building 2025-09-29 15:18:42 +02:00
tomas.kracmar 53f21492da Fixes 2025-09-29 13:30:45 +02:00
tomas.kracmar 37328eeae2 Added XCode project files v1.0.0 2025-08-23 15:43:03 +02:00
tomas.kracmar 3ac1faa3dc Initial commit 2025-08-23 15:39:57 +02:00
tomas.kracmar d6c04b9d90 Initial commit 2025-08-23 13:32:37 +00:00