Per-file cloud sync + plugin framework primitives (storage + inline mounts)#45
Merged
Conversation
Foundational framework work for per-file cloud sync (and the plugin ecosystem generally). No behavior change yet — the mount points render nothing until a plugin contributes. - storage.ts: getPluginStore(id) — schema-less KV scoped to a plugin in its own IndexedDB DB (dove-plugin-<id>), fully decoupled from core dbUtils/DB_VERSION. Also exposed as ctx.storage in PluginContext. - mounts.ts + PluginMount.tsx: inline mount framework. Plugins contribute components to a MountSlot; <PluginMount slot ctx> renders them error- boundaried + Suspense-wrapped, or nothing when none. Sibling to the panel framework (cards) for injecting raw components into core UI. - FilesTab wires two mount points: MountSlot.FileRow (per file) and MountSlot.FileManagerSection (under the list). - Tests for the getMounts selector; registry test mock updated for ctx.storage. https://claude.ai/code/session_01QF56Xjp5ZMgXrqfTWD14Le
Coverage SummaryLines: 14.56% (1493/10250) · Statements: 13.86% · Functions: 10.12% · Branches: 10.59% Per-file coverage
|
Builds on the Phase A primitives. Files are now individually selectable for sync, modeled on the device track-sync UX; opt-in, off by default. - fileSync.ts: selection state in the plugin's own KV store (getPluginStore), with a pure, tested fileSyncStatus (off/pending/synced). - FileSyncToggle.tsx: a FileRow mount — per-file toggle that selects + pushes (or records intent when offline/signed-out). Lazy-loaded (its own chunk). - syncEngine: pushAll now uploads garage docs + only *selected* files; new pushFile for a single toggle; pulled files are marked synced. - index.ts contributes the FileRow mount (lazy, cloud-gated) alongside the panel. - Docs: plugins/README gains storage + inline-mount authoring sections; CLAUDE.md + CHANGELOG updated. https://claude.ai/code/session_01QF56Xjp5ZMgXrqfTWD14Le
Completes the per-file sync UX. Files that exist in the cloud but not on this device are listed under the file manager (via the FileManagerSection mount), each with a one-click pull. Pulling persists through ctx.onSaveFile, which refreshes the list, so the file moves out of the cloud-only section into the list automatically. - syncEngine: listCloudFiles + downloadCloudFile. - fileSync: cloudOnlyNames pure helper (+ tests). - CloudFilesSection.tsx: the section mount (lazy, cloud-gated, signed-in only). - CloudSyncPanel copy updated to reflect selective push. - modified detection + "sync all" remain follow-ups. https://claude.ai/code/session_01QF56Xjp5ZMgXrqfTWD14Le
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.
Summary
Lets users individually choose which files sync to the cloud from the file manager (modeled on the device track/course sync UX), and adds the plugin-framework primitives that make it possible.
Per-file sync is opt-in, off by default; gated by
VITE_ENABLE_CLOUDlike the rest of cloud sync; fully offline-first (toggling offline records intent and uploads on reconnect).Phase A — framework primitives (no behavior change on their own)
plugins/storage.ts):getPluginStore(id)gives a plugin a schema-less KV store in its own IndexedDB DB (dove-plugin-<id>), fully decoupled from coredbUtils/DB_VERSION. Also surfaced asctx.storage.plugins/mounts.ts+PluginMount.tsx): sibling to the panel framework. Plugins contribute aPluginMountDefto aMountSlot;<PluginMount slot ctx>renders them error-boundaried +Suspense-wrapped, or nothing when no plugin targets the slot.FilesTabexposesMountSlot.FileRow(per file) andMountSlot.FileManagerSection(under the list).Phase B — per-file cloud sync
cloud-sync/fileSync.ts: per-file selection state in the plugin's KV store + a pure, testedfileSyncStatus(off→pending→synced).cloud-sync/FileSyncToggle.tsx: aFileRowmount — the per-file toggle (lazy chunk, ~1.3 kB).syncEngine:pushAlluploads all garage docs but only the selected files; newpushFilefor a single toggle; pulled files are marked synced.Phase C — cloud-only files inline
cloud-sync/CloudFilesSection.tsx: aFileManagerSectionmount listing files that are in your cloud but not on this device, each with a one-click pull. Pulling persists viactx.onSaveFile(which refreshes the list), so the file moves into the list automatically.syncEngine:listCloudFiles+downloadCloudFile;cloudOnlyNamespure helper (tested).CloudSyncPanelcopy updated to reflect selective push.Deferred (follow-ups)
modifieddetection (file blobs are immutable so this is low-value for files) and a "sync all / select all" convenience.Docs
plugins/README.md(storage + inline-mount authoring sections),CLAUDE.md,CHANGELOG.md.Test plan
npm run lint,npm run typecheck,npm run test:run(303 passing),npm run buildall green locallygetMountsselector;fileSyncStatusstates;cloudOnlyNamesVITE_ENABLE_CLOUD=truebuild): toggle a file on while signed in → uploads + shows synced; toggle while offline → pending, uploads on reconnect; toggle off → stops syncing (cloud copy kept); a file synced from another device appears under "Available in cloud" and pulls into the list in one clickhttps://claude.ai/code/session_01QF56Xjp5ZMgXrqfTWD14Le