Desktop app (Phase 2): Tauri sync control center + converter GUI, release CI, website - #1
Merged
Conversation
- inkterop.sync package: rules (allow/block/rename/format overrides in
rules.toml), sources (reMarkable cache, note-file folders, experimental
GoodNotes/Notability container scanners with deadline-guarded walks),
sinks (pdf/svg/png/inkz via the registry writers; atomic multi-file
moves), engine (generalized mirror with v2 state + v1 migration),
daemon (JSON-RPC over stdio for the desktop app; no network surface).
- mirror.py is now a thin back-compat wrapper; launchd daemon unchanged.
Real-library check: pass after migration is a clean 39/39 no-op, and
filenames keep the old verbatim naming (':' preserved on mac).
- config: [sync] default format, [sources.*]; tomlkit round-trip writes.
- CLI: inkterop sync + inkterop daemon.
- 23 new tests (engine/rules/sources/daemon incl. subprocess pipe smoke);
full suite 389 green, goldens untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eviews - Rust shell: sidecar daemon manager (stdio JSON-RPC bridge, auto-restart, clean EOF shutdown), tray menu (open/sync/pause/quit), close-to-tray with macOS accessory policy, dialog/opener/autostart plugins. - Library view: Finder-style Miller columns (sources > folders > notes > preview pane), thumbnail grid, and details list — shared inspector with allow/block, rename, destination and per-note format controls; folder sync toggles at every level; breadcrumbs + view-mode toggle. - Convert view: drag-and-drop (or picker) -> any writer format with fidelity choice; experimental writers routed through --experimental. - Settings: output dir, scope, sources incl. watched folders, page sizing/pen style, autostart, close-to-tray. Activity: live event log. - core fixes found by driving the real app: Library reload race under concurrent thumbnail RPCs (source-level lock), pdfium global lock (not thread-safe), watcher pid-lockfile so app + launchd daemon can't double-sync, root folder '.' -> ''. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… landing page M3 (packaging/releases): - core/packaging: PyInstaller spec + entry + build-sidecar.sh (freezes the engine into app/src-tauri/binaries/inkterop-daemon-<triple>; JSON-RPC ping smoke test). Local release verified end-to-end: the bundled Inkterop.app runs the frozen sidecar with no uv/python dependency; .dmg produced (35MB). - .github/workflows/release.yml: v* tags -> macOS arm64 (signs+notarizes once Apple secrets exist), Windows + Linux community builds, draft GitHub Release via tauri-action. Secrets + cask recipe + version-bump checklist in app/RELEASING.md. - app: dev placeholder sidecar auto-created (ensure-sidecar.mjs), real binaries gitignored; Settings gains legacy launchd-daemon migration (detect com.inkterop.watch, one-click disable). M4 (website/docs): - website/: static landing page (hero, features, downloads wired to the GitHub releases API, brew snippet, format matrix), light/dark. - Pages restructure: landing at the root, mkdocs under /docs/ — docs.yml assembles both into one artifact; mkdocs site_url updated; verified locally (strict build green, combined tree served and spot-checked). - CLAUDE.md: sync module/app/website layout + commands; 'no heavy deps' rule removed (rescinded by maintainer). ROADMAP Phase 2 marked done. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…erywhere, search, icons, sort, convert/open actions
Per maintainer feedback:
- Sync History page: persisted pass table (when/result/changed/duration/
trigger, expandable failures; history.json capped at 200) + live event
feed. Sync Now navigates there; the bottom-left status is now a
clickable 'synced Xm ago' link.
- 'blocked' renamed to 'excluded' and every status carries a hover
explanation ('annotated PDFs are off in Settings', 'folder X is turned
off', 'synced 5m ago', ...). Engine now returns machine reason codes.
- Explicit note/folder allows OVERRIDE the scope toggles, so checking a
PDFs-only folder (Books/Music) just works — verified live: Books on ->
2 book PDFs render; reason codes and folder-status aggregate icons all
correct. (Root cause of the 'can't toggle Books' report.)
- Folders AND notes both get a sync checkbox (left) + status icon
(right); custom SVG icon set replaces emoji (folder/tablet/note/book/
status glyphs); kind is visible (book icon + 'annotated PDF' tooltip).
- Toolbar search + status filter (flat results across folders).
- List mode: sortable columns (name/status/pages/format/modified/output).
- Inspector: Convert-to-another-format (hands the note to the Convert
view; works for library docs via uuid), Open synced output, Open
original file (folder-source docs), Reveal in Finder.
- 392 tests green; sidecar rebuild + release bundle verified on the
real library.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sync on rule changes Root causes of the 'pending forever with no explanation' report, fixed: - Rule/config changes now trigger a debounced sync pass (trigger: 'settings') — previously only SOURCE file changes woke the watcher, so a toggled checkbox sat pending until the library happened to change. - Per-doc failures are persisted (state entry keeps error + failed_mtime) and surface as a real 'failed' status whose tooltip and inspector show the actual error; retried automatically each pass, cleared on success. - Sync History pass rows expand to per-file results: synced -> outputs (+ per-file duration), failed -> error message. Status icons and the inspector status badge are clickable links to Sync History. Maintainer decision: annotated PDFs/EPUBs don't sync at all until the base-page merge exists (handwriting-only output is useless). Engine hard-excludes them (reason 'unsupported-kind', nothing overrides it), UI grays them with disabled checkboxes + book icon + explanatory tooltips, Settings drops the pdf/epub toggles. Folders containing only PDFs (Books/Music) show a disabled checkbox explaining why. Verified live on the release bundle: uncheck Calibration -> settings- triggered pass removes the PDF in ~4s; recheck -> re-rendered; history shows 'Calibration -> Calibration.pdf (0.03s)' in the expanded pass; stale Books allow-rule cleaned up automatically. 394 tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Phase 2, shipped bigger than the roadmap's menu-bar-only plan — a full desktop app that is both a sync control center and a GUI over the converter, plus everything needed to distribute it:
core/src/inkterop/sync/— multi-source/multi-sink engine generalizing the mirror:rules.py(per-note/folder allow/block, rename, destination, format overrides inrules.toml),sources.py(reMarkable cache, watched note-file folders, experimental GoodNotes/Notability container scanners with deadline-guarded walks),sinks.py(pdf/svg/png/inkz via the registry writers, atomic multi-file moves),engine.py(v2 state with v1 migration, per-doc error persistence, history log, watcher pid-lock),daemon.py(stdio JSON-RPC for the app — no network surface).mirror.pyis now a thin back-compat wrapper; the launchd daemon keeps working.app/— Tauri 2 + React. Library browser (Finder-style columns / thumbnail grid / sortable details list, first-page previews, search + status filter), per-note/folder sync checkboxes with status icons and hover explanations, Sync History page with per-file diagnostics, drag-and-drop Convert view (also reachable from any library note), Settings, tray with sync controls, one-click migration off the legacy launchd agent. Release bundles run a PyInstaller-frozen sidecar; dev mode runs the live Python tree via uv.release.ymlbuilds macOS (signs+notarizes onceAPPLE_*secrets land — seeapp/RELEASING.md), Windows, Linux onv*tags into a draft GitHub Release. Homebrew cask recipe documented.website/landing page at the Pages root; mkdocs docs move under/docs/(single workflow assembles both).Why
Original goal #4/#5 (hands-off sync into normal PDFs) had no UI: no way to see what synced, pick notes, or diagnose failures. This adds that, and turns the one-off converter into something a non-CLI user can use.
Reviewer notes
:on APFS). State file migrates v1→v2 in place; old daemons rewriting v1 state self-heal on the next pass.settingssync pass — that plus persisted per-doc errors fixes the "pending forever with no explanation" class of bug.mkdocs build --strictgreen.website/screenshot.png, pick an app icon, then tagv0.1.0.🤖 Generated with Claude Code