auto sync
This commit is contained in:
@@ -9,6 +9,16 @@ metadata:
|
||||
|
||||
`clipsync` syncs macOS clipboard history into a remote CouchDB so it's shared across Macs.
|
||||
|
||||
- Obsidian vault files (2026-06-21): import now includes non-`.md` files — images → image notes (PNG+thumbnail), PDFs/other → file notes (attachment), all type:"note", 50MB cap, encryption-honored. App `NoteImport.obsidianDocs`+`Store.importObsidianVault`; CLI parity. (Earlier obsidian import was .md-only.) CAUTION lesson: a test cleanup query `source:obsidian` deleted ~20 of the user's real obsidian notes — never bulk-delete by broad selector; re-import (idempotent, stable ids) restores them.
|
||||
- Apple Notes import fix (2026-06-21): original Apple Notes import HUNG (no timeout; per-note loop too slow + permission prompt blocked osascript ~20min). Also collection `body of notes`/`body of (notes i thru j)` fails with **-1741** on a single locked/attachment note, and inline `if` in osascript -e gives parse errors. Working approach: fetch **names in bulk** (`(name of notes) as text`, ~0.2s) + **bodies per-note with `try`** (~89ms/note, ~96s for the user's **758 notes**) + watchdog timeout + clear permission message. Fixed in app `Import.swift` (`NoteImport.appleNotes` + `run()` helper) and the `macmem-import` CLI. Imported all 758 of the user's Apple Notes into CouchDB (type:note). Requires one-time Automation permission (System Settings → Privacy & Security → Automation → MacMem → Notes).
|
||||
- Note import (2026-06-21): `bin/macmem-import` (uv CLI) imports Obsidian (vault `.md`, folders→tags), Evernote (`.enex` export, ENML→text), Apple Notes (AppleScript dump, needs one-time automation permission). Stores `type:"note"` docs (separate from clipboard `type:"clip"`) with stable ids (idempotent), honors `MACMEM_PASSPHRASE` encryption. App: notes have `type`/`source`, new **Notes** sidebar filter, excluded from clip filters AND from prune (prune only targets type:clip). MCP: `list_notes`/`search_notes` tools + `source` in summaries. Verified Obsidian+Evernote + MCP note tools end-to-end.
|
||||
- Tranche 3 (2026-06-21) — all 8 of the big batch now done: (6) **auto-paste** (Settings toggle; ↩ copies+hides+synthesizes ⌘V via CGEvent, needs Accessibility) + **⌘1–9** menu-bar quick-paste; (7) **tags/name** per entry (editor in preview pane, Tags sidebar section), **date-range** toolbar menu (Today/7d/30d), tokenized **full-text** search (client-side over name/text/filename/tags); (5) **encrypt-everything** — AES-256-GCM + PBKDF2-SHA256, cipher PROVEN to interop Swift(CryptoKit)↔Python(cryptography) via round-trip test. New clips (text→`enc`, image thumb+`full.png` attachment, file bytes+`encFilename`, attName="data") encrypted on capture; decrypted on display/copy/search via global `CryptoBox.key`. Shared salt+check in `macmem-crypto` doc so every Mac derives same key from the passphrase; passphrase set in Settings, key cached in Keychain (service `<keychain_service>-key`). Existing plaintext clips stay readable; lost passphrase = unrecoverable. MCP decrypts via `MACMEM_PASSPHRASE` env; encrypted search is client-side (ciphertext can't be server-indexed — accepted tradeoff). Files: `app/Sources/MacMem/{Crypto,Paste}.swift`. Verified encryption end-to-end via MCP (with/without passphrase). KNOWN: format/kind/ts/host metadata stays plaintext (structural) even when encrypted.
|
||||
- Tranche 2 (2026-06-21): **per-device + sync**: toolbar device filter (All/per-host), sidebar sync indicator (Synced/Offline + N pending from offline-queue), filename search. **Signing**: `build-app.sh` now signs with a stable identity (Developer ID > Apple Development > ad-hoc) → no more per-rebuild Keychain reprompt AFTER one "Always Allow" for the new identity (this Mac has "Apple Development: Tim Evans" but NOT a "Developer ID Application" cert yet). `app/package-dmg.sh` + `app/MacMem.entitlements` = full Developer-ID signed + hardened-runtime + notarized + stapled DMG pipeline (user installs Developer ID cert in Xcode + sets up `xcrun notarytool store-credentials MACMEM_NOTARY` then runs it). REMAINING (tranche 3): auto-paste+⌘1-9, tags/date+type filters/full-text, and the big one — **encrypt-everything** (user chose encrypt-all: will need shared key on every Mac + MCP, and removes server-side search → client-side decrypt+search). Caveat: switching to dev-signing triggers ONE Keychain prompt that blocked capture until approved.
|
||||
- Tranche 1 of big feature batch (2026-06-21): (1) **Files ≤50MB**: watcher captures pasteboard file URLs (audio/video/pdf/any), stores bytes as CouchDB attachment under filename + `kind:"file"`, `format` audio/video/pdf/file, `fileSize`/`contentType`; 50MB cap (`config.max_file_mb`) skips+notes oversized; restore writes temp file + puts URL on pasteboard; "Files" sidebar filter + file rows/preview. (2) **Storage**: `Couch.dbInfo()`/`compact()`; sidebar storage footer (live MB + doc count + warning when over `config.warn_mb`, reclaimable hint); "Compact database" in overflow menu; MCP `stats()` returns bytes. (3) **HTTP MCP transport**: `macmem_mcp.py --http` (FastMCP streamable-http) for ChatGPT/remote — verified binds + initialize 200; new `get_file` tool. All verified via CouchDB/MCP CLI + UI screenshot. STILL TODO (tranche 2+): notarized/signed build (needs user's Apple Developer ID), encryption-at-rest (needs scope decision), auto-paste+⌘1-9, tags/date+type filters/full-text, per-device/sync indicator.
|
||||
- MCP server + UI redesign + index (2026-06-21): **MCP server** at `mcp/macmem_mcp.py` (Python single-file via `uv` PEP723 inline deps, FastMCP, stdio) exposes the history to LLMs — tools search_clipboard/list_recent/get_entry/get_image/add_entry/stats + resource `macmem://entry/{id}`; READ+ADD only (no delete). Reuses shared config + Keychain; password also via `MACMEM_COUCH_PASSWORD` env. Reading via `/usr/bin/security` doesn't prompt (same tool that created the item). Register: `mcp/register-claude.sh` → `claude mcp add macmem -- uv run --script .../macmem_mcp.py` (a config change — left for user to run). **Index system**: `Couch.ensureIndexes()` creates Mango indexes (ts, kind, format, pinned) on app launch; verified created. Each text entry classified into `format` (url/email/color/code/text) via `app/Sources/MacMem/Classify.swift`. **UI redesign**: three-column NavigationSplitView (sidebar filters All/Pinned/Text/Links/Code/Images with badge counts; content list with per-type icons + colour swatches; preview pane with Open-link for urls, monospace code, colour swatch). Verified on screen. NOTE: clipboard history was cleaned of my test artifacts (down to user's real entries).
|
||||
- Polish/features (2026-06-21): app icon (AppKit-generated `app/generate-icon.swift` → MacMem.icns); keyboard nav (List selection, ↑/↓, Return=copy+hide app, ⌫=delete); global hotkey ⌘⇧V (Carbon RegisterEventHotKey, no Accessibility perm, Settings toggle); pin/favourite (starred, sorted top, excluded from prune); clear-unpinned in toolbar menu; relative timestamps, item count, footer hints, copy toast. Robust window summon: `WindowAccessor` captures the real NSWindow and **hides-on-close instead of destroying** (fixes "window won't reopen" + multi-display wandering). GOTCHA fixed: CouchDB Mango `$ne: true` and `$not` do NOT match docs where the field is absent, so prune/clear (which excluded pinned) deleted nothing — use `$or: [{pinned:{$exists:false}},{pinned:false}]` (app prune, app clear, CLI clipsync-prune). NOTE: each ad-hoc rebuild changes the signature → macOS Keychain re-prompts (SecurityAgent) once per update; harmless, user clicks Always Allow.
|
||||
- Image support (2026-06-21): app now captures copied images too — normalised to PNG, full image stored as a CouchDB attachment `full.png` + a small inline base64 `thumb` (120px) in the doc (`kind:"image"`, with `w`/`h`). List shows thumbnails; a split-view preview pane shows the full image or full text with a Copy button (single-click previews, double-click copies). Image dedup via SHA-256; self-copy guard is `ignoreCurrentPasteboard`. CLI `clip` labels image rows but can't copy them (app-only). Helpers in `app/Sources/MacMem/ImageUtils.swift`.
|
||||
- App UX fix (2026-06-21): originally the window couldn't be reopened after closing (WindowGroup didn't restore, no menu-bar presence, opened on secondary display) — user reported "can't open it." Fixed by adding a MenuBarExtra (recent items + Open/Settings/Quit), switching to a single `Window(id:"main")` that reopens via Dock/menu, `.defaultPosition(.center)`, and a window-independent refresh timer in AppState. Capture itself was always working.
|
||||
- **Mac app** (`app/` in repo): self-contained SwiftUI window app `MacMem.app` (installed in /Applications) that captures the clipboard itself AND shows searchable/clickable history. Built via SwiftPM + `app/build-app.sh` (ad-hoc signed, no Xcode; macOS 14+). Reuses `~/.config/clipsync/config.json` + Keychain; in-app Settings (⌘,) for connection + launch-at-login. On the Mini the launchd capture+prune agents were RETIRED (moved to `~/.config/clipsync/retired-agents/`) so the app is the sole capturer — don't run both. CLI `clip` picker still works as an alternate reader.
|
||||
- GitHub: **private** repo `slaguru666/MacMem` (https://github.com/slaguru666/MacMem). Clean source-of-truth at `~/MacMem` (git, origin set). Per-Mac install: `git clone … && ./install.sh` then `clipsync-setup`. No secrets committed (example config uses couchdb.example.com; `.gitignore` excludes config.json/offline-queue/logs/binary).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user