Make synced vaults functional end-to-end by driving the push-only sync
engine from the providers and the composition root:
- SyncedVaultFilesystemProvider: disk tree + CRUD (extends
LocalFilesystemProvider), reconciling each mutation through the engine
(pushFile on create/copy, sync on rename/delete).
- SyncedVaultDocumentsProvider: opens files via the live Automerge session
(multiplayer over libp2p), resolving disk path -> Habitat URI from the
snapshot (pushing first if new), pulling latest on open, and mirroring
session edits back to disk. The session factory is injected (DI) so the
module stays free of the libp2p runtime and is testable.
- engine.ts: add noteMirroredFile() so mirrored in-app edits aren't
re-pushed as phantom external changes.
- registry.ts: persist OpenVault.rootUri.
- App.tsx: provision a synced vault's root directory record on first open,
construct the per-vault engine stack, run the first-mount sync(), and
wire the two synced providers (acquireSession = real acquireDocSession).
Testing uses fakes over mocks: extract InMemoryHabitatRepo +
NodeFilesystemApi to src/vault/testing/fakeHabitat.ts and add a
FakeDocSession sharing one in-memory doc store with the repo. The provider
test runs the real engine/detector/snapshot manager against the fakes and
asserts on real state (on-disk files, snapshot, doc store) — no vi.mock.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
loadAutomergeDoc captured entry.doc before awaiting the PDS fetch. A
concurrent applyChange during that await marked the captured reference
stale (Automerge progressDocument sets state.heads), so the resumed
loadIncremental threw "Attempting to change an out of date document".
Fix: load into a fresh Automerge.init({ actor }) and reconcile any
in-flight local changes after the await via Automerge.merge(result.doc,
entry.doc). Applied to initSession, reinitSession, and resyncEntry.
mergeAllEdits now returns the final doc reference (MergeEditsResult) so
loadAutomergeDoc threads through a valid (non-stale) doc.
Adds a TODO for a regression test, and TESTING.md documenting the
Vitest/Automerge WASM config.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the vault core sync algorithms on top of the phase 1 foundation:
- change-detection.ts: split detection into local-only (steady state,
no network) and remote-tree (first-open clone only). Removes the
per-file remote head-comparison.
- engine.ts: VaultSyncEngine. sync() does a one-time remote clone on
first mount, then is push-only. Adds per-file openFile() (pull on
open) and pushFile() (push on save), so steady-state cost is
proportional to what the user touched rather than the whole tree.
- move-detection.ts: rename detection by content similarity.
- habitat-repo.ts: implement create() via createAutomergeDoc.
- types.ts/snapshot.ts: supporting types and snapshot wiring.
- App.tsx: TODO to run a top-level sync on first vault mount.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract docSession module-level state (ydocRegistry, titleListeners,
visibilityListenerInstalled) into a DocSessionRegistry class. Tests now
instantiate a fresh registry per test instead of calling a test-only
reset function exported from production code. The module-level
acquireDocSession/subscribeEntryTitleChanges wrappers delegate to a
default singleton so no callers change.
Also fix Vitest picking @automerge/automerge's browser entry (base64
WASM, OOMs) by externalising the package and passing --conditions=node
to forked workers so Node picks the disk-loading entry instead.
Remove importOriginal() from habitatDocumentsProvider.test.ts to avoid
pulling in libp2p's native addon during mock setup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lays the groundwork for Obsidian-style vaults backed by Habitat PDS +
libp2p gossipsub. Adds types, HabitatRepo/DocHandle adapter over
AutomergeDocSession, VaultSnapshotManager, vault registry, and utility
modules (content hashing, text diff, move detection similarity, directory
traversal). Also pulls forward collection-aware routing in automergeDoc.ts
and adds changeAt to AutomergeDocSession.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>