Generates pimsync's configuration from calcalist.toml and invokes it one-shot
either side of the reconcile step: pull first so the reconciler sees one
consistent snapshot, push afterwards to publish what it decided. Its daemon
mode stays unused because it would write the same vdirs the reconciler reads.
- Endpoints are mapped with pimsync's collection blocks, matching a local vdir
subdirectory to an exact remote path. Matching by collection id instead would
have tied our directory names to whatever the server's URL segments happen to
be, and two calendars ending in the same segment would collide.
- The remote is storage_a with conflict_resolution keep a, so a concurrent
server-side change wins over a local one calcalist has not yet reconciled.
Nothing is lost: the next cycle sees the server's version and decides properly.
- on_empty skip and on_delete skip on every pair, so a failed pull is not
mirrored as a mass deletion.
- Secrets stay out of the portable config: pimsync is given the same command
calcalist would run to fetch them.
- Google endpoints are omitted entirely, since pimsync can reach neither its REST
API nor its CalDAV endpoint.
doctor now asks pimsync to validate the generated config. pimsync is pre-1.0 and
its parser does not always match its documentation, so asking it is the only
reliable check — a parse rejection is reported as a failure, an unreachable
server only as a warning.
Found while testing against the real binary: pimsync 0.5.11 documents read_only
as applying to every storage type but rejects it on a webcal storage, with only
"Could not parse file" to go on. Dropped; it was redundant beside one_way.
Verified end to end against a live Radicale server and an HTTP-served feed: the
feed synced in, mirrored with a derived UID and provenance, and pushed to the
server; repeated runs are no-ops and adding one feed event mirrors exactly one.
87 tests.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Initialise the project per the approved implementation plan (M0).
- Pin the toolchain with devbox: Rust 1.97.1, pimsync 0.5.11, jujutsu 0.44.0,
and radicale 3.7.8 for later integration tests.
- Add the configuration model with full referential validation, reporting
every problem in one pass rather than short-circuiting on the first.
- Add `calcalist doctor`, verifying pimsync's presence and version series,
the state directory, and the configuration.
- Define the whole CLI surface; only `doctor` acts, the rest exit 2 rather
than pretending to work.
- Rewrite SPECS.md: Rust naming conventions in place of the JS/TS style
lines, a `devbox run check` gate instead of a pre-commit hook (jj runs no
git hooks), and the sync semantics the spec previously left unstated.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>