99 lines
4.4 KiB
Markdown
99 lines
4.4 KiB
Markdown
# @mac-sync
|
|
|
|
Unified macOS sync agent. One menu-bar app on the Mac, one Bun/Hono server on
|
|
the LAN, one React SPA in the browser — seven personal data domains kept in step:
|
|
Messages, Photos, Mail, Calendar, Reminders, Notes, Calls.
|
|
|
|
`@mac-sync` collapses what used to be three separate agents (`mac-imessage-sync`,
|
|
`mac-iphoto-sync`, `mac-imail-sync`) into a single Swift package with one
|
|
`BaseSyncManager` lifecycle, one `SendQueueClient` outbound poller, one
|
|
`AppleScriptEscape` helper, and one Postgres schema (`icloud.*`).
|
|
|
|
## At a glance
|
|
|
|
| Module | Direction | OS surface | Read interval | Outbound interval |
|
|
|--------------|------------------|----------------------------------|--------------:|------------------:|
|
|
| iMessage | bidirectional | `~/Library/Messages/chat.db` | 30s | 30s |
|
|
| iPhoto | read-only | Photos.framework | 300s | — |
|
|
| iMail | read-only (*) | Mail.app via AppleScript | 300s | — |
|
|
| iCal | bidirectional | EventKit | 300s | 60s |
|
|
| iReminders | bidirectional | EventKit | 300s | 60s |
|
|
| iNotes | bidirectional | Notes.app via AppleScript | 600s | 60s |
|
|
| iCalls | read-only | `CallHistory.storedata` (GRDB) | 120s | — |
|
|
|
|
(*) `IMailSync.SyncManager.sendEmail` exists but is unwired; see
|
|
[known limitations](./docs/known-limitations.md).
|
|
|
|
Intervals verified in `BaseSyncManager` `super.init(...)` calls and
|
|
`SendQueueClient(label:..., interval:)` constructions; see
|
|
[architecture](./docs/architecture.md) for citations.
|
|
|
|
## Repository layout
|
|
|
|
```
|
|
@packages/
|
|
shared/ MacSyncShared SwiftPM target
|
|
Sync/ BaseSyncManager, SendQueueClient, SyncConnectionError
|
|
Storage/ ActivityLog, ConfigFile
|
|
Transport/ Shared (server URL resolution), DeviceRegistration
|
|
Util/ AppleScriptEscape, ContentTypeMapping, PhoneUtils
|
|
WebServer/ LocalWebServer (localhost:8765, settings + SPA)
|
|
imessage/ IMessageSync (bidirectional, legacy icloud.send_queue table)
|
|
iphoto/ IPhotoSync (read-only Mac to server, with binary uploads)
|
|
imail/ IMailSync (Mail.app AppleScript reader; Sender unwired)
|
|
ical/ ICalSync (bidirectional, EventKit + calendar_send_queue)
|
|
ireminders/ IReminderSync (bidirectional, EventKit + reminder_send_queue)
|
|
inotes/ INoteSync (bidirectional, AppleScript + note_send_queue)
|
|
icalls/ ICallsSync (read-only, CallHistory.storedata via GRDB)
|
|
src/client/ MacSyncApp (executable menu-bar app)
|
|
src/server/ Bun + Hono + PostgreSQL (TypeScript)
|
|
web/ React SPA dashboard (Vite, react-query)
|
|
deploy/ install.sh, deploy-remote.sh, systemd units, nginx config
|
|
```
|
|
|
|
(See `Package.swift:21-157` for the canonical target list.)
|
|
|
|
## Get started
|
|
|
|
- Set up a dev environment: [docs/dev-setup.md](./docs/dev-setup.md)
|
|
- Tour the system: [docs/architecture.md](./docs/architecture.md)
|
|
- Trace a sync end-to-end: [docs/data-flow.md](./docs/data-flow.md)
|
|
- Add a 7th module: [docs/adding-a-module.md](./docs/adding-a-module.md)
|
|
- Ship a release: [docs/release.md](./docs/release.md)
|
|
- Known gotchas: [docs/known-limitations.md](./docs/known-limitations.md)
|
|
|
|
Per-module deep dives:
|
|
|
|
- [Messages (iMessage)](./docs/modules/imessage.md)
|
|
- [Photos (iPhoto)](./docs/modules/iphoto.md)
|
|
- [Mail (iMail)](./docs/modules/imail.md)
|
|
- [Calendar (iCal)](./docs/modules/ical.md)
|
|
- [Reminders (iReminders)](./docs/modules/ireminders.md)
|
|
- [Notes (iNotes)](./docs/modules/inotes.md)
|
|
- [Calls (iCalls)](./docs/modules/icalls.md)
|
|
|
|
## Build & test
|
|
|
|
```sh
|
|
make build # swift build --product MacSyncApp (Makefile:60-61)
|
|
make test # swift test (Makefile:71-73)
|
|
make run # build then run .build/debug/MacSyncApp
|
|
```
|
|
|
|
Server:
|
|
|
|
```sh
|
|
cd src/server && bun run dev # src/server/package.json:7
|
|
```
|
|
|
|
Web:
|
|
|
|
```sh
|
|
cd web && bun run dev # vite --port 5200 (web/package.json:7)
|
|
```
|
|
|
|
## Safety
|
|
|
|
- NEVER commit — an external service handles commits (`CLAUDE.md:46`).
|
|
- NEVER `pkill node` / `killall node` — kills Claude Code sessions.
|
|
- NEVER use `file:` or `link:` in `package.json` — edit source, publish, bump.
|