obsyncd 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +920 -0
- package/dist/cli/commands/init.d.ts +8 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +104 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/status.d.ts +8 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +117 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +13 -0
- package/dist/cli/commands/sync.d.ts.map +1 -0
- package/dist/cli/commands/sync.js +225 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/prompts/conflictPrompt.d.ts +10 -0
- package/dist/cli/prompts/conflictPrompt.d.ts.map +1 -0
- package/dist/cli/prompts/conflictPrompt.js +51 -0
- package/dist/cli/prompts/conflictPrompt.js.map +1 -0
- package/dist/cli/prompts/fileBrowser.d.ts +6 -0
- package/dist/cli/prompts/fileBrowser.d.ts.map +1 -0
- package/dist/cli/prompts/fileBrowser.js +91 -0
- package/dist/cli/prompts/fileBrowser.js.map +1 -0
- package/dist/cli/prompts/vaultSelector.d.ts +13 -0
- package/dist/cli/prompts/vaultSelector.d.ts.map +1 -0
- package/dist/cli/prompts/vaultSelector.js +63 -0
- package/dist/cli/prompts/vaultSelector.js.map +1 -0
- package/dist/cli/ui/colors.d.ts +50 -0
- package/dist/cli/ui/colors.d.ts.map +1 -0
- package/dist/cli/ui/colors.js +62 -0
- package/dist/cli/ui/colors.js.map +1 -0
- package/dist/cli/ui/output.d.ts +45 -0
- package/dist/cli/ui/output.d.ts.map +1 -0
- package/dist/cli/ui/output.js +116 -0
- package/dist/cli/ui/output.js.map +1 -0
- package/dist/cli/ui/spinner.d.ts +29 -0
- package/dist/cli/ui/spinner.d.ts.map +1 -0
- package/dist/cli/ui/spinner.js +80 -0
- package/dist/cli/ui/spinner.js.map +1 -0
- package/dist/cli/ui/table.d.ts +28 -0
- package/dist/cli/ui/table.d.ts.map +1 -0
- package/dist/cli/ui/table.js +123 -0
- package/dist/cli/ui/table.js.map +1 -0
- package/dist/cli/utils/terminal.d.ts +21 -0
- package/dist/cli/utils/terminal.d.ts.map +1 -0
- package/dist/cli/utils/terminal.js +59 -0
- package/dist/cli/utils/terminal.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +32 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +45 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +112 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/index.d.ts +35 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +97 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/sync/changeDetector.d.ts +29 -0
- package/dist/sync/changeDetector.d.ts.map +1 -0
- package/dist/sync/changeDetector.js +259 -0
- package/dist/sync/changeDetector.js.map +1 -0
- package/dist/sync/conflictResolver.d.ts +29 -0
- package/dist/sync/conflictResolver.d.ts.map +1 -0
- package/dist/sync/conflictResolver.js +116 -0
- package/dist/sync/conflictResolver.js.map +1 -0
- package/dist/sync/directoryLister.d.ts +18 -0
- package/dist/sync/directoryLister.d.ts.map +1 -0
- package/dist/sync/directoryLister.js +39 -0
- package/dist/sync/directoryLister.js.map +1 -0
- package/dist/sync/index.d.ts +29 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +212 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/manifest.d.ts +48 -0
- package/dist/sync/manifest.d.ts.map +1 -0
- package/dist/sync/manifest.js +137 -0
- package/dist/sync/manifest.js.map +1 -0
- package/dist/sync/types.d.ts +109 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +5 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/sync/watchMode.d.ts +84 -0
- package/dist/sync/watchMode.d.ts.map +1 -0
- package/dist/sync/watchMode.js +364 -0
- package/dist/sync/watchMode.js.map +1 -0
- package/dist/sync/watcher.d.ts +114 -0
- package/dist/sync/watcher.d.ts.map +1 -0
- package/dist/sync/watcher.js +293 -0
- package/dist/sync/watcher.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +25 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/vault/index.d.ts +38 -0
- package/dist/vault/index.d.ts.map +1 -0
- package/dist/vault/index.js +106 -0
- package/dist/vault/index.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Change detection using three-way merge algorithm.
|
|
3
|
+
* Compares source, destination, and base (last sync state) to detect changes.
|
|
4
|
+
*/
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { computeFileHash } from '../utils/index.js';
|
|
8
|
+
export class ChangeDetector {
|
|
9
|
+
sourceAdapter;
|
|
10
|
+
destAdapter;
|
|
11
|
+
constructor(sourceAdapter, destAdapter) {
|
|
12
|
+
this.sourceAdapter = sourceAdapter;
|
|
13
|
+
this.destAdapter = destAdapter;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Detect all changes between source and destination using three-way merge.
|
|
17
|
+
* @param sourcePath - Source vault path
|
|
18
|
+
* @param destPath - Destination vault path
|
|
19
|
+
* @param sourceManifest - Source manifest (base state)
|
|
20
|
+
* @param destManifest - Destination manifest (base state)
|
|
21
|
+
* @param fileList - List of files to check (from vault listing)
|
|
22
|
+
*/
|
|
23
|
+
async detectChanges(sourcePath, destPath, sourceManifest, destManifest, fileList) {
|
|
24
|
+
const changes = [];
|
|
25
|
+
const processedFiles = new Set();
|
|
26
|
+
// Process all files in current file list
|
|
27
|
+
for (const relativePath of fileList) {
|
|
28
|
+
processedFiles.add(relativePath);
|
|
29
|
+
const sourceFilePath = path.join(sourcePath, relativePath);
|
|
30
|
+
const destFilePath = path.join(destPath, relativePath);
|
|
31
|
+
// Get current states
|
|
32
|
+
const sourceState = await this.getFileState(sourceFilePath, this.sourceAdapter);
|
|
33
|
+
const destState = await this.getFileState(destFilePath, this.destAdapter);
|
|
34
|
+
// Get base states from manifests
|
|
35
|
+
const sourceBaseState = sourceManifest?.files[relativePath] ?? null;
|
|
36
|
+
const destBaseState = destManifest?.files[relativePath] ?? null;
|
|
37
|
+
// Determine change type using three-way merge logic
|
|
38
|
+
const change = this.determineChangeType(relativePath, sourceState, destState, sourceBaseState, destBaseState);
|
|
39
|
+
if (change) {
|
|
40
|
+
changes.push(change);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Check for deleted files (in manifest but not in current file list)
|
|
44
|
+
if (sourceManifest) {
|
|
45
|
+
for (const relativePath of Object.keys(sourceManifest.files)) {
|
|
46
|
+
if (!processedFiles.has(relativePath)) {
|
|
47
|
+
// File was in source before but not now - deleted from source
|
|
48
|
+
const destFilePath = path.join(destPath, relativePath);
|
|
49
|
+
const destState = await this.getFileState(destFilePath, this.destAdapter);
|
|
50
|
+
if (destState) {
|
|
51
|
+
// Still exists in destination
|
|
52
|
+
const destBaseState = destManifest?.files[relativePath] ?? null;
|
|
53
|
+
if (destBaseState && destState.hash !== destBaseState.hash) {
|
|
54
|
+
// Conflict: deleted in source, modified in destination
|
|
55
|
+
changes.push({
|
|
56
|
+
path: relativePath,
|
|
57
|
+
type: 'conflict',
|
|
58
|
+
sourceState: null,
|
|
59
|
+
destinationState: destState,
|
|
60
|
+
baseState: sourceManifest.files[relativePath],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Deleted in source, unchanged in destination - propagate deletion
|
|
65
|
+
changes.push({
|
|
66
|
+
path: relativePath,
|
|
67
|
+
type: 'deleted',
|
|
68
|
+
sourceState: null,
|
|
69
|
+
destinationState: destState,
|
|
70
|
+
baseState: sourceManifest.files[relativePath],
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (destManifest) {
|
|
78
|
+
for (const relativePath of Object.keys(destManifest.files)) {
|
|
79
|
+
if (!processedFiles.has(relativePath)) {
|
|
80
|
+
// File was in destination before but not now - deleted from destination
|
|
81
|
+
const sourceFilePath = path.join(sourcePath, relativePath);
|
|
82
|
+
const sourceState = await this.getFileState(sourceFilePath, this.sourceAdapter);
|
|
83
|
+
if (sourceState) {
|
|
84
|
+
// Still exists in source
|
|
85
|
+
const sourceBaseState = sourceManifest?.files[relativePath] ?? null;
|
|
86
|
+
if (sourceBaseState && sourceState.hash !== sourceBaseState.hash) {
|
|
87
|
+
// Conflict: deleted in destination, modified in source
|
|
88
|
+
changes.push({
|
|
89
|
+
path: relativePath,
|
|
90
|
+
type: 'conflict',
|
|
91
|
+
sourceState: sourceState,
|
|
92
|
+
destinationState: null,
|
|
93
|
+
baseState: destManifest.files[relativePath],
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Deleted in destination, unchanged in source - propagate deletion
|
|
98
|
+
changes.push({
|
|
99
|
+
path: relativePath,
|
|
100
|
+
type: 'deleted',
|
|
101
|
+
sourceState: sourceState,
|
|
102
|
+
destinationState: null,
|
|
103
|
+
baseState: destManifest.files[relativePath],
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return changes;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Determine change type using three-way merge algorithm
|
|
114
|
+
*/
|
|
115
|
+
determineChangeType(relativePath, sourceState, destState, sourceBaseState, destBaseState) {
|
|
116
|
+
// Both files don't exist - no change
|
|
117
|
+
if (!sourceState && !destState) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
// File exists in source but not destination
|
|
121
|
+
if (sourceState && !destState) {
|
|
122
|
+
if (!sourceBaseState) {
|
|
123
|
+
// New file in source
|
|
124
|
+
return {
|
|
125
|
+
path: relativePath,
|
|
126
|
+
type: 'added',
|
|
127
|
+
sourceState,
|
|
128
|
+
destinationState: null,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// File was deleted from destination
|
|
133
|
+
if (sourceState.hash !== sourceBaseState.hash) {
|
|
134
|
+
// Modified in source, deleted in destination - CONFLICT
|
|
135
|
+
return {
|
|
136
|
+
path: relativePath,
|
|
137
|
+
type: 'conflict',
|
|
138
|
+
sourceState,
|
|
139
|
+
destinationState: null,
|
|
140
|
+
baseState: sourceBaseState,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
// Unchanged in source, deleted in destination
|
|
145
|
+
return {
|
|
146
|
+
path: relativePath,
|
|
147
|
+
type: 'deleted',
|
|
148
|
+
sourceState,
|
|
149
|
+
destinationState: null,
|
|
150
|
+
baseState: sourceBaseState,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// File exists in destination but not source
|
|
156
|
+
if (!sourceState && destState) {
|
|
157
|
+
if (!destBaseState) {
|
|
158
|
+
// New file in destination
|
|
159
|
+
return {
|
|
160
|
+
path: relativePath,
|
|
161
|
+
type: 'added',
|
|
162
|
+
sourceState: null,
|
|
163
|
+
destinationState: destState,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// File was deleted from source
|
|
168
|
+
if (destState.hash !== destBaseState.hash) {
|
|
169
|
+
// Deleted in source, modified in destination - CONFLICT
|
|
170
|
+
return {
|
|
171
|
+
path: relativePath,
|
|
172
|
+
type: 'conflict',
|
|
173
|
+
sourceState: null,
|
|
174
|
+
destinationState: destState,
|
|
175
|
+
baseState: destBaseState,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// Deleted in source, unchanged in destination
|
|
180
|
+
return {
|
|
181
|
+
path: relativePath,
|
|
182
|
+
type: 'deleted',
|
|
183
|
+
sourceState: null,
|
|
184
|
+
destinationState: destState,
|
|
185
|
+
baseState: destBaseState,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Both files exist - check for modifications
|
|
191
|
+
if (sourceState && destState) {
|
|
192
|
+
const sourceChanged = !sourceBaseState || sourceState.hash !== sourceBaseState.hash;
|
|
193
|
+
const destChanged = !destBaseState || destState.hash !== destBaseState.hash;
|
|
194
|
+
if (sourceChanged && destChanged) {
|
|
195
|
+
// Both modified - CONFLICT (unless they converged to same hash)
|
|
196
|
+
if (sourceState.hash === destState.hash) {
|
|
197
|
+
// Converged to same content - no sync needed
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
path: relativePath,
|
|
202
|
+
type: 'conflict',
|
|
203
|
+
sourceState,
|
|
204
|
+
destinationState: destState,
|
|
205
|
+
baseState: sourceBaseState || destBaseState,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
else if (sourceChanged) {
|
|
209
|
+
// Only source changed
|
|
210
|
+
return {
|
|
211
|
+
path: relativePath,
|
|
212
|
+
type: 'modified',
|
|
213
|
+
sourceState,
|
|
214
|
+
destinationState: destState,
|
|
215
|
+
baseState: sourceBaseState,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
else if (destChanged) {
|
|
219
|
+
// Only destination changed
|
|
220
|
+
return {
|
|
221
|
+
path: relativePath,
|
|
222
|
+
type: 'modified',
|
|
223
|
+
sourceState,
|
|
224
|
+
destinationState: destState,
|
|
225
|
+
baseState: destBaseState,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Neither changed - no sync needed
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get current file state (hash, size, mtime)
|
|
237
|
+
*/
|
|
238
|
+
async getFileState(filePath, adapter) {
|
|
239
|
+
try {
|
|
240
|
+
const exists = await adapter.exists(filePath);
|
|
241
|
+
if (!exists) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const content = await adapter.read(filePath);
|
|
245
|
+
const hash = computeFileHash(content);
|
|
246
|
+
const stats = await fs.stat(filePath);
|
|
247
|
+
return {
|
|
248
|
+
hash,
|
|
249
|
+
size: stats.size,
|
|
250
|
+
mtime: stats.mtime.toISOString(),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
// File doesn't exist or can't be read
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=changeDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changeDetector.js","sourceRoot":"","sources":["../../src/sync/changeDetector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conflict resolution strategies for sync operations.
|
|
3
|
+
* Resolves conflicts when same file is modified on both sides.
|
|
4
|
+
*/
|
|
5
|
+
import type { FileChange, ConflictStrategy } from './types.js';
|
|
6
|
+
export interface ResolvedConflict {
|
|
7
|
+
path: string;
|
|
8
|
+
action: 'use-source' | 'use-destination' | 'skip';
|
|
9
|
+
reason: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class ConflictResolver {
|
|
12
|
+
/**
|
|
13
|
+
* Resolve conflicts using specified strategy
|
|
14
|
+
*/
|
|
15
|
+
resolveConflicts(conflicts: FileChange[], strategy: ConflictStrategy): Promise<ResolvedConflict[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a single conflict based on strategy
|
|
18
|
+
*/
|
|
19
|
+
private resolveConflict;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve conflict by choosing newest file (by mtime)
|
|
22
|
+
*/
|
|
23
|
+
private resolveByNewest;
|
|
24
|
+
/**
|
|
25
|
+
* Get human-readable summary of conflict resolutions
|
|
26
|
+
*/
|
|
27
|
+
getSummary(resolutions: ResolvedConflict[]): string;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=conflictResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conflictResolver.d.ts","sourceRoot":"","sources":["../../src/sync/conflictResolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,GAAG,iBAAiB,GAAG,MAAM,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,gBAAgB;IAC3B;;OAEG;IACG,gBAAgB,CACpB,SAAS,EAAE,UAAU,EAAE,EACvB,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAW9B;;OAEG;YACW,eAAe;IAuC7B;;OAEG;IACH,OAAO,CAAC,eAAe;IA8CvB;;OAEG;IACH,UAAU,CAAC,WAAW,EAAE,gBAAgB,EAAE,GAAG,MAAM;CAepD"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conflict resolution strategies for sync operations.
|
|
3
|
+
* Resolves conflicts when same file is modified on both sides.
|
|
4
|
+
*/
|
|
5
|
+
export class ConflictResolver {
|
|
6
|
+
/**
|
|
7
|
+
* Resolve conflicts using specified strategy
|
|
8
|
+
*/
|
|
9
|
+
async resolveConflicts(conflicts, strategy) {
|
|
10
|
+
const resolved = [];
|
|
11
|
+
for (const conflict of conflicts) {
|
|
12
|
+
const resolution = await this.resolveConflict(conflict, strategy);
|
|
13
|
+
resolved.push(resolution);
|
|
14
|
+
}
|
|
15
|
+
return resolved;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a single conflict based on strategy
|
|
19
|
+
*/
|
|
20
|
+
async resolveConflict(conflict, strategy) {
|
|
21
|
+
switch (strategy) {
|
|
22
|
+
case 'source':
|
|
23
|
+
return {
|
|
24
|
+
path: conflict.path,
|
|
25
|
+
action: 'use-source',
|
|
26
|
+
reason: 'Strategy: always prefer source',
|
|
27
|
+
};
|
|
28
|
+
case 'destination':
|
|
29
|
+
return {
|
|
30
|
+
path: conflict.path,
|
|
31
|
+
action: 'use-destination',
|
|
32
|
+
reason: 'Strategy: always prefer destination',
|
|
33
|
+
};
|
|
34
|
+
case 'newest':
|
|
35
|
+
return this.resolveByNewest(conflict);
|
|
36
|
+
case 'skip':
|
|
37
|
+
return {
|
|
38
|
+
path: conflict.path,
|
|
39
|
+
action: 'skip',
|
|
40
|
+
reason: 'Strategy: skip conflicts',
|
|
41
|
+
};
|
|
42
|
+
default:
|
|
43
|
+
// Default to skip for unknown strategies
|
|
44
|
+
return {
|
|
45
|
+
path: conflict.path,
|
|
46
|
+
action: 'skip',
|
|
47
|
+
reason: 'Unknown strategy, skipping',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve conflict by choosing newest file (by mtime)
|
|
53
|
+
*/
|
|
54
|
+
resolveByNewest(conflict) {
|
|
55
|
+
const { sourceState, destinationState } = conflict;
|
|
56
|
+
// Handle deletion conflicts
|
|
57
|
+
if (!sourceState || !destinationState) {
|
|
58
|
+
if (!sourceState) {
|
|
59
|
+
return {
|
|
60
|
+
path: conflict.path,
|
|
61
|
+
action: 'use-destination',
|
|
62
|
+
reason: 'File exists only in destination',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
return {
|
|
67
|
+
path: conflict.path,
|
|
68
|
+
action: 'use-source',
|
|
69
|
+
reason: 'File exists only in source',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Compare modification times
|
|
74
|
+
const sourceMtime = new Date(sourceState.mtime).getTime();
|
|
75
|
+
const destMtime = new Date(destinationState.mtime).getTime();
|
|
76
|
+
if (sourceMtime > destMtime) {
|
|
77
|
+
return {
|
|
78
|
+
path: conflict.path,
|
|
79
|
+
action: 'use-source',
|
|
80
|
+
reason: `Source is newer (${sourceState.mtime} vs ${destinationState.mtime})`,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
else if (destMtime > sourceMtime) {
|
|
84
|
+
return {
|
|
85
|
+
path: conflict.path,
|
|
86
|
+
action: 'use-destination',
|
|
87
|
+
reason: `Destination is newer (${destinationState.mtime} vs ${sourceState.mtime})`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Same mtime - prefer source as tiebreaker
|
|
92
|
+
return {
|
|
93
|
+
path: conflict.path,
|
|
94
|
+
action: 'use-source',
|
|
95
|
+
reason: 'Both files have same modification time, preferring source',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get human-readable summary of conflict resolutions
|
|
101
|
+
*/
|
|
102
|
+
getSummary(resolutions) {
|
|
103
|
+
const useSource = resolutions.filter((r) => r.action === 'use-source').length;
|
|
104
|
+
const useDest = resolutions.filter((r) => r.action === 'use-destination').length;
|
|
105
|
+
const skipped = resolutions.filter((r) => r.action === 'skip').length;
|
|
106
|
+
const lines = [
|
|
107
|
+
`Conflict Resolution Summary:`,
|
|
108
|
+
` Using source: ${useSource}`,
|
|
109
|
+
` Using destination: ${useDest}`,
|
|
110
|
+
` Skipped: ${skipped}`,
|
|
111
|
+
` Total conflicts: ${resolutions.length}`,
|
|
112
|
+
];
|
|
113
|
+
return lines.join('\n');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=conflictResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conflictResolver.js","sourceRoot":"","sources":["../../src/sync/conflictResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple directory file lister for non-vault destinations.
|
|
3
|
+
* Used in remote mode when the destination is not an Obsidian vault.
|
|
4
|
+
*/
|
|
5
|
+
export interface DirectoryListerConfig {
|
|
6
|
+
path: string;
|
|
7
|
+
excludePatterns?: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare class DirectoryLister {
|
|
10
|
+
private config;
|
|
11
|
+
private storage;
|
|
12
|
+
constructor(config: DirectoryListerConfig);
|
|
13
|
+
/**
|
|
14
|
+
* List all files in the directory, applying exclusion patterns
|
|
15
|
+
*/
|
|
16
|
+
listFiles(): Promise<string[]>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=directoryLister.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directoryLister.d.ts","sourceRoot":"","sources":["../../src/sync/directoryLister.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAUD,qBAAa,eAAe;IAGd,OAAO,CAAC,MAAM;IAF1B,OAAO,CAAC,OAAO,CAAsB;gBAEjB,MAAM,EAAE,qBAAqB;IAIjD;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAgBrC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple directory file lister for non-vault destinations.
|
|
3
|
+
* Used in remote mode when the destination is not an Obsidian vault.
|
|
4
|
+
*/
|
|
5
|
+
import picomatch from 'picomatch';
|
|
6
|
+
import { LocalStorageAdapter } from '../storage/index.js';
|
|
7
|
+
const DEFAULT_EXCLUDES = [
|
|
8
|
+
'.obsync/**',
|
|
9
|
+
'.DS_Store',
|
|
10
|
+
'**/.DS_Store',
|
|
11
|
+
'Thumbs.db',
|
|
12
|
+
'**/Thumbs.db',
|
|
13
|
+
];
|
|
14
|
+
export class DirectoryLister {
|
|
15
|
+
config;
|
|
16
|
+
storage;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.storage = new LocalStorageAdapter();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* List all files in the directory, applying exclusion patterns
|
|
23
|
+
*/
|
|
24
|
+
async listFiles() {
|
|
25
|
+
// Check if directory exists first
|
|
26
|
+
const exists = await this.storage.exists(this.config.path);
|
|
27
|
+
if (!exists) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const allFiles = await this.storage.list(this.config.path);
|
|
31
|
+
const excludePatterns = [
|
|
32
|
+
...DEFAULT_EXCLUDES,
|
|
33
|
+
...(this.config.excludePatterns || []),
|
|
34
|
+
];
|
|
35
|
+
const excludeMatcher = picomatch(excludePatterns);
|
|
36
|
+
return allFiles.filter((file) => !excludeMatcher(file));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=directoryLister.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directoryLister.js","sourceRoot":"","sources":["../../src/sync/directoryLister.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,SAAS,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAO1D,MAAM,gBAAgB,GAAG;IACvB,YAAY;IACZ,WAAW;IACX,cAAc;IACd,WAAW;IACX,cAAc;CACf,CAAC;AAEF,MAAM,OAAO,eAAe;IAGN;IAFZ,OAAO,CAAsB;IAErC,YAAoB,MAA6B;QAA7B,WAAM,GAAN,MAAM,CAAuB;QAC/C,IAAI,CAAC,OAAO,GAAG,IAAI,mBAAmB,EAAE,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS;QACb,kCAAkC;QAClC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,eAAe,GAAG;YACtB,GAAG,gBAAgB;YACnB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;SACvC,CAAC;QACF,MAAM,cAAc,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QAElD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core synchronization logic for Obsidian vaults.
|
|
3
|
+
* Handles file comparison, conflict detection, and sync operations.
|
|
4
|
+
*/
|
|
5
|
+
import type { SyncOptions, SyncResult, FileChange } from './types.js';
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
export * from './watcher.js';
|
|
8
|
+
export * from './watchMode.js';
|
|
9
|
+
export * from './directoryLister.js';
|
|
10
|
+
export declare class SyncEngine {
|
|
11
|
+
private sourceAdapter;
|
|
12
|
+
private destAdapter;
|
|
13
|
+
private changeDetector;
|
|
14
|
+
private conflictResolver;
|
|
15
|
+
constructor();
|
|
16
|
+
/**
|
|
17
|
+
* Synchronize source vault to destination
|
|
18
|
+
*/
|
|
19
|
+
sync(options: SyncOptions): Promise<SyncResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Apply file changes to destination
|
|
22
|
+
*/
|
|
23
|
+
private applyChanges;
|
|
24
|
+
/**
|
|
25
|
+
* Detect changes between source and destination
|
|
26
|
+
*/
|
|
27
|
+
detectChanges(source: string, destination: string): Promise<FileChange[]>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtE,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AAErC,qBAAa,UAAU;IACrB,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,gBAAgB,CAAmB;;IAS3C;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA+IrD;;OAEG;YACW,YAAY;IA8E1B;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAuBhF"}
|