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,123 @@
1
+ import { theme, symbols } from './colors.js';
2
+ import { supportsColor } from '../utils/terminal.js';
3
+ /**
4
+ * Format sync results as formatted text
5
+ */
6
+ export function formatSyncResultTable(result) {
7
+ const hasColors = supportsColor();
8
+ const lines = [];
9
+ const rows = [
10
+ {
11
+ label: 'Files added',
12
+ value: result.filesAdded,
13
+ color: result.filesAdded > 0 ? theme.success : theme.muted,
14
+ symbol: result.filesAdded > 0 ? symbols.success : ' ',
15
+ },
16
+ {
17
+ label: 'Files updated',
18
+ value: result.filesUpdated,
19
+ color: result.filesUpdated > 0 ? theme.info : theme.muted,
20
+ symbol: result.filesUpdated > 0 ? symbols.info : ' ',
21
+ },
22
+ {
23
+ label: 'Files deleted',
24
+ value: result.filesDeleted,
25
+ color: result.filesDeleted > 0 ? theme.warning : theme.muted,
26
+ symbol: result.filesDeleted > 0 ? symbols.warning : ' ',
27
+ },
28
+ {
29
+ label: 'Conflicts',
30
+ value: result.conflicts.length,
31
+ color: result.conflicts.length > 0 ? theme.error : theme.muted,
32
+ symbol: result.conflicts.length > 0 ? symbols.error : ' ',
33
+ },
34
+ {
35
+ label: 'Skipped',
36
+ value: result.skipped.length,
37
+ color: result.skipped.length > 0 ? theme.muted : theme.muted,
38
+ symbol: ' ',
39
+ },
40
+ {
41
+ label: 'Errors',
42
+ value: result.errors.length,
43
+ color: result.errors.length > 0 ? theme.error : theme.muted,
44
+ symbol: result.errors.length > 0 ? symbols.error : ' ',
45
+ },
46
+ ];
47
+ for (const row of rows) {
48
+ const label = row.label.padEnd(15);
49
+ if (hasColors) {
50
+ lines.push(` ${row.symbol} ${theme.dim(label)} ${row.color(String(row.value))}`);
51
+ }
52
+ else {
53
+ lines.push(` ${label} ${row.value}`);
54
+ }
55
+ }
56
+ return lines.join('\n');
57
+ }
58
+ /**
59
+ * Format vault status information
60
+ */
61
+ export function formatVaultInfoTable(info) {
62
+ const hasColors = supportsColor();
63
+ const lines = [];
64
+ const rows = [
65
+ ['Name', info.name],
66
+ ['Path', info.path],
67
+ ['Files', String(info.fileCount)],
68
+ ['Total size', info.totalSize],
69
+ ['Last modified', info.lastModified],
70
+ ];
71
+ for (const [label, value] of rows) {
72
+ const paddedLabel = (label + ':').padEnd(16);
73
+ if (hasColors) {
74
+ lines.push(` ${theme.dim(paddedLabel)} ${value}`);
75
+ }
76
+ else {
77
+ lines.push(` ${paddedLabel} ${value}`);
78
+ }
79
+ }
80
+ return lines.join('\n');
81
+ }
82
+ /**
83
+ * Format sync status
84
+ */
85
+ export function formatSyncStatusTable(status) {
86
+ const hasColors = supportsColor();
87
+ const lines = [];
88
+ const rows = [
89
+ ['Sync ID', status.syncId],
90
+ ['Last sync', status.lastSync],
91
+ ['Tracked files', String(status.trackedFiles)],
92
+ ];
93
+ for (const [label, value] of rows) {
94
+ const paddedLabel = (label + ':').padEnd(16);
95
+ if (hasColors) {
96
+ lines.push(` ${theme.dim(paddedLabel)} ${value}`);
97
+ }
98
+ else {
99
+ lines.push(` ${paddedLabel} ${value}`);
100
+ }
101
+ }
102
+ return lines.join('\n');
103
+ }
104
+ /**
105
+ * Format a list of files with an optional header
106
+ */
107
+ export function formatFileList(files, header, maxItems = 10) {
108
+ if (files.length === 0)
109
+ return '';
110
+ const hasColors = supportsColor();
111
+ const lines = [];
112
+ lines.push(hasColors ? theme.bold(header) : header);
113
+ const displayFiles = files.slice(0, maxItems);
114
+ for (const file of displayFiles) {
115
+ lines.push(` ${hasColors ? symbols.bullet : '-'} ${file}`);
116
+ }
117
+ if (files.length > maxItems) {
118
+ const remaining = files.length - maxItems;
119
+ lines.push(hasColors ? theme.muted(` ... and ${remaining} more`) : ` ... and ${remaining} more`);
120
+ }
121
+ return lines.join('\n');
122
+ }
123
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../../../src/cli/ui/table.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Terminal detection utilities for graceful degradation
3
+ */
4
+ /**
5
+ * Check if the terminal is interactive (supports prompts)
6
+ * Returns false when piped, redirected, or in CI environments
7
+ */
8
+ export declare function isInteractive(): boolean;
9
+ /**
10
+ * Check if the terminal supports colors
11
+ */
12
+ export declare function supportsColor(): boolean;
13
+ /**
14
+ * Get terminal width, with a sensible default
15
+ */
16
+ export declare function getTerminalWidth(): number;
17
+ /**
18
+ * Clear the current line (useful for spinners)
19
+ */
20
+ export declare function clearLine(): void;
21
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/terminal.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAavC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAwBvC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,IAAI,CAKhC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Terminal detection utilities for graceful degradation
3
+ */
4
+ /**
5
+ * Check if the terminal is interactive (supports prompts)
6
+ * Returns false when piped, redirected, or in CI environments
7
+ */
8
+ export function isInteractive() {
9
+ // Check for CI environment variables
10
+ if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) {
11
+ return false;
12
+ }
13
+ // Check for non-interactive flags
14
+ if (process.env.TERM === 'dumb') {
15
+ return false;
16
+ }
17
+ // Check if stdin and stdout are TTYs
18
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
19
+ }
20
+ /**
21
+ * Check if the terminal supports colors
22
+ */
23
+ export function supportsColor() {
24
+ // Respect NO_COLOR standard
25
+ if ('NO_COLOR' in process.env) {
26
+ return false;
27
+ }
28
+ // Force color if explicitly requested
29
+ if (process.env.FORCE_COLOR) {
30
+ return true;
31
+ }
32
+ // Check if output is a TTY
33
+ if (!process.stdout.isTTY) {
34
+ return false;
35
+ }
36
+ // Check TERM environment variable
37
+ const term = process.env.TERM || '';
38
+ if (term === 'dumb') {
39
+ return false;
40
+ }
41
+ // Most modern terminals support color
42
+ return true;
43
+ }
44
+ /**
45
+ * Get terminal width, with a sensible default
46
+ */
47
+ export function getTerminalWidth() {
48
+ return process.stdout.columns || 80;
49
+ }
50
+ /**
51
+ * Clear the current line (useful for spinners)
52
+ */
53
+ export function clearLine() {
54
+ if (process.stdout.isTTY) {
55
+ process.stdout.clearLine(0);
56
+ process.stdout.cursorTo(0);
57
+ }
58
+ }
59
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../../src/cli/utils/terminal.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,qCAAqC;IACrC,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,CAAC;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kCAAkC;IAClC,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,qCAAqC;IACrC,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,4BAA4B;IAC5B,IAAI,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sCAAsC;IACtC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,2BAA2B;IAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kCAAkC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACpC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sCAAsC;IACtC,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { handleSyncCommand } from './cli/commands/sync.js';
4
+ import { handleInitCommand } from './cli/commands/init.js';
5
+ import { handleStatusCommand } from './cli/commands/status.js';
6
+ const program = new Command();
7
+ program
8
+ .name('obsync')
9
+ .description('A tool for synchronizing Obsidian vaults')
10
+ .version('0.1.0');
11
+ program
12
+ .command('sync')
13
+ .description('Synchronize an Obsidian vault')
14
+ .option('-s, --source <path>', 'Source vault path')
15
+ .option('-d, --destination <path>', 'Destination vault path')
16
+ .option('-c, --conflict <strategy>', 'Conflict resolution strategy (source|destination|newest|skip)', 'newest')
17
+ .option('--dry-run', 'Show what would be synced without making changes')
18
+ .option('-w, --watch', 'Watch for changes and sync continuously')
19
+ .option('-r, --remote', 'Allow destination to be a non-vault directory (e.g., Dropbox folder)')
20
+ .action(handleSyncCommand);
21
+ program
22
+ .command('init')
23
+ .description('Initialize obsync configuration for a vault')
24
+ .option('-p, --path <path>', 'Vault path (defaults to current directory)')
25
+ .action(handleInitCommand);
26
+ program
27
+ .command('status')
28
+ .description('Show sync status of a vault')
29
+ .option('-p, --path <path>', 'Vault path (defaults to current directory)')
30
+ .action(handleStatusCommand);
31
+ program.parse();
32
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,0CAA0C,CAAC;KACvD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,qBAAqB,EAAE,mBAAmB,CAAC;KAClD,MAAM,CAAC,0BAA0B,EAAE,wBAAwB,CAAC;KAC5D,MAAM,CACL,2BAA2B,EAC3B,+DAA+D,EAC/D,QAAQ,CACT;KACA,MAAM,CAAC,WAAW,EAAE,kDAAkD,CAAC;KACvE,MAAM,CAAC,aAAa,EAAE,yCAAyC,CAAC;KAChE,MAAM,CAAC,cAAc,EAAE,sEAAsE,CAAC;KAC9F,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAE7B,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,mBAAmB,EAAE,4CAA4C,CAAC;KACzE,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAE7B,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,mBAAmB,EAAE,4CAA4C,CAAC;KACzE,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAE/B,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Configuration file management for obsync.
3
+ * Handles reading, writing, and validating configuration files.
4
+ */
5
+ export interface ObsyncConfig {
6
+ vaults: VaultConfig[];
7
+ defaultSyncStrategy: 'incremental' | 'full';
8
+ conflictResolution: 'source' | 'destination' | 'newest' | 'skip';
9
+ excludePatterns: string[];
10
+ }
11
+ export interface VaultConfig {
12
+ name: string;
13
+ path: string;
14
+ remote?: RemoteConfig;
15
+ syncInterval?: number;
16
+ }
17
+ export interface RemoteConfig {
18
+ type: 'local' | 's3' | 'ftp';
19
+ path: string;
20
+ credentials?: Record<string, string>;
21
+ }
22
+ export declare class ConfigManager {
23
+ private static readonly CONFIG_FILENAME;
24
+ /**
25
+ * Load config from vault directory, returns default if doesn't exist
26
+ */
27
+ load(vaultPath: string): Promise<ObsyncConfig>;
28
+ /**
29
+ * Save config to vault directory
30
+ */
31
+ save(vaultPath: string, config: ObsyncConfig): Promise<void>;
32
+ /**
33
+ * Validate configuration structure
34
+ */
35
+ validate(config: ObsyncConfig): Promise<boolean>;
36
+ /**
37
+ * Get default configuration
38
+ */
39
+ getDefaultConfig(): ObsyncConfig;
40
+ /**
41
+ * Check if config file exists
42
+ */
43
+ exists(vaultPath: string): Promise<boolean>;
44
+ }
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,mBAAmB,EAAE,aAAa,GAAG,MAAM,CAAC;IAC5C,kBAAkB,EAAE,QAAQ,GAAG,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjE,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,KAAK,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAEzD;;OAEG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAyBpD;;OAEG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlE;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IAqCtD;;OAEG;IACH,gBAAgB,IAAI,YAAY;IAgBhC;;OAEG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CASlD"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Configuration file management for obsync.
3
+ * Handles reading, writing, and validating configuration files.
4
+ */
5
+ import { promises as fs } from 'fs';
6
+ import path from 'path';
7
+ export class ConfigManager {
8
+ static CONFIG_FILENAME = '.obsync.json';
9
+ /**
10
+ * Load config from vault directory, returns default if doesn't exist
11
+ */
12
+ async load(vaultPath) {
13
+ const configPath = path.join(vaultPath, ConfigManager.CONFIG_FILENAME);
14
+ try {
15
+ const content = await fs.readFile(configPath, 'utf-8');
16
+ const config = JSON.parse(content);
17
+ // Validate loaded config
18
+ const isValid = await this.validate(config);
19
+ if (!isValid) {
20
+ throw new Error('Invalid configuration file');
21
+ }
22
+ return config;
23
+ }
24
+ catch (error) {
25
+ if (error.code === 'ENOENT') {
26
+ // Return default config if file doesn't exist
27
+ return this.getDefaultConfig();
28
+ }
29
+ throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
30
+ }
31
+ }
32
+ /**
33
+ * Save config to vault directory
34
+ */
35
+ async save(vaultPath, config) {
36
+ const configPath = path.join(vaultPath, ConfigManager.CONFIG_FILENAME);
37
+ // Validate before saving
38
+ const isValid = await this.validate(config);
39
+ if (!isValid) {
40
+ throw new Error('Cannot save invalid configuration');
41
+ }
42
+ try {
43
+ await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
44
+ }
45
+ catch (error) {
46
+ throw new Error(`Failed to save config: ${error instanceof Error ? error.message : String(error)}`);
47
+ }
48
+ }
49
+ /**
50
+ * Validate configuration structure
51
+ */
52
+ async validate(config) {
53
+ // Check required fields
54
+ if (!config || typeof config !== 'object') {
55
+ return false;
56
+ }
57
+ if (!Array.isArray(config.vaults)) {
58
+ return false;
59
+ }
60
+ if (!['incremental', 'full'].includes(config.defaultSyncStrategy)) {
61
+ return false;
62
+ }
63
+ if (!['source', 'destination', 'newest', 'skip'].includes(config.conflictResolution)) {
64
+ return false;
65
+ }
66
+ if (!Array.isArray(config.excludePatterns)) {
67
+ return false;
68
+ }
69
+ // Validate each vault config
70
+ for (const vault of config.vaults) {
71
+ if (!vault.name || typeof vault.name !== 'string') {
72
+ return false;
73
+ }
74
+ if (!vault.path || typeof vault.path !== 'string') {
75
+ return false;
76
+ }
77
+ }
78
+ return true;
79
+ }
80
+ /**
81
+ * Get default configuration
82
+ */
83
+ getDefaultConfig() {
84
+ return {
85
+ vaults: [],
86
+ defaultSyncStrategy: 'incremental',
87
+ conflictResolution: 'newest',
88
+ excludePatterns: [
89
+ '.obsidian/**',
90
+ '.trash/**',
91
+ '.git/**',
92
+ '.obsync/**',
93
+ '*.tmp',
94
+ '**/.DS_Store',
95
+ ],
96
+ };
97
+ }
98
+ /**
99
+ * Check if config file exists
100
+ */
101
+ async exists(vaultPath) {
102
+ const configPath = path.join(vaultPath, ConfigManager.CONFIG_FILENAME);
103
+ try {
104
+ await fs.access(configPath);
105
+ return true;
106
+ }
107
+ catch {
108
+ return false;
109
+ }
110
+ }
111
+ }
112
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export * from './sync/index.js';
2
+ export * from './storage/index.js';
3
+ export { ObsidianVault, type VaultMetadata } from './vault/index.js';
4
+ export type { VaultConfig, ObsyncConfig, RemoteConfig, ConfigManager } from './config/index.js';
5
+ export * from './utils/index.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACrE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAChG,cAAc,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './sync/index.js';
2
+ export * from './storage/index.js';
3
+ export { ObsidianVault } from './vault/index.js';
4
+ export * from './utils/index.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,aAAa,EAAsB,MAAM,kBAAkB,CAAC;AAErE,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Storage adapters for different backends (local filesystem, S3, etc.).
3
+ * All adapters implement the StorageAdapter interface for consistency.
4
+ */
5
+ export interface StorageAdapter {
6
+ read(path: string): Promise<Buffer>;
7
+ write(path: string, content: Buffer): Promise<void>;
8
+ delete(path: string): Promise<void>;
9
+ list(prefix: string): Promise<string[]>;
10
+ exists(path: string): Promise<boolean>;
11
+ }
12
+ export declare class LocalStorageAdapter implements StorageAdapter {
13
+ /**
14
+ * Read a file and return its contents as a Buffer
15
+ */
16
+ read(filePath: string): Promise<Buffer>;
17
+ /**
18
+ * Write content to a file, creating parent directories if needed
19
+ */
20
+ write(filePath: string, content: Buffer): Promise<void>;
21
+ /**
22
+ * Delete a file. Does not throw if file doesn't exist.
23
+ */
24
+ delete(filePath: string): Promise<void>;
25
+ /**
26
+ * List all files recursively under a directory prefix.
27
+ * Returns paths relative to the prefix.
28
+ */
29
+ list(prefix: string): Promise<string[]>;
30
+ /**
31
+ * Check if a file or directory exists
32
+ */
33
+ exists(filePath: string): Promise<boolean>;
34
+ }
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxC;AAED,qBAAa,mBAAoB,YAAW,cAAc;IACxD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAY7C;;OAEG;IACG,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW7D;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7C;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAgC7C;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CASjD"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Storage adapters for different backends (local filesystem, S3, etc.).
3
+ * All adapters implement the StorageAdapter interface for consistency.
4
+ */
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+ import { sanitizePath } from '../utils/index.js';
8
+ export class LocalStorageAdapter {
9
+ /**
10
+ * Read a file and return its contents as a Buffer
11
+ */
12
+ async read(filePath) {
13
+ try {
14
+ const normalizedPath = sanitizePath(filePath);
15
+ return await fs.readFile(normalizedPath);
16
+ }
17
+ catch (error) {
18
+ if (error.code === 'ENOENT') {
19
+ throw new Error(`File not found: ${filePath}`);
20
+ }
21
+ throw error;
22
+ }
23
+ }
24
+ /**
25
+ * Write content to a file, creating parent directories if needed
26
+ */
27
+ async write(filePath, content) {
28
+ const normalizedPath = sanitizePath(filePath);
29
+ const dir = path.dirname(normalizedPath);
30
+ // Ensure parent directory exists
31
+ await fs.mkdir(dir, { recursive: true });
32
+ // Write the file
33
+ await fs.writeFile(normalizedPath, content);
34
+ }
35
+ /**
36
+ * Delete a file. Does not throw if file doesn't exist.
37
+ */
38
+ async delete(filePath) {
39
+ try {
40
+ const normalizedPath = sanitizePath(filePath);
41
+ await fs.unlink(normalizedPath);
42
+ }
43
+ catch (error) {
44
+ // If file doesn't exist, consider it a success
45
+ if (error.code !== 'ENOENT') {
46
+ throw error;
47
+ }
48
+ }
49
+ }
50
+ /**
51
+ * List all files recursively under a directory prefix.
52
+ * Returns paths relative to the prefix.
53
+ */
54
+ async list(prefix) {
55
+ const normalizedPrefix = sanitizePath(prefix);
56
+ const files = [];
57
+ async function traverse(dir, relativePath = '') {
58
+ try {
59
+ const entries = await fs.readdir(dir, { withFileTypes: true });
60
+ for (const entry of entries) {
61
+ const fullPath = path.join(dir, entry.name);
62
+ const relPath = relativePath ? path.join(relativePath, entry.name) : entry.name;
63
+ if (entry.isDirectory()) {
64
+ await traverse(fullPath, relPath);
65
+ }
66
+ else if (entry.isFile()) {
67
+ files.push(sanitizePath(relPath));
68
+ }
69
+ // Note: Following symlinks in Phase 1 as per plan
70
+ }
71
+ }
72
+ catch (error) {
73
+ if (error.code === 'ENOENT') {
74
+ // Directory doesn't exist, return empty list
75
+ return;
76
+ }
77
+ throw error;
78
+ }
79
+ }
80
+ await traverse(normalizedPrefix);
81
+ return files.sort(); // Return sorted for consistency
82
+ }
83
+ /**
84
+ * Check if a file or directory exists
85
+ */
86
+ async exists(filePath) {
87
+ try {
88
+ const normalizedPath = sanitizePath(filePath);
89
+ await fs.access(normalizedPath);
90
+ return true;
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ }
97
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Change detection using three-way merge algorithm.
3
+ * Compares source, destination, and base (last sync state) to detect changes.
4
+ */
5
+ import type { FileChange, SyncManifest } from './types.js';
6
+ import type { StorageAdapter } from '../storage/index.js';
7
+ export declare class ChangeDetector {
8
+ private sourceAdapter;
9
+ private destAdapter;
10
+ constructor(sourceAdapter: StorageAdapter, destAdapter: StorageAdapter);
11
+ /**
12
+ * Detect all changes between source and destination using three-way merge.
13
+ * @param sourcePath - Source vault path
14
+ * @param destPath - Destination vault path
15
+ * @param sourceManifest - Source manifest (base state)
16
+ * @param destManifest - Destination manifest (base state)
17
+ * @param fileList - List of files to check (from vault listing)
18
+ */
19
+ detectChanges(sourcePath: string, destPath: string, sourceManifest: SyncManifest | null, destManifest: SyncManifest | null, fileList: string[]): Promise<FileChange[]>;
20
+ /**
21
+ * Determine change type using three-way merge algorithm
22
+ */
23
+ private determineChangeType;
24
+ /**
25
+ * Get current file state (hash, size, mtime)
26
+ */
27
+ private getFileState;
28
+ }
29
+ //# sourceMappingURL=changeDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changeDetector.d.ts","sourceRoot":"","sources":["../../src/sync/changeDetector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,qBAAa,cAAc;IAEvB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,WAAW;gBADX,aAAa,EAAE,cAAc,EAC7B,WAAW,EAAE,cAAc;IAGrC;;;;;;;OAOG;IACG,aAAa,CACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,YAAY,GAAG,IAAI,EACnC,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC;IA8GxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA6H3B;;OAEG;YACW,YAAY;CAwB3B"}