From f18ea4fea701302bee4489f0d0ec065f71c670b7 Mon Sep 17 00:00:00 2001 From: Alejandrina Gonzalez Date: Fri, 4 Sep 2026 18:31:14 -0400 Subject: [PATCH] Restore locally deleted files during sync --- src/syncEngine.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/syncEngine.ts b/src/syncEngine.ts index 816414c..c7fbb82 100644 --- a/src/syncEngine.ts +++ b/src/syncEngine.ts @@ -111,16 +111,29 @@ export async function runDeviceSync( const listings: DeviceNoteListing[] = deviceFiles.map((f) => ({ uri: f.uri, date: f.date, size: f.size })); const patterns = parsePathFilters(settings.syncPathFiltersRaw); const plan = planSync(listings, settings.noteSyncState, patterns); + // A device listing can be unchanged while its vault copy was deleted. + // Restore those files from the unchanged bucket; a missing file is safe to + // create, unlike a present file whose hash no longer matches the manifest. + const toSync = [...plan.toSync]; + const unchanged: DeviceNoteListing[] = []; + for (const listing of plan.unchanged) { + const record = settings.noteSyncState[listing.uri]; + if (record && await currentHash(app, record.vaultPath) === null) { + toSync.push(listing); + } else { + unchanged.push(listing); + } + } const result: DeviceSyncResult = { synced: 0, - unchanged: plan.unchanged.length, + unchanged: unchanged.length, excluded: plan.excluded.length, skippedConflicts: [], failed: [], }; - for (const listing of plan.toSync) { + for (const listing of toSync) { try { const deviceFile = deviceFiles.find((f) => f.uri === listing.uri); if (!deviceFile) continue; // Listing changed between the scan and here; pick it up next run. @@ -161,16 +174,16 @@ export async function runDeviceSync( } } - // The loop above only ever looks at plan.toSync — files the *device* + // The loop above only ever looks at toSync — files the *device* // reports as new or changed. A file the user edited locally (in the // vault, or directly on disk) whose device counterpart hasn't changed // would otherwise go completely unnoticed: nothing threatens to // overwrite it, but nothing flags the drift either, until the device - // copy eventually changes too and the file re-enters plan.toSync. Since + // copy eventually changes too and the file re-enters toSync. Since // this only reads vault-local files (no device/network round-trip — the // actual cost planSync's change detection avoids), it's cheap enough to // check on every run rather than waiting for that. - for (const listing of plan.unchanged) { + for (const listing of unchanged) { const record = settings.noteSyncState[listing.uri]; if (!record) continue; // 'unchanged' implies a record exists; defensive only.