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,293 @@
1
+ /**
2
+ * FileWatcher - Watches directories for file changes with debouncing.
3
+ * Uses chokidar for cross-platform file watching.
4
+ */
5
+ import * as chokidar from 'chokidar';
6
+ import path from 'path';
7
+ import { EventEmitter } from 'events';
8
+ import picomatch from 'picomatch';
9
+ export class FileWatcher extends EventEmitter {
10
+ watchers = new Map();
11
+ pendingChanges = new Map();
12
+ debounceTimers = new Map();
13
+ debounceMs;
14
+ ignorePatterns;
15
+ ignoreMatchers;
16
+ ignoreInitial;
17
+ usePolling;
18
+ pollInterval;
19
+ depth;
20
+ isReady = new Map();
21
+ lastEventTime = null;
22
+ isStopped = false;
23
+ constructor(options = {}) {
24
+ super();
25
+ this.debounceMs = options.debounceMs ?? 300;
26
+ this.ignorePatterns = options.ignorePatterns ?? [
27
+ '.obsidian/**',
28
+ '.trash/**',
29
+ '.git/**',
30
+ '.obsync/**',
31
+ '.DS_Store',
32
+ 'Thumbs.db',
33
+ '*.tmp',
34
+ '*.temp',
35
+ ];
36
+ this.ignoreMatchers = this.ignorePatterns.map((pattern) => picomatch(pattern, { dot: true }));
37
+ this.ignoreInitial = options.ignoreInitial ?? true;
38
+ // Use polling by default for better cross-platform compatibility
39
+ this.usePolling = options.usePolling ?? true;
40
+ this.pollInterval = options.pollInterval ?? 100;
41
+ this.depth = options.depth;
42
+ }
43
+ /**
44
+ * Start watching a directory for file changes
45
+ */
46
+ watch(watchPath) {
47
+ if (this.isStopped) {
48
+ throw new Error('Watcher has been stopped. Create a new instance to watch again.');
49
+ }
50
+ const normalizedPath = path.resolve(watchPath);
51
+ if (this.watchers.has(normalizedPath)) {
52
+ return; // Already watching this path
53
+ }
54
+ this.isReady.set(normalizedPath, false);
55
+ const watcher = chokidar.watch(normalizedPath, {
56
+ ignored: (filePath) => this.shouldIgnore(filePath, normalizedPath),
57
+ persistent: true,
58
+ ignoreInitial: this.ignoreInitial,
59
+ usePolling: this.usePolling,
60
+ interval: this.pollInterval,
61
+ binaryInterval: this.pollInterval,
62
+ depth: this.depth,
63
+ atomic: true,
64
+ awaitWriteFinish: {
65
+ stabilityThreshold: 50,
66
+ pollInterval: 25,
67
+ },
68
+ });
69
+ watcher.on('add', (filePath) => this.handleEvent('add', filePath, normalizedPath));
70
+ watcher.on('change', (filePath) => this.handleEvent('change', filePath, normalizedPath));
71
+ watcher.on('unlink', (filePath) => this.handleEvent('unlink', filePath, normalizedPath));
72
+ watcher.on('error', (error) => this.emit('error', error));
73
+ watcher.on('ready', () => {
74
+ this.isReady.set(normalizedPath, true);
75
+ if (this.areAllWatchersReady()) {
76
+ this.emit('ready');
77
+ }
78
+ });
79
+ this.watchers.set(normalizedPath, watcher);
80
+ }
81
+ /**
82
+ * Watch multiple directories
83
+ */
84
+ watchMultiple(paths) {
85
+ for (const watchPath of paths) {
86
+ this.watch(watchPath);
87
+ }
88
+ }
89
+ /**
90
+ * Stop watching a specific directory
91
+ */
92
+ async unwatch(watchPath) {
93
+ const normalizedPath = path.resolve(watchPath);
94
+ const watcher = this.watchers.get(normalizedPath);
95
+ if (watcher) {
96
+ await watcher.close();
97
+ this.watchers.delete(normalizedPath);
98
+ this.isReady.delete(normalizedPath);
99
+ // Clear any pending debounce timers for this path
100
+ for (const [key, timer] of this.debounceTimers.entries()) {
101
+ if (key.startsWith(normalizedPath)) {
102
+ clearTimeout(timer);
103
+ this.debounceTimers.delete(key);
104
+ }
105
+ }
106
+ // Clear pending changes for this path
107
+ for (const [key] of this.pendingChanges.entries()) {
108
+ if (key.startsWith(normalizedPath)) {
109
+ this.pendingChanges.delete(key);
110
+ }
111
+ }
112
+ }
113
+ }
114
+ /**
115
+ * Stop watching all directories and clean up
116
+ */
117
+ async stop() {
118
+ this.isStopped = true;
119
+ // Clear all debounce timers
120
+ for (const timer of this.debounceTimers.values()) {
121
+ clearTimeout(timer);
122
+ }
123
+ this.debounceTimers.clear();
124
+ // Close all watchers
125
+ const closePromises = Array.from(this.watchers.values()).map((w) => w.close());
126
+ await Promise.all(closePromises);
127
+ this.watchers.clear();
128
+ this.pendingChanges.clear();
129
+ this.isReady.clear();
130
+ this.removeAllListeners();
131
+ }
132
+ /**
133
+ * Get current watcher status
134
+ */
135
+ getStatus() {
136
+ return {
137
+ isWatching: this.watchers.size > 0,
138
+ watchedPaths: Array.from(this.watchers.keys()),
139
+ pendingChanges: this.pendingChanges.size,
140
+ lastEventTime: this.lastEventTime,
141
+ };
142
+ }
143
+ /**
144
+ * Check if all watchers are ready
145
+ */
146
+ areAllWatchersReady() {
147
+ if (this.watchers.size === 0)
148
+ return false;
149
+ return Array.from(this.isReady.values()).every((ready) => ready);
150
+ }
151
+ /**
152
+ * Force flush all pending changes immediately
153
+ */
154
+ flushPendingChanges() {
155
+ // Clear all debounce timers
156
+ for (const timer of this.debounceTimers.values()) {
157
+ clearTimeout(timer);
158
+ }
159
+ this.debounceTimers.clear();
160
+ const changes = Array.from(this.pendingChanges.values());
161
+ this.pendingChanges.clear();
162
+ return changes;
163
+ }
164
+ /**
165
+ * Get count of pending changes
166
+ */
167
+ getPendingCount() {
168
+ return this.pendingChanges.size;
169
+ }
170
+ /**
171
+ * Handle file system events with debouncing
172
+ */
173
+ handleEvent(type, filePath, watchedPath) {
174
+ if (this.isStopped)
175
+ return;
176
+ const normalizedFilePath = path.resolve(filePath);
177
+ const relativePath = path.relative(watchedPath, normalizedFilePath);
178
+ // Skip events for the base directory itself
179
+ if (this.shouldSkipEvent(normalizedFilePath, watchedPath)) {
180
+ return;
181
+ }
182
+ this.lastEventTime = new Date();
183
+ const event = {
184
+ type,
185
+ path: normalizedFilePath,
186
+ relativePath: relativePath.replace(/\\/g, '/'), // Normalize to forward slashes
187
+ watchedPath,
188
+ };
189
+ // Use the relative path as key to properly coalesce events
190
+ const eventKey = `${watchedPath}:${relativePath}`;
191
+ // Store/update the pending change
192
+ this.pendingChanges.set(eventKey, event);
193
+ // Emit immediate change event
194
+ this.emit('change', event);
195
+ // Clear existing debounce timer for this file
196
+ const existingTimer = this.debounceTimers.get(eventKey);
197
+ if (existingTimer) {
198
+ clearTimeout(existingTimer);
199
+ }
200
+ // Set new debounce timer
201
+ const timer = setTimeout(() => {
202
+ this.debounceTimers.delete(eventKey);
203
+ const pendingEvent = this.pendingChanges.get(eventKey);
204
+ if (pendingEvent) {
205
+ this.pendingChanges.delete(eventKey);
206
+ this.emit('debounced', pendingEvent);
207
+ }
208
+ }, this.debounceMs);
209
+ this.debounceTimers.set(eventKey, timer);
210
+ }
211
+ /**
212
+ * Check if a path should be ignored (for the ignored option passed to chokidar)
213
+ */
214
+ shouldIgnore(filePath, watchedPath) {
215
+ const relativePath = path.relative(watchedPath, filePath).replace(/\\/g, '/');
216
+ // Never ignore the base path itself - we need to watch it
217
+ if (relativePath === '' || relativePath === '.') {
218
+ return false;
219
+ }
220
+ // Check against ignore patterns
221
+ return this.ignoreMatchers.some((matcher) => matcher(relativePath));
222
+ }
223
+ /**
224
+ * Check if an event should be skipped (for internal filtering)
225
+ */
226
+ shouldSkipEvent(filePath, watchedPath) {
227
+ const relativePath = path.relative(watchedPath, filePath).replace(/\\/g, '/');
228
+ // Skip events for the base path itself
229
+ if (relativePath === '' || relativePath === '.') {
230
+ return true;
231
+ }
232
+ return false;
233
+ }
234
+ }
235
+ /**
236
+ * Create a debounced batch watcher that collects multiple changes
237
+ * and emits them as a batch after a delay
238
+ */
239
+ export class BatchFileWatcher extends FileWatcher {
240
+ batchTimer = null;
241
+ batchedChanges = new Map();
242
+ batchDelayMs;
243
+ constructor(options = {}) {
244
+ super(options);
245
+ this.batchDelayMs = options.batchDelayMs ?? 500;
246
+ // Override debounced event to collect into batch
247
+ this.on('debounced', (event) => {
248
+ const key = `${event.watchedPath}:${event.relativePath}`;
249
+ this.batchedChanges.set(key, event);
250
+ this.scheduleBatchEmit();
251
+ });
252
+ }
253
+ scheduleBatchEmit() {
254
+ if (this.batchTimer) {
255
+ clearTimeout(this.batchTimer);
256
+ }
257
+ this.batchTimer = setTimeout(() => {
258
+ const batch = Array.from(this.batchedChanges.values());
259
+ this.batchedChanges.clear();
260
+ this.batchTimer = null;
261
+ if (batch.length > 0) {
262
+ this.emit('batch', batch);
263
+ }
264
+ }, this.batchDelayMs);
265
+ }
266
+ /**
267
+ * Get current batch
268
+ */
269
+ getCurrentBatch() {
270
+ return Array.from(this.batchedChanges.values());
271
+ }
272
+ /**
273
+ * Force emit current batch immediately
274
+ */
275
+ flushBatch() {
276
+ if (this.batchTimer) {
277
+ clearTimeout(this.batchTimer);
278
+ this.batchTimer = null;
279
+ }
280
+ const batch = Array.from(this.batchedChanges.values());
281
+ this.batchedChanges.clear();
282
+ return batch;
283
+ }
284
+ async stop() {
285
+ if (this.batchTimer) {
286
+ clearTimeout(this.batchTimer);
287
+ this.batchTimer = null;
288
+ }
289
+ this.batchedChanges.clear();
290
+ await super.stop();
291
+ }
292
+ }
293
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Shared utility functions used across the application.
3
+ */
4
+ export declare function computeFileHash(content: Buffer): string;
5
+ export declare function sanitizePath(path: string): string;
6
+ export declare function isMarkdownFile(filename: string): boolean;
7
+ export declare function formatBytes(bytes: number): string;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWjD"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared utility functions used across the application.
3
+ */
4
+ import * as crypto from 'crypto';
5
+ export function computeFileHash(content) {
6
+ return crypto.createHash('sha256').update(content).digest('hex');
7
+ }
8
+ export function sanitizePath(path) {
9
+ // TODO: Implement path sanitization
10
+ return path.replace(/\\/g, '/');
11
+ }
12
+ export function isMarkdownFile(filename) {
13
+ return filename.endsWith('.md');
14
+ }
15
+ export function formatBytes(bytes) {
16
+ const units = ['B', 'KB', 'MB', 'GB'];
17
+ let size = bytes;
18
+ let unitIndex = 0;
19
+ while (size >= 1024 && unitIndex < units.length - 1) {
20
+ size /= 1024;
21
+ unitIndex++;
22
+ }
23
+ return `${size.toFixed(2)} ${units[unitIndex]}`;
24
+ }
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,oCAAoC;IACpC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtC,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,OAAO,IAAI,IAAI,IAAI,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,IAAI,IAAI,IAAI,CAAC;QACb,SAAS,EAAE,CAAC;IACd,CAAC;IAED,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Obsidian vault-specific operations.
3
+ * Handles vault structure parsing, metadata extraction, and validation.
4
+ */
5
+ export interface VaultMetadata {
6
+ name: string;
7
+ path: string;
8
+ fileCount: number;
9
+ totalSize: number;
10
+ lastModified: Date;
11
+ }
12
+ export interface VaultConfig {
13
+ vaultPath: string;
14
+ excludePatterns?: string[];
15
+ includePatterns?: string[];
16
+ }
17
+ export declare class ObsidianVault {
18
+ private readonly config;
19
+ private storage;
20
+ constructor(config: VaultConfig);
21
+ /**
22
+ * Get metadata about the vault (file count, total size, last modified)
23
+ */
24
+ getMetadata(): Promise<VaultMetadata>;
25
+ /**
26
+ * List all files in the vault, applying include and exclude patterns
27
+ */
28
+ listFiles(): Promise<string[]>;
29
+ /**
30
+ * Validate that this is a proper Obsidian vault structure
31
+ */
32
+ validateStructure(): Promise<boolean>;
33
+ /**
34
+ * Check if a given path is an Obsidian vault (has .obsidian directory)
35
+ */
36
+ isObsidianVault(vaultPath?: string): Promise<boolean>;
37
+ }
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vault/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AASD,qBAAa,aAAa;IAGZ,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,OAAO,CAAsB;gBAER,MAAM,EAAE,WAAW;IAIhD;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,aAAa,CAAC;IA4B3C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IA2BpC;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAsB3C;;OAEG;IACG,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAK5D"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Obsidian vault-specific operations.
3
+ * Handles vault structure parsing, metadata extraction, and validation.
4
+ */
5
+ import * as path from 'path';
6
+ import * as fs from 'fs/promises';
7
+ import picomatch from 'picomatch';
8
+ import { LocalStorageAdapter } from '../storage/index.js';
9
+ const DEFAULT_EXCLUDE_PATTERNS = [
10
+ '.obsidian/**',
11
+ '.trash/**',
12
+ '.git/**',
13
+ '.obsync/**',
14
+ ];
15
+ export class ObsidianVault {
16
+ config;
17
+ storage;
18
+ constructor(config) {
19
+ this.config = config;
20
+ this.storage = new LocalStorageAdapter();
21
+ }
22
+ /**
23
+ * Get metadata about the vault (file count, total size, last modified)
24
+ */
25
+ async getMetadata() {
26
+ const files = await this.listFiles();
27
+ let totalSize = 0;
28
+ let lastModified = new Date(0);
29
+ for (const file of files) {
30
+ const fullPath = path.join(this.config.vaultPath, file);
31
+ try {
32
+ const stats = await fs.stat(fullPath);
33
+ totalSize += stats.size;
34
+ if (stats.mtime > lastModified) {
35
+ lastModified = stats.mtime;
36
+ }
37
+ }
38
+ catch {
39
+ // Skip files that can't be read
40
+ continue;
41
+ }
42
+ }
43
+ return {
44
+ name: path.basename(this.config.vaultPath),
45
+ path: this.config.vaultPath,
46
+ fileCount: files.length,
47
+ totalSize,
48
+ lastModified,
49
+ };
50
+ }
51
+ /**
52
+ * List all files in the vault, applying include and exclude patterns
53
+ */
54
+ async listFiles() {
55
+ const allFiles = await this.storage.list(this.config.vaultPath);
56
+ // Get exclude patterns (defaults + user-specified)
57
+ const excludePatterns = [
58
+ ...DEFAULT_EXCLUDE_PATTERNS,
59
+ ...(this.config.excludePatterns || []),
60
+ ];
61
+ // Create matchers
62
+ const excludeMatcher = picomatch(excludePatterns);
63
+ const includeMatcher = this.config.includePatterns
64
+ ? picomatch(this.config.includePatterns)
65
+ : null;
66
+ // Filter files based on patterns
67
+ return allFiles.filter((file) => {
68
+ // If include patterns specified, file must match one
69
+ if (includeMatcher && !includeMatcher(file)) {
70
+ return false;
71
+ }
72
+ // File must not match any exclude pattern
73
+ return !excludeMatcher(file);
74
+ });
75
+ }
76
+ /**
77
+ * Validate that this is a proper Obsidian vault structure
78
+ */
79
+ async validateStructure() {
80
+ const obsidianDir = path.join(this.config.vaultPath, '.obsidian');
81
+ // Check if .obsidian directory exists
82
+ if (!(await this.storage.exists(obsidianDir))) {
83
+ return false;
84
+ }
85
+ // Check for at least one of the common Obsidian config files
86
+ const configFiles = ['app.json', 'appearance.json', 'config'];
87
+ for (const configFile of configFiles) {
88
+ const configPath = path.join(obsidianDir, configFile);
89
+ if (await this.storage.exists(configPath)) {
90
+ return true;
91
+ }
92
+ }
93
+ // If .obsidian exists but no config files, still consider it valid
94
+ // (might be a new vault)
95
+ return true;
96
+ }
97
+ /**
98
+ * Check if a given path is an Obsidian vault (has .obsidian directory)
99
+ */
100
+ async isObsidianVault(vaultPath) {
101
+ const checkPath = vaultPath || this.config.vaultPath;
102
+ const obsidianDir = path.join(checkPath, '.obsidian');
103
+ return await this.storage.exists(obsidianDir);
104
+ }
105
+ }
106
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vault/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "obsyncd",
3
+ "version": "1.0.0",
4
+ "description": "A tool for synchronizing Obsidian vaults across devices via Dropbox, Google Drive, or any shared folder",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "bin": {
9
+ "obsyncd": "./dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "scripts": {
17
+ "dev": "bun --watch src/cli.ts",
18
+ "build": "tsc",
19
+ "start": "node dist/cli.js",
20
+ "test": "vitest run",
21
+ "test:watch": "vitest",
22
+ "test:ui": "vitest --ui",
23
+ "lint": "eslint src tests --ext .ts",
24
+ "lint:fix": "eslint src tests --ext .ts --fix",
25
+ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
26
+ "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
27
+ "typecheck": "tsc --noEmit"
28
+ },
29
+ "keywords": [
30
+ "obsidian",
31
+ "sync",
32
+ "vault",
33
+ "backup",
34
+ "synchronization",
35
+ "dropbox",
36
+ "google-drive",
37
+ "icloud",
38
+ "notes",
39
+ "markdown"
40
+ ],
41
+ "author": "",
42
+ "license": "MIT",
43
+ "dependencies": {
44
+ "@inquirer/prompts": "^8.1.0",
45
+ "chokidar": "3",
46
+ "commander": "^12.1.0",
47
+ "ora": "^9.0.0",
48
+ "picocolors": "^1.1.1",
49
+ "picomatch": "^4.0.3",
50
+ "uuid": "^13.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@eslint/js": "^9.39.2",
54
+ "@types/node": "^22.10.5",
55
+ "@types/picomatch": "^4.0.2",
56
+ "@typescript-eslint/eslint-plugin": "^8.19.1",
57
+ "@typescript-eslint/parser": "^8.19.1",
58
+ "eslint": "^9.18.0",
59
+ "prettier": "^3.4.2",
60
+ "tsx": "^4.19.2",
61
+ "typescript": "^5.7.2",
62
+ "typescript-eslint": "^8.52.0",
63
+ "vitest": "^2.1.8"
64
+ },
65
+ "engines": {
66
+ "node": ">=18.0.0"
67
+ }
68
+ }