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.
Files changed (102) hide show
  1. package/README.md +920 -0
  2. package/dist/cli/commands/init.d.ts +8 -0
  3. package/dist/cli/commands/init.d.ts.map +1 -0
  4. package/dist/cli/commands/init.js +104 -0
  5. package/dist/cli/commands/init.js.map +1 -0
  6. package/dist/cli/commands/status.d.ts +8 -0
  7. package/dist/cli/commands/status.d.ts.map +1 -0
  8. package/dist/cli/commands/status.js +117 -0
  9. package/dist/cli/commands/status.js.map +1 -0
  10. package/dist/cli/commands/sync.d.ts +13 -0
  11. package/dist/cli/commands/sync.d.ts.map +1 -0
  12. package/dist/cli/commands/sync.js +225 -0
  13. package/dist/cli/commands/sync.js.map +1 -0
  14. package/dist/cli/prompts/conflictPrompt.d.ts +10 -0
  15. package/dist/cli/prompts/conflictPrompt.d.ts.map +1 -0
  16. package/dist/cli/prompts/conflictPrompt.js +51 -0
  17. package/dist/cli/prompts/conflictPrompt.js.map +1 -0
  18. package/dist/cli/prompts/fileBrowser.d.ts +6 -0
  19. package/dist/cli/prompts/fileBrowser.d.ts.map +1 -0
  20. package/dist/cli/prompts/fileBrowser.js +91 -0
  21. package/dist/cli/prompts/fileBrowser.js.map +1 -0
  22. package/dist/cli/prompts/vaultSelector.d.ts +13 -0
  23. package/dist/cli/prompts/vaultSelector.d.ts.map +1 -0
  24. package/dist/cli/prompts/vaultSelector.js +63 -0
  25. package/dist/cli/prompts/vaultSelector.js.map +1 -0
  26. package/dist/cli/ui/colors.d.ts +50 -0
  27. package/dist/cli/ui/colors.d.ts.map +1 -0
  28. package/dist/cli/ui/colors.js +62 -0
  29. package/dist/cli/ui/colors.js.map +1 -0
  30. package/dist/cli/ui/output.d.ts +45 -0
  31. package/dist/cli/ui/output.d.ts.map +1 -0
  32. package/dist/cli/ui/output.js +116 -0
  33. package/dist/cli/ui/output.js.map +1 -0
  34. package/dist/cli/ui/spinner.d.ts +29 -0
  35. package/dist/cli/ui/spinner.d.ts.map +1 -0
  36. package/dist/cli/ui/spinner.js +80 -0
  37. package/dist/cli/ui/spinner.js.map +1 -0
  38. package/dist/cli/ui/table.d.ts +28 -0
  39. package/dist/cli/ui/table.d.ts.map +1 -0
  40. package/dist/cli/ui/table.js +123 -0
  41. package/dist/cli/ui/table.js.map +1 -0
  42. package/dist/cli/utils/terminal.d.ts +21 -0
  43. package/dist/cli/utils/terminal.d.ts.map +1 -0
  44. package/dist/cli/utils/terminal.js +59 -0
  45. package/dist/cli/utils/terminal.js.map +1 -0
  46. package/dist/cli.d.ts +3 -0
  47. package/dist/cli.d.ts.map +1 -0
  48. package/dist/cli.js +32 -0
  49. package/dist/cli.js.map +1 -0
  50. package/dist/config/index.d.ts +45 -0
  51. package/dist/config/index.d.ts.map +1 -0
  52. package/dist/config/index.js +112 -0
  53. package/dist/config/index.js.map +1 -0
  54. package/dist/index.d.ts +6 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +5 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/storage/index.d.ts +35 -0
  59. package/dist/storage/index.d.ts.map +1 -0
  60. package/dist/storage/index.js +97 -0
  61. package/dist/storage/index.js.map +1 -0
  62. package/dist/sync/changeDetector.d.ts +29 -0
  63. package/dist/sync/changeDetector.d.ts.map +1 -0
  64. package/dist/sync/changeDetector.js +259 -0
  65. package/dist/sync/changeDetector.js.map +1 -0
  66. package/dist/sync/conflictResolver.d.ts +29 -0
  67. package/dist/sync/conflictResolver.d.ts.map +1 -0
  68. package/dist/sync/conflictResolver.js +116 -0
  69. package/dist/sync/conflictResolver.js.map +1 -0
  70. package/dist/sync/directoryLister.d.ts +18 -0
  71. package/dist/sync/directoryLister.d.ts.map +1 -0
  72. package/dist/sync/directoryLister.js +39 -0
  73. package/dist/sync/directoryLister.js.map +1 -0
  74. package/dist/sync/index.d.ts +29 -0
  75. package/dist/sync/index.d.ts.map +1 -0
  76. package/dist/sync/index.js +212 -0
  77. package/dist/sync/index.js.map +1 -0
  78. package/dist/sync/manifest.d.ts +48 -0
  79. package/dist/sync/manifest.d.ts.map +1 -0
  80. package/dist/sync/manifest.js +137 -0
  81. package/dist/sync/manifest.js.map +1 -0
  82. package/dist/sync/types.d.ts +109 -0
  83. package/dist/sync/types.d.ts.map +1 -0
  84. package/dist/sync/types.js +5 -0
  85. package/dist/sync/types.js.map +1 -0
  86. package/dist/sync/watchMode.d.ts +84 -0
  87. package/dist/sync/watchMode.d.ts.map +1 -0
  88. package/dist/sync/watchMode.js +364 -0
  89. package/dist/sync/watchMode.js.map +1 -0
  90. package/dist/sync/watcher.d.ts +114 -0
  91. package/dist/sync/watcher.d.ts.map +1 -0
  92. package/dist/sync/watcher.js +293 -0
  93. package/dist/sync/watcher.js.map +1 -0
  94. package/dist/utils/index.d.ts +8 -0
  95. package/dist/utils/index.d.ts.map +1 -0
  96. package/dist/utils/index.js +25 -0
  97. package/dist/utils/index.js.map +1 -0
  98. package/dist/vault/index.d.ts +38 -0
  99. package/dist/vault/index.d.ts.map +1 -0
  100. package/dist/vault/index.js +106 -0
  101. package/dist/vault/index.js.map +1 -0
  102. package/package.json +68 -0
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Core synchronization logic for Obsidian vaults.
3
+ * Handles file comparison, conflict detection, and sync operations.
4
+ */
5
+ import path from 'path';
6
+ import * as fs from 'fs/promises';
7
+ import { LocalStorageAdapter } from '../storage/index.js';
8
+ import { ObsidianVault } from '../vault/index.js';
9
+ import { ManifestManager } from './manifest.js';
10
+ import { ChangeDetector } from './changeDetector.js';
11
+ import { ConflictResolver } from './conflictResolver.js';
12
+ import { DirectoryLister } from './directoryLister.js';
13
+ import { computeFileHash } from '../utils/index.js';
14
+ export * from './types.js';
15
+ export * from './watcher.js';
16
+ export * from './watchMode.js';
17
+ export * from './directoryLister.js';
18
+ export class SyncEngine {
19
+ sourceAdapter;
20
+ destAdapter;
21
+ changeDetector;
22
+ conflictResolver;
23
+ constructor() {
24
+ this.sourceAdapter = new LocalStorageAdapter();
25
+ this.destAdapter = new LocalStorageAdapter();
26
+ this.changeDetector = new ChangeDetector(this.sourceAdapter, this.destAdapter);
27
+ this.conflictResolver = new ConflictResolver();
28
+ }
29
+ /**
30
+ * Synchronize source vault to destination
31
+ */
32
+ async sync(options) {
33
+ const { source, destination, conflictResolution = 'newest', dryRun = false, remoteMode = false, } = options;
34
+ const result = {
35
+ filesAdded: 0,
36
+ filesUpdated: 0,
37
+ filesDeleted: 0,
38
+ conflicts: [],
39
+ errors: [],
40
+ skipped: [],
41
+ };
42
+ try {
43
+ // Validate source is an Obsidian vault
44
+ const sourceVault = new ObsidianVault({ vaultPath: source });
45
+ const isSourceVault = await sourceVault.isObsidianVault();
46
+ if (!isSourceVault) {
47
+ result.errors.push(`Source path is not an Obsidian vault: ${source}`);
48
+ return result;
49
+ }
50
+ // In remote mode, destination can be any directory
51
+ // Otherwise, validate it's an Obsidian vault
52
+ if (!remoteMode) {
53
+ const destVault = new ObsidianVault({ vaultPath: destination });
54
+ const isDestVault = await destVault.isObsidianVault();
55
+ if (!isDestVault) {
56
+ result.errors.push(`Destination path is not an Obsidian vault: ${destination}. Use --remote flag for non-vault destinations.`);
57
+ return result;
58
+ }
59
+ }
60
+ else {
61
+ // Create destination directory if it doesn't exist
62
+ await fs.mkdir(destination, { recursive: true });
63
+ }
64
+ // Load manifests (state from last sync)
65
+ const sourceManifestMgr = new ManifestManager(source);
66
+ const destManifestMgr = new ManifestManager(destination);
67
+ const sourceManifest = await sourceManifestMgr.load();
68
+ const destManifest = await destManifestMgr.load();
69
+ // Get list of files from source vault
70
+ const sourceFiles = await sourceVault.listFiles();
71
+ // Get list of files from destination
72
+ // Use DirectoryLister for remote mode, ObsidianVault otherwise
73
+ let destFiles;
74
+ if (remoteMode) {
75
+ const destLister = new DirectoryLister({ path: destination });
76
+ destFiles = await destLister.listFiles();
77
+ }
78
+ else {
79
+ const destVault = new ObsidianVault({ vaultPath: destination });
80
+ destFiles = await destVault.listFiles();
81
+ }
82
+ // Combine file lists (unique paths)
83
+ const allFiles = Array.from(new Set([...sourceFiles, ...destFiles]));
84
+ // Detect changes using three-way merge
85
+ const changes = await this.changeDetector.detectChanges(source, destination, sourceManifest, destManifest, allFiles);
86
+ // Separate conflicts from regular changes
87
+ const conflicts = changes.filter((c) => c.type === 'conflict');
88
+ const regularChanges = changes.filter((c) => c.type !== 'conflict');
89
+ // Resolve conflicts
90
+ if (conflicts.length > 0) {
91
+ const resolutions = await this.conflictResolver.resolveConflicts(conflicts, conflictResolution);
92
+ for (const resolution of resolutions) {
93
+ const conflict = conflicts.find((c) => c.path === resolution.path);
94
+ if (resolution.action === 'skip') {
95
+ result.skipped.push(resolution.path);
96
+ result.conflicts.push(conflict);
97
+ }
98
+ else {
99
+ // Convert resolved conflict to a regular change
100
+ // Set the appropriate state based on which side wins
101
+ const resolvedChange = {
102
+ path: conflict.path,
103
+ type: 'modified',
104
+ sourceState: resolution.action === 'use-source' ? conflict.sourceState : null,
105
+ destinationState: resolution.action === 'use-destination' ? conflict.destinationState : null,
106
+ baseState: conflict.baseState,
107
+ };
108
+ regularChanges.push(resolvedChange);
109
+ }
110
+ }
111
+ }
112
+ // Apply changes
113
+ if (!dryRun) {
114
+ await this.applyChanges(source, destination, regularChanges, sourceManifestMgr, destManifestMgr, result);
115
+ }
116
+ else {
117
+ // Dry run - just count what would be done
118
+ for (const change of regularChanges) {
119
+ if (change.type === 'added') {
120
+ result.filesAdded++;
121
+ }
122
+ else if (change.type === 'modified') {
123
+ result.filesUpdated++;
124
+ }
125
+ else if (change.type === 'deleted') {
126
+ result.filesDeleted++;
127
+ }
128
+ }
129
+ }
130
+ }
131
+ catch (error) {
132
+ result.errors.push(`Sync failed: ${error instanceof Error ? error.message : String(error)}`);
133
+ }
134
+ return result;
135
+ }
136
+ /**
137
+ * Apply file changes to destination
138
+ */
139
+ async applyChanges(source, destination, changes, sourceManifestMgr, destManifestMgr, result) {
140
+ for (const change of changes) {
141
+ const sourcePath = path.join(source, change.path);
142
+ const destPath = path.join(destination, change.path);
143
+ try {
144
+ if (change.type === 'added' || change.type === 'modified') {
145
+ // Copy from source to destination (or vice versa)
146
+ const fromPath = change.sourceState ? sourcePath : destPath;
147
+ const toPath = change.sourceState ? destPath : sourcePath;
148
+ const content = await (change.sourceState
149
+ ? this.sourceAdapter
150
+ : this.destAdapter).read(fromPath);
151
+ await (change.sourceState ? this.destAdapter : this.sourceAdapter).write(toPath, content);
152
+ // Update manifests
153
+ const hash = computeFileHash(content);
154
+ const stats = await (change.sourceState
155
+ ? this.sourceAdapter
156
+ : this.destAdapter).exists(fromPath);
157
+ if (stats) {
158
+ const fileState = {
159
+ hash,
160
+ size: content.length,
161
+ mtime: new Date().toISOString(),
162
+ };
163
+ await sourceManifestMgr.updateFileState(change.path, fileState);
164
+ await destManifestMgr.updateFileState(change.path, fileState);
165
+ }
166
+ if (change.type === 'added') {
167
+ result.filesAdded++;
168
+ }
169
+ else {
170
+ result.filesUpdated++;
171
+ }
172
+ }
173
+ else if (change.type === 'deleted') {
174
+ // Determine which side the file was deleted from and propagate
175
+ // If sourceState is null, file was deleted from source -> delete from dest
176
+ // If destinationState is null, file was deleted from dest -> delete from source
177
+ if (!change.sourceState && change.destinationState) {
178
+ // Deleted from source, remove from destination
179
+ await this.destAdapter.delete(destPath);
180
+ }
181
+ else if (change.sourceState && !change.destinationState) {
182
+ // Deleted from destination, remove from source
183
+ await this.sourceAdapter.delete(sourcePath);
184
+ }
185
+ // Remove from manifests
186
+ await sourceManifestMgr.removeFileState(change.path);
187
+ await destManifestMgr.removeFileState(change.path);
188
+ result.filesDeleted++;
189
+ }
190
+ }
191
+ catch (error) {
192
+ result.errors.push(`Failed to sync ${change.path}: ${error instanceof Error ? error.message : String(error)}`);
193
+ }
194
+ }
195
+ }
196
+ /**
197
+ * Detect changes between source and destination
198
+ */
199
+ async detectChanges(source, destination) {
200
+ const sourceVault = new ObsidianVault({ vaultPath: source });
201
+ const destVault = new ObsidianVault({ vaultPath: destination });
202
+ const sourceManifestMgr = new ManifestManager(source);
203
+ const destManifestMgr = new ManifestManager(destination);
204
+ const sourceManifest = await sourceManifestMgr.load();
205
+ const destManifest = await destManifestMgr.load();
206
+ const sourceFiles = await sourceVault.listFiles();
207
+ const destFiles = await destVault.listFiles();
208
+ const allFiles = Array.from(new Set([...sourceFiles, ...destFiles]));
209
+ return this.changeDetector.detectChanges(source, destination, sourceManifest, destManifest, allFiles);
210
+ }
211
+ }
212
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Sync manifest manager for tracking sync state.
3
+ * Used for three-way merge algorithm.
4
+ */
5
+ import type { SyncManifest, FileState } from './types.js';
6
+ export declare class ManifestManager {
7
+ private vaultPath;
8
+ private static readonly MANIFEST_DIR;
9
+ private static readonly MANIFEST_FILE;
10
+ constructor(vaultPath: string);
11
+ /**
12
+ * Load manifest from vault, returns null if doesn't exist
13
+ */
14
+ load(): Promise<SyncManifest | null>;
15
+ /**
16
+ * Save manifest to vault (atomic write using temp file + rename)
17
+ */
18
+ save(manifest: SyncManifest): Promise<void>;
19
+ /**
20
+ * Get file state from manifest
21
+ */
22
+ getFileState(relativePath: string): Promise<FileState | null>;
23
+ /**
24
+ * Update file state in manifest
25
+ */
26
+ updateFileState(relativePath: string, state: FileState): Promise<void>;
27
+ /**
28
+ * Remove file state from manifest (when file is deleted)
29
+ */
30
+ removeFileState(relativePath: string): Promise<void>;
31
+ /**
32
+ * Create a new empty manifest with UUID
33
+ */
34
+ createEmptyManifest(): SyncManifest;
35
+ /**
36
+ * Get full path to manifest file
37
+ */
38
+ private getManifestPath;
39
+ /**
40
+ * Check if manifest exists
41
+ */
42
+ exists(): Promise<boolean>;
43
+ /**
44
+ * Delete manifest file
45
+ */
46
+ delete(): Promise<void>;
47
+ }
48
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/sync/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,eAAe;IAId,OAAO,CAAC,SAAS;IAH7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAa;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAwB;gBAEzC,SAAS,EAAE,MAAM;IAErC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAiB1C;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BjD;;OAEG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAQnE;;OAEG;IACG,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5E;;OAEG;IACG,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY1D;;OAEG;IACH,mBAAmB,IAAI,YAAY;IASnC;;OAEG;IACH,OAAO,CAAC,eAAe;IAQvB;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAUhC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAU9B"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Sync manifest manager for tracking sync state.
3
+ * Used for three-way merge algorithm.
4
+ */
5
+ import { promises as fs } from 'fs';
6
+ import path from 'path';
7
+ import { v4 as uuidv4 } from 'uuid';
8
+ export class ManifestManager {
9
+ vaultPath;
10
+ static MANIFEST_DIR = '.obsync';
11
+ static MANIFEST_FILE = 'sync-manifest.json';
12
+ constructor(vaultPath) {
13
+ this.vaultPath = vaultPath;
14
+ }
15
+ /**
16
+ * Load manifest from vault, returns null if doesn't exist
17
+ */
18
+ async load() {
19
+ const manifestPath = this.getManifestPath();
20
+ try {
21
+ const content = await fs.readFile(manifestPath, 'utf-8');
22
+ const manifest = JSON.parse(content);
23
+ return manifest;
24
+ }
25
+ catch (error) {
26
+ if (error.code === 'ENOENT') {
27
+ return null;
28
+ }
29
+ throw new Error(`Failed to load manifest: ${error instanceof Error ? error.message : String(error)}`);
30
+ }
31
+ }
32
+ /**
33
+ * Save manifest to vault (atomic write using temp file + rename)
34
+ */
35
+ async save(manifest) {
36
+ const manifestPath = this.getManifestPath();
37
+ const manifestDir = path.dirname(manifestPath);
38
+ const tempPath = `${manifestPath}.tmp`;
39
+ try {
40
+ // Ensure .obsync directory exists
41
+ await fs.mkdir(manifestDir, { recursive: true });
42
+ // Write to temp file first
43
+ await fs.writeFile(tempPath, JSON.stringify(manifest, null, 2), 'utf-8');
44
+ // Atomic rename
45
+ await fs.rename(tempPath, manifestPath);
46
+ }
47
+ catch (error) {
48
+ // Clean up temp file if it exists
49
+ try {
50
+ await fs.unlink(tempPath);
51
+ }
52
+ catch {
53
+ // Ignore cleanup errors
54
+ }
55
+ throw new Error(`Failed to save manifest: ${error instanceof Error ? error.message : String(error)}`);
56
+ }
57
+ }
58
+ /**
59
+ * Get file state from manifest
60
+ */
61
+ async getFileState(relativePath) {
62
+ const manifest = await this.load();
63
+ if (!manifest) {
64
+ return null;
65
+ }
66
+ return manifest.files[relativePath] ?? null;
67
+ }
68
+ /**
69
+ * Update file state in manifest
70
+ */
71
+ async updateFileState(relativePath, state) {
72
+ let manifest = await this.load();
73
+ if (!manifest) {
74
+ manifest = this.createEmptyManifest();
75
+ }
76
+ manifest.files[relativePath] = state;
77
+ manifest.lastSync = new Date().toISOString();
78
+ await this.save(manifest);
79
+ }
80
+ /**
81
+ * Remove file state from manifest (when file is deleted)
82
+ */
83
+ async removeFileState(relativePath) {
84
+ const manifest = await this.load();
85
+ if (!manifest) {
86
+ return;
87
+ }
88
+ delete manifest.files[relativePath];
89
+ manifest.lastSync = new Date().toISOString();
90
+ await this.save(manifest);
91
+ }
92
+ /**
93
+ * Create a new empty manifest with UUID
94
+ */
95
+ createEmptyManifest() {
96
+ return {
97
+ version: '1.0',
98
+ lastSync: new Date().toISOString(),
99
+ syncId: uuidv4(),
100
+ files: {},
101
+ };
102
+ }
103
+ /**
104
+ * Get full path to manifest file
105
+ */
106
+ getManifestPath() {
107
+ return path.join(this.vaultPath, ManifestManager.MANIFEST_DIR, ManifestManager.MANIFEST_FILE);
108
+ }
109
+ /**
110
+ * Check if manifest exists
111
+ */
112
+ async exists() {
113
+ const manifestPath = this.getManifestPath();
114
+ try {
115
+ await fs.access(manifestPath);
116
+ return true;
117
+ }
118
+ catch {
119
+ return false;
120
+ }
121
+ }
122
+ /**
123
+ * Delete manifest file
124
+ */
125
+ async delete() {
126
+ const manifestPath = this.getManifestPath();
127
+ try {
128
+ await fs.unlink(manifestPath);
129
+ }
130
+ catch (error) {
131
+ if (error.code !== 'ENOENT') {
132
+ throw error;
133
+ }
134
+ }
135
+ }
136
+ }
137
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/sync/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAGpC,MAAM,OAAO,eAAe;IAIN;IAHZ,MAAM,CAAU,YAAY,GAAG,SAAS,CAAC;IACzC,MAAM,CAAU,aAAa,GAAG,oBAAoB,CAAC;IAE7D,YAAoB,SAAiB;QAAjB,cAAS,GAAT,SAAS,CAAQ;IAAG,CAAC;IAEzC;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAE5C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;YACrD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrF,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,QAAsB;QAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,GAAG,YAAY,MAAM,CAAC;QAEvC,IAAI,CAAC;YACH,kCAAkC;YAClC,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEjD,2BAA2B;YAC3B,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAEzE,gBAAgB;YAChB,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kCAAkC;YAClC,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;YAED,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrF,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,YAAoB;QACrC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,YAAoB,EAAE,KAAgB;QAC1D,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAEjC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACxC,CAAC;QAED,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC;QACrC,QAAQ,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE7C,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,YAAoB;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO;QACT,CAAC;QAED,OAAO,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACpC,QAAQ,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE7C,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAClC,MAAM,EAAE,MAAM,EAAE;YAChB,KAAK,EAAE,EAAE;SACV,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,OAAO,IAAI,CAAC,IAAI,CACd,IAAI,CAAC,SAAS,EACd,eAAe,CAAC,YAAY,EAC5B,eAAe,CAAC,aAAa,CAC9B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM;QACV,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM;QACV,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Type definitions for sync operations
3
+ */
4
+ export interface FileState {
5
+ hash: string;
6
+ size: number;
7
+ mtime: string;
8
+ }
9
+ export interface SyncManifest {
10
+ version: string;
11
+ lastSync: string;
12
+ syncId: string;
13
+ files: Record<string, FileState>;
14
+ }
15
+ export type ChangeType = 'added' | 'modified' | 'deleted' | 'conflict';
16
+ export interface FileChange {
17
+ path: string;
18
+ type: ChangeType;
19
+ sourceState?: FileState | null;
20
+ destinationState?: FileState | null;
21
+ baseState?: FileState | null;
22
+ }
23
+ export type ConflictStrategy = 'source' | 'destination' | 'newest' | 'skip';
24
+ export interface SyncOptions {
25
+ source: string;
26
+ destination: string;
27
+ strategy?: 'incremental' | 'full';
28
+ conflictResolution?: ConflictStrategy;
29
+ dryRun?: boolean;
30
+ /** Allow destination to be a non-vault directory (e.g., Dropbox folder) */
31
+ remoteMode?: boolean;
32
+ }
33
+ export interface SyncResult {
34
+ filesAdded: number;
35
+ filesUpdated: number;
36
+ filesDeleted: number;
37
+ conflicts: FileChange[];
38
+ errors: string[];
39
+ skipped: string[];
40
+ }
41
+ export interface WatchModeOptions {
42
+ /** Source vault path */
43
+ source: string;
44
+ /** Destination vault path */
45
+ destination: string;
46
+ /** Conflict resolution strategy */
47
+ conflictResolution?: ConflictStrategy;
48
+ /** Allow destination to be a non-vault directory (e.g., Dropbox folder) */
49
+ remoteMode?: boolean;
50
+ /** Debounce delay in milliseconds (default: 300) */
51
+ debounceMs?: number;
52
+ /** Batch delay - wait for multiple changes before syncing (default: 500) */
53
+ batchDelayMs?: number;
54
+ /** Maximum time to wait before forcing a sync (default: 5000) */
55
+ maxWaitMs?: number;
56
+ /** Whether to run initial sync on start (default: true) */
57
+ initialSync?: boolean;
58
+ /** Callback for sync events */
59
+ onSync?: (result: SyncResult) => void;
60
+ /** Callback for errors */
61
+ onError?: (error: Error) => void;
62
+ /** Callback for status changes */
63
+ onStatusChange?: (status: WatchModeStatus) => void;
64
+ }
65
+ export type WatchModeState = 'idle' | 'watching' | 'syncing' | 'error' | 'stopped';
66
+ export interface WatchModeStatus {
67
+ /** Current state of watch mode */
68
+ state: WatchModeState;
69
+ /** Whether watch mode is active */
70
+ isActive: boolean;
71
+ /** Number of pending file changes */
72
+ pendingChanges: number;
73
+ /** Last sync time */
74
+ lastSyncTime: Date | null;
75
+ /** Last sync result */
76
+ lastSyncResult: SyncResult | null;
77
+ /** Number of syncs performed in this session */
78
+ syncCount: number;
79
+ /** Total files synced in this session */
80
+ totalFilesSynced: number;
81
+ /** Current error (if state is 'error') */
82
+ currentError: Error | null;
83
+ /** Paths being watched */
84
+ watchedPaths: string[];
85
+ }
86
+ export interface WatchModeEvent {
87
+ type: 'sync_start' | 'sync_complete' | 'sync_error' | 'file_change' | 'status_change';
88
+ timestamp: Date;
89
+ data?: SyncResult | Error | WatchModeStatus;
90
+ }
91
+ export interface WatchModeSyncSession {
92
+ /** Unique session ID */
93
+ sessionId: string;
94
+ /** Session start time */
95
+ startTime: Date;
96
+ /** Session end time (null if still active) */
97
+ endTime: Date | null;
98
+ /** Total syncs in this session */
99
+ syncCount: number;
100
+ /** Total errors in this session */
101
+ errorCount: number;
102
+ /** All sync results in this session */
103
+ syncHistory: Array<{
104
+ timestamp: Date;
105
+ result: SyncResult;
106
+ duration: number;
107
+ }>;
108
+ }
109
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Type definitions for sync operations
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * WatchModeSync - Orchestrates continuous file watching and automatic synchronization.
3
+ * Coordinates between FileWatcher and SyncEngine for real-time vault synchronization.
4
+ */
5
+ import { EventEmitter } from 'events';
6
+ import type { WatchModeOptions, WatchModeStatus, WatchModeSyncSession, SyncResult } from './types.js';
7
+ export declare class WatchModeSync extends EventEmitter {
8
+ private watcher;
9
+ private syncEngine;
10
+ private options;
11
+ private state;
12
+ private syncCount;
13
+ private totalFilesSynced;
14
+ private lastSyncTime;
15
+ private lastSyncResult;
16
+ private currentError;
17
+ private isSyncing;
18
+ private pendingSyncRequest;
19
+ private session;
20
+ private maxWaitTimer;
21
+ private pendingChangesCount;
22
+ constructor(options: WatchModeOptions);
23
+ /**
24
+ * Start watch mode synchronization
25
+ */
26
+ start(): Promise<void>;
27
+ /**
28
+ * Stop watch mode synchronization
29
+ */
30
+ stop(): Promise<void>;
31
+ /**
32
+ * Pause watch mode (stop watching but keep state)
33
+ */
34
+ pause(): Promise<void>;
35
+ /**
36
+ * Resume watch mode after pause
37
+ */
38
+ resume(): Promise<void>;
39
+ /**
40
+ * Force an immediate sync
41
+ */
42
+ forceSync(): Promise<SyncResult>;
43
+ /**
44
+ * Get current status
45
+ */
46
+ getStatus(): WatchModeStatus;
47
+ /**
48
+ * Get current session information
49
+ */
50
+ getSession(): WatchModeSyncSession | null;
51
+ /**
52
+ * Handle batched file changes
53
+ */
54
+ private handleBatchChanges;
55
+ /**
56
+ * Trigger a sync operation
57
+ */
58
+ private triggerSync;
59
+ /**
60
+ * Perform the actual sync operation
61
+ */
62
+ private performSync;
63
+ /**
64
+ * Handle errors
65
+ */
66
+ private handleError;
67
+ /**
68
+ * Set state and emit status change
69
+ */
70
+ private setState;
71
+ /**
72
+ * Emit status change event
73
+ */
74
+ private emitStatusChange;
75
+ /**
76
+ * Emit an event
77
+ */
78
+ private emitEvent;
79
+ }
80
+ /**
81
+ * Create a watch mode sync instance with default options
82
+ */
83
+ export declare function createWatchModeSync(options: WatchModeOptions): WatchModeSync;
84
+ //# sourceMappingURL=watchMode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watchMode.d.ts","sourceRoot":"","sources":["../../src/sync/watchMode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAItC,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAGf,oBAAoB,EACpB,UAAU,EAEX,MAAM,YAAY,CAAC;AAEpB,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,OAAO,CAIb;IACF,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,cAAc,CAA2B;IACjD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,mBAAmB,CAAa;gBAE5B,OAAO,EAAE,gBAAgB;IAmBrC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6F5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAyC7B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC;IAItC;;OAEG;IACH,SAAS,IAAI,eAAe;IAc5B;;OAEG;IACH,UAAU,IAAI,oBAAoB,GAAG,IAAI;IAIzC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAWnB;;OAEG;YACW,WAAW;IAiFzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAOhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;OAEG;IACH,OAAO,CAAC,SAAS;CAMlB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAE5E"}