contextmate 0.1.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 (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -0
  3. package/dist/src/adapters/base.d.ts +32 -0
  4. package/dist/src/adapters/base.d.ts.map +1 -0
  5. package/dist/src/adapters/base.js +49 -0
  6. package/dist/src/adapters/base.js.map +1 -0
  7. package/dist/src/adapters/claude.d.ts +30 -0
  8. package/dist/src/adapters/claude.d.ts.map +1 -0
  9. package/dist/src/adapters/claude.js +534 -0
  10. package/dist/src/adapters/claude.js.map +1 -0
  11. package/dist/src/adapters/index.d.ts +7 -0
  12. package/dist/src/adapters/index.d.ts.map +1 -0
  13. package/dist/src/adapters/index.js +16 -0
  14. package/dist/src/adapters/index.js.map +1 -0
  15. package/dist/src/adapters/openclaw.d.ts +15 -0
  16. package/dist/src/adapters/openclaw.d.ts.map +1 -0
  17. package/dist/src/adapters/openclaw.js +198 -0
  18. package/dist/src/adapters/openclaw.js.map +1 -0
  19. package/dist/src/bin/contextmate.d.ts +3 -0
  20. package/dist/src/bin/contextmate.d.ts.map +1 -0
  21. package/dist/src/bin/contextmate.js +4 -0
  22. package/dist/src/bin/contextmate.js.map +1 -0
  23. package/dist/src/cli/adapter.d.ts +3 -0
  24. package/dist/src/cli/adapter.d.ts.map +1 -0
  25. package/dist/src/cli/adapter.js +187 -0
  26. package/dist/src/cli/adapter.js.map +1 -0
  27. package/dist/src/cli/daemon.d.ts +3 -0
  28. package/dist/src/cli/daemon.d.ts.map +1 -0
  29. package/dist/src/cli/daemon.js +212 -0
  30. package/dist/src/cli/daemon.js.map +1 -0
  31. package/dist/src/cli/files.d.ts +3 -0
  32. package/dist/src/cli/files.d.ts.map +1 -0
  33. package/dist/src/cli/files.js +158 -0
  34. package/dist/src/cli/files.js.map +1 -0
  35. package/dist/src/cli/index.d.ts +3 -0
  36. package/dist/src/cli/index.d.ts.map +1 -0
  37. package/dist/src/cli/index.js +20 -0
  38. package/dist/src/cli/index.js.map +1 -0
  39. package/dist/src/cli/init.d.ts +3 -0
  40. package/dist/src/cli/init.d.ts.map +1 -0
  41. package/dist/src/cli/init.js +88 -0
  42. package/dist/src/cli/init.js.map +1 -0
  43. package/dist/src/cli/log.d.ts +3 -0
  44. package/dist/src/cli/log.d.ts.map +1 -0
  45. package/dist/src/cli/log.js +141 -0
  46. package/dist/src/cli/log.js.map +1 -0
  47. package/dist/src/cli/mcp.d.ts +3 -0
  48. package/dist/src/cli/mcp.d.ts.map +1 -0
  49. package/dist/src/cli/mcp.js +186 -0
  50. package/dist/src/cli/mcp.js.map +1 -0
  51. package/dist/src/cli/status.d.ts +3 -0
  52. package/dist/src/cli/status.d.ts.map +1 -0
  53. package/dist/src/cli/status.js +107 -0
  54. package/dist/src/cli/status.js.map +1 -0
  55. package/dist/src/config.d.ts +42 -0
  56. package/dist/src/config.d.ts.map +1 -0
  57. package/dist/src/config.js +93 -0
  58. package/dist/src/config.js.map +1 -0
  59. package/dist/src/crypto/auth.d.ts +4 -0
  60. package/dist/src/crypto/auth.d.ts.map +1 -0
  61. package/dist/src/crypto/auth.js +21 -0
  62. package/dist/src/crypto/auth.js.map +1 -0
  63. package/dist/src/crypto/encrypt.d.ts +9 -0
  64. package/dist/src/crypto/encrypt.d.ts.map +1 -0
  65. package/dist/src/crypto/encrypt.js +39 -0
  66. package/dist/src/crypto/encrypt.js.map +1 -0
  67. package/dist/src/crypto/index.d.ts +4 -0
  68. package/dist/src/crypto/index.d.ts.map +1 -0
  69. package/dist/src/crypto/index.js +4 -0
  70. package/dist/src/crypto/index.js.map +1 -0
  71. package/dist/src/crypto/keys.d.ts +9 -0
  72. package/dist/src/crypto/keys.d.ts.map +1 -0
  73. package/dist/src/crypto/keys.js +43 -0
  74. package/dist/src/crypto/keys.js.map +1 -0
  75. package/dist/src/mcp/embeddings.d.ts +16 -0
  76. package/dist/src/mcp/embeddings.d.ts.map +1 -0
  77. package/dist/src/mcp/embeddings.js +237 -0
  78. package/dist/src/mcp/embeddings.js.map +1 -0
  79. package/dist/src/mcp/index.d.ts +10 -0
  80. package/dist/src/mcp/index.d.ts.map +1 -0
  81. package/dist/src/mcp/index.js +6 -0
  82. package/dist/src/mcp/index.js.map +1 -0
  83. package/dist/src/mcp/rerank.d.ts +14 -0
  84. package/dist/src/mcp/rerank.d.ts.map +1 -0
  85. package/dist/src/mcp/rerank.js +47 -0
  86. package/dist/src/mcp/rerank.js.map +1 -0
  87. package/dist/src/mcp/scope.d.ts +26 -0
  88. package/dist/src/mcp/scope.d.ts.map +1 -0
  89. package/dist/src/mcp/scope.js +71 -0
  90. package/dist/src/mcp/scope.js.map +1 -0
  91. package/dist/src/mcp/search.d.ts +18 -0
  92. package/dist/src/mcp/search.d.ts.map +1 -0
  93. package/dist/src/mcp/search.js +110 -0
  94. package/dist/src/mcp/search.js.map +1 -0
  95. package/dist/src/mcp/server.d.ts +15 -0
  96. package/dist/src/mcp/server.d.ts.map +1 -0
  97. package/dist/src/mcp/server.js +340 -0
  98. package/dist/src/mcp/server.js.map +1 -0
  99. package/dist/src/sync/client.d.ts +25 -0
  100. package/dist/src/sync/client.d.ts.map +1 -0
  101. package/dist/src/sync/client.js +109 -0
  102. package/dist/src/sync/client.js.map +1 -0
  103. package/dist/src/sync/engine.d.ts +21 -0
  104. package/dist/src/sync/engine.d.ts.map +1 -0
  105. package/dist/src/sync/engine.js +304 -0
  106. package/dist/src/sync/engine.js.map +1 -0
  107. package/dist/src/sync/index.d.ts +6 -0
  108. package/dist/src/sync/index.d.ts.map +1 -0
  109. package/dist/src/sync/index.js +6 -0
  110. package/dist/src/sync/index.js.map +1 -0
  111. package/dist/src/sync/state.d.ts +33 -0
  112. package/dist/src/sync/state.d.ts.map +1 -0
  113. package/dist/src/sync/state.js +146 -0
  114. package/dist/src/sync/state.js.map +1 -0
  115. package/dist/src/sync/watcher.d.ts +14 -0
  116. package/dist/src/sync/watcher.d.ts.map +1 -0
  117. package/dist/src/sync/watcher.js +74 -0
  118. package/dist/src/sync/watcher.js.map +1 -0
  119. package/dist/src/sync/websocket.d.ts +22 -0
  120. package/dist/src/sync/websocket.d.ts.map +1 -0
  121. package/dist/src/sync/websocket.js +103 -0
  122. package/dist/src/sync/websocket.js.map +1 -0
  123. package/dist/src/types.d.ts +63 -0
  124. package/dist/src/types.d.ts.map +1 -0
  125. package/dist/src/types.js +2 -0
  126. package/dist/src/types.js.map +1 -0
  127. package/dist/src/utils/paths.d.ts +9 -0
  128. package/dist/src/utils/paths.d.ts.map +1 -0
  129. package/dist/src/utils/paths.js +24 -0
  130. package/dist/src/utils/paths.js.map +1 -0
  131. package/package.json +61 -0
@@ -0,0 +1,21 @@
1
+ import type { ContextMateConfig } from '../config.js';
2
+ import type { SyncResult } from '../types.js';
3
+ export declare class SyncEngine {
4
+ private watcher;
5
+ private stateDb;
6
+ private client;
7
+ private ws;
8
+ private readonly vaultKey;
9
+ private readonly config;
10
+ private pollTimer;
11
+ constructor(config: ContextMateConfig, vaultKey: Uint8Array);
12
+ start(): Promise<void>;
13
+ stop(): Promise<void>;
14
+ handleLocalChange(relativePath: string): Promise<void>;
15
+ handleRemoteUpdate(path: string, version: number): Promise<void>;
16
+ syncAll(): Promise<SyncResult>;
17
+ private handleLocalDelete;
18
+ private handleRemoteDelete;
19
+ private resolveConflictWithRemote;
20
+ }
21
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/sync/engine.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,EAAE,CAA8B;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,SAAS,CAA+C;gBAEpD,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,UAAU;IAMrD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2CtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBrB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4DtD,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDhE,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;YA6GtB,iBAAiB;YAMjB,kBAAkB;YAMlB,yBAAyB;CAmCxC"}
@@ -0,0 +1,304 @@
1
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
+ import { join, dirname } from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { FileWatcher } from './watcher.js';
5
+ import { SyncStateDB } from './state.js';
6
+ import { SyncClient, ConflictError } from './client.js';
7
+ import { SyncWebSocket } from './websocket.js';
8
+ import { encryptFile, decryptFile, hashContent, deriveKeyForPath } from '../crypto/index.js';
9
+ import { getSyncDbPath } from '../utils/paths.js';
10
+ export class SyncEngine {
11
+ watcher = null;
12
+ stateDb = null;
13
+ client;
14
+ ws = null;
15
+ vaultKey;
16
+ config;
17
+ pollTimer = null;
18
+ constructor(config, vaultKey) {
19
+ this.config = config;
20
+ this.vaultKey = vaultKey;
21
+ this.client = new SyncClient(config.server.url, config.server.apiKey ?? '');
22
+ }
23
+ async start() {
24
+ // Initialize state database
25
+ const dbPath = getSyncDbPath(this.config);
26
+ await mkdir(dirname(dbPath), { recursive: true });
27
+ this.stateDb = new SyncStateDB(dbPath);
28
+ // Start file watcher
29
+ this.watcher = new FileWatcher(this.config.vault.path, this.config.sync.debounceMs);
30
+ this.watcher.start();
31
+ // Connect WebSocket
32
+ const wsUrl = this.config.server.url.replace(/^http/, 'ws');
33
+ this.ws = new SyncWebSocket(wsUrl, this.config.server.apiKey ?? '');
34
+ this.ws.connect();
35
+ // Initial full sync
36
+ await this.syncAll();
37
+ // Wire up local file events
38
+ this.watcher.on('file-changed', (event) => {
39
+ void this.handleLocalChange(event.path);
40
+ });
41
+ this.watcher.on('file-added', (event) => {
42
+ void this.handleLocalChange(event.path);
43
+ });
44
+ this.watcher.on('file-removed', (event) => {
45
+ void this.handleLocalDelete(event.path);
46
+ });
47
+ // Wire up remote events
48
+ this.ws.on('file-updated', (event) => {
49
+ void this.handleRemoteUpdate(event.path, event.version);
50
+ });
51
+ this.ws.on('file-deleted', (event) => {
52
+ void this.handleRemoteDelete(event.path);
53
+ });
54
+ // Start periodic poll
55
+ this.pollTimer = setInterval(() => {
56
+ void this.syncAll();
57
+ }, this.config.sync.pollIntervalMs);
58
+ }
59
+ async stop() {
60
+ if (this.pollTimer) {
61
+ clearInterval(this.pollTimer);
62
+ this.pollTimer = null;
63
+ }
64
+ if (this.watcher) {
65
+ await this.watcher.stop();
66
+ this.watcher = null;
67
+ }
68
+ if (this.ws) {
69
+ this.ws.disconnect();
70
+ this.ws = null;
71
+ }
72
+ if (this.stateDb) {
73
+ this.stateDb.close();
74
+ this.stateDb = null;
75
+ }
76
+ }
77
+ async handleLocalChange(relativePath) {
78
+ if (!this.stateDb)
79
+ return;
80
+ try {
81
+ const absolutePath = join(this.config.vault.path, relativePath);
82
+ const content = await readFile(absolutePath);
83
+ const contentBytes = new Uint8Array(content);
84
+ // Hash the content
85
+ const contentHash = hashContent(contentBytes);
86
+ // Check state db - skip if hash unchanged
87
+ const existing = this.stateDb.getFile(relativePath);
88
+ if (existing && existing.contentHash === contentHash) {
89
+ return;
90
+ }
91
+ // Derive file-specific encryption key
92
+ const fileKey = deriveKeyForPath(this.vaultKey, relativePath);
93
+ // Encrypt file
94
+ const encrypted = encryptFile(contentBytes, fileKey);
95
+ const encryptedHash = hashContent(encrypted);
96
+ // Upload
97
+ const currentVersion = existing?.version ?? 0;
98
+ try {
99
+ const result = await this.client.uploadFile(relativePath, encrypted, encryptedHash, currentVersion);
100
+ // Update state db
101
+ this.stateDb.upsertFile({
102
+ id: existing?.id ?? randomUUID(),
103
+ path: relativePath,
104
+ contentHash,
105
+ encryptedHash,
106
+ version: result.version,
107
+ size: contentBytes.length,
108
+ syncState: 'synced',
109
+ lastModified: Date.now(),
110
+ });
111
+ this.stateDb.addSyncLog('upload', relativePath);
112
+ }
113
+ catch (err) {
114
+ if (err instanceof ConflictError) {
115
+ // Conflict: download remote version, save local as .conflict.md
116
+ await this.resolveConflictWithRemote(relativePath, contentBytes);
117
+ }
118
+ else {
119
+ throw err;
120
+ }
121
+ }
122
+ }
123
+ catch (err) {
124
+ const message = err instanceof Error ? err.message : String(err);
125
+ this.stateDb.addSyncLog('error', relativePath, message);
126
+ }
127
+ }
128
+ async handleRemoteUpdate(path, version) {
129
+ if (!this.stateDb)
130
+ return;
131
+ try {
132
+ // Check state db - skip if same version
133
+ const existing = this.stateDb.getFile(path);
134
+ if (existing && existing.version >= version) {
135
+ return;
136
+ }
137
+ // Download encrypted blob
138
+ const { data: encryptedData, version: remoteVersion, encryptedHash } = await this.client.downloadFile(path);
139
+ // Derive file key and decrypt
140
+ const fileKey = deriveKeyForPath(this.vaultKey, path);
141
+ const decrypted = decryptFile(encryptedData, fileKey);
142
+ const absolutePath = join(this.config.vault.path, path);
143
+ // Check for local modifications
144
+ if (existing && existing.syncState === 'modified') {
145
+ // Save local as conflict file
146
+ const conflictPath = absolutePath.replace(/\.md$/, '.conflict.md');
147
+ const localContent = await readFile(absolutePath);
148
+ await writeFile(conflictPath, localContent);
149
+ this.stateDb.addSyncLog('conflict', path, 'Local changes saved as .conflict.md');
150
+ }
151
+ // Write remote version to vault
152
+ await mkdir(dirname(absolutePath), { recursive: true });
153
+ await writeFile(absolutePath, decrypted);
154
+ // Update state db
155
+ const contentHash = hashContent(decrypted);
156
+ this.stateDb.upsertFile({
157
+ id: existing?.id ?? randomUUID(),
158
+ path,
159
+ contentHash,
160
+ encryptedHash,
161
+ version: remoteVersion,
162
+ size: decrypted.length,
163
+ syncState: 'synced',
164
+ lastModified: Date.now(),
165
+ });
166
+ this.stateDb.addSyncLog('download', path);
167
+ }
168
+ catch (err) {
169
+ const message = err instanceof Error ? err.message : String(err);
170
+ this.stateDb.addSyncLog('error', path, message);
171
+ }
172
+ }
173
+ async syncAll() {
174
+ const result = {
175
+ uploaded: [],
176
+ downloaded: [],
177
+ conflicts: [],
178
+ errors: [],
179
+ };
180
+ if (!this.stateDb)
181
+ return result;
182
+ try {
183
+ // Get remote file list
184
+ const remoteFiles = await this.client.listRemoteFiles();
185
+ const localFiles = this.stateDb.getAllFiles();
186
+ const localFileMap = new Map(localFiles.map((f) => [f.path, f]));
187
+ // Push local changes (modified/pending files)
188
+ const modifiedFiles = this.stateDb.getModifiedFiles();
189
+ for (const file of modifiedFiles) {
190
+ try {
191
+ const absolutePath = join(this.config.vault.path, file.path);
192
+ const content = await readFile(absolutePath);
193
+ const contentBytes = new Uint8Array(content);
194
+ const fileKey = deriveKeyForPath(this.vaultKey, file.path);
195
+ const encrypted = encryptFile(contentBytes, fileKey);
196
+ const encryptedHash = hashContent(encrypted);
197
+ const uploadResult = await this.client.uploadFile(file.path, encrypted, encryptedHash, file.version);
198
+ this.stateDb.markSynced(file.path, uploadResult.version, encryptedHash);
199
+ result.uploaded.push(file.path);
200
+ }
201
+ catch (err) {
202
+ if (err instanceof ConflictError) {
203
+ result.conflicts.push(file.path);
204
+ this.stateDb.markConflict(file.path);
205
+ }
206
+ else {
207
+ result.errors.push({
208
+ path: file.path,
209
+ error: err instanceof Error ? err.message : String(err),
210
+ });
211
+ }
212
+ }
213
+ }
214
+ // Pull remote changes
215
+ for (const remote of remoteFiles) {
216
+ const local = localFileMap.get(remote.path);
217
+ // Skip if we already have this version
218
+ if (local && local.version >= remote.version) {
219
+ continue;
220
+ }
221
+ try {
222
+ const { data: encryptedData, version: remoteVersion, encryptedHash } = await this.client.downloadFile(remote.path);
223
+ const fileKey = deriveKeyForPath(this.vaultKey, remote.path);
224
+ const decrypted = decryptFile(encryptedData, fileKey);
225
+ const absolutePath = join(this.config.vault.path, remote.path);
226
+ // Check for local conflict
227
+ if (local && local.syncState === 'modified') {
228
+ const conflictPath = absolutePath.replace(/\.md$/, '.conflict.md');
229
+ const localContent = await readFile(absolutePath);
230
+ await writeFile(conflictPath, localContent);
231
+ result.conflicts.push(remote.path);
232
+ this.stateDb.addSyncLog('conflict', remote.path, 'Local changes saved as .conflict.md');
233
+ }
234
+ await mkdir(dirname(absolutePath), { recursive: true });
235
+ await writeFile(absolutePath, decrypted);
236
+ const contentHash = hashContent(decrypted);
237
+ this.stateDb.upsertFile({
238
+ id: local?.id ?? randomUUID(),
239
+ path: remote.path,
240
+ contentHash,
241
+ encryptedHash,
242
+ version: remoteVersion,
243
+ size: decrypted.length,
244
+ syncState: 'synced',
245
+ lastModified: Date.now(),
246
+ });
247
+ result.downloaded.push(remote.path);
248
+ }
249
+ catch (err) {
250
+ result.errors.push({
251
+ path: remote.path,
252
+ error: err instanceof Error ? err.message : String(err),
253
+ });
254
+ }
255
+ }
256
+ }
257
+ catch (err) {
258
+ result.errors.push({
259
+ path: '*',
260
+ error: err instanceof Error ? err.message : String(err),
261
+ });
262
+ }
263
+ return result;
264
+ }
265
+ async handleLocalDelete(relativePath) {
266
+ if (!this.stateDb)
267
+ return;
268
+ this.stateDb.removeFile(relativePath);
269
+ this.stateDb.addSyncLog('delete', relativePath, 'Local file removed');
270
+ }
271
+ async handleRemoteDelete(path) {
272
+ if (!this.stateDb)
273
+ return;
274
+ this.stateDb.removeFile(path);
275
+ this.stateDb.addSyncLog('delete', path, 'Remote file deleted');
276
+ }
277
+ async resolveConflictWithRemote(relativePath, localContent) {
278
+ if (!this.stateDb)
279
+ return;
280
+ const absolutePath = join(this.config.vault.path, relativePath);
281
+ // Save local content as conflict file
282
+ const conflictPath = absolutePath.replace(/\.md$/, '.conflict.md');
283
+ await writeFile(conflictPath, localContent);
284
+ // Download and write remote version
285
+ const { data: encryptedData, version: remoteVersion, encryptedHash } = await this.client.downloadFile(relativePath);
286
+ const fileKey = deriveKeyForPath(this.vaultKey, relativePath);
287
+ const decrypted = decryptFile(encryptedData, fileKey);
288
+ await writeFile(absolutePath, decrypted);
289
+ const contentHash = hashContent(decrypted);
290
+ const existing = this.stateDb.getFile(relativePath);
291
+ this.stateDb.upsertFile({
292
+ id: existing?.id ?? randomUUID(),
293
+ path: relativePath,
294
+ contentHash,
295
+ encryptedHash,
296
+ version: remoteVersion,
297
+ size: decrypted.length,
298
+ syncState: 'conflict',
299
+ lastModified: Date.now(),
300
+ });
301
+ this.stateDb.addSyncLog('conflict', relativePath, 'Local changes saved as .conflict.md, remote version written');
302
+ }
303
+ }
304
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/sync/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { SyncEngine } from './engine.js';
2
+ export { SyncStateDB } from './state.js';
3
+ export { FileWatcher } from './watcher.js';
4
+ export { SyncClient, ConflictError } from './client.js';
5
+ export { SyncWebSocket } from './websocket.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sync/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { SyncEngine } from './engine.js';
2
+ export { SyncStateDB } from './state.js';
3
+ export { FileWatcher } from './watcher.js';
4
+ export { SyncClient, ConflictError } from './client.js';
5
+ export { SyncWebSocket } from './websocket.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sync/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { SyncFile, SyncState } from '../types.js';
2
+ export interface SyncLogEntry {
3
+ id: number;
4
+ action: string;
5
+ path: string;
6
+ timestamp: number;
7
+ details: string | null;
8
+ }
9
+ export interface SyncLogOptions {
10
+ action?: string;
11
+ path?: string;
12
+ since?: number;
13
+ limit?: number;
14
+ offset?: number;
15
+ }
16
+ export declare class SyncStateDB {
17
+ private db;
18
+ constructor(dbPath: string);
19
+ private createSchema;
20
+ getFile(path: string): SyncFile | null;
21
+ upsertFile(file: SyncFile): void;
22
+ getAllFiles(): SyncFile[];
23
+ getFilesByState(state: SyncState): SyncFile[];
24
+ getModifiedFiles(): SyncFile[];
25
+ getConflicts(): SyncFile[];
26
+ markSynced(path: string, version: number, encryptedHash: string): void;
27
+ markConflict(path: string): void;
28
+ removeFile(path: string): void;
29
+ addSyncLog(action: string, path: string, details?: string): void;
30
+ getSyncLog(options?: SyncLogOptions): SyncLogEntry[];
31
+ close(): void;
32
+ }
33
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/sync/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAoB;gBAElB,MAAM,EAAE,MAAM;IAM1B,OAAO,CAAC,YAAY;IAgCpB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAiBtC,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAuBhC,WAAW,IAAI,QAAQ,EAAE;IAgBzB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,EAAE;IAgB7C,gBAAgB,IAAI,QAAQ,EAAE;IAgB9B,YAAY,IAAI,QAAQ,EAAE;IAI1B,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAMtE,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMhC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI9B,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAMhE,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,YAAY,EAAE;IA0BxD,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,146 @@
1
+ import Database from 'better-sqlite3';
2
+ export class SyncStateDB {
3
+ db;
4
+ constructor(dbPath) {
5
+ this.db = new Database(dbPath);
6
+ this.db.pragma('journal_mode = WAL');
7
+ this.createSchema();
8
+ }
9
+ createSchema() {
10
+ this.db.exec(`
11
+ CREATE TABLE IF NOT EXISTS files (
12
+ id TEXT PRIMARY KEY,
13
+ path TEXT UNIQUE NOT NULL,
14
+ content_hash TEXT NOT NULL,
15
+ encrypted_hash TEXT NOT NULL,
16
+ version INTEGER NOT NULL DEFAULT 0,
17
+ size INTEGER NOT NULL DEFAULT 0,
18
+ sync_state TEXT NOT NULL DEFAULT 'pending',
19
+ last_modified INTEGER NOT NULL,
20
+ last_synced INTEGER
21
+ );
22
+
23
+ CREATE TABLE IF NOT EXISTS devices (
24
+ id TEXT PRIMARY KEY,
25
+ name TEXT NOT NULL,
26
+ public_key TEXT NOT NULL,
27
+ last_seen INTEGER NOT NULL,
28
+ current INTEGER NOT NULL DEFAULT 0
29
+ );
30
+
31
+ CREATE TABLE IF NOT EXISTS sync_log (
32
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
33
+ action TEXT NOT NULL,
34
+ path TEXT NOT NULL,
35
+ timestamp INTEGER NOT NULL,
36
+ details TEXT
37
+ );
38
+ `);
39
+ }
40
+ getFile(path) {
41
+ const row = this.db.prepare('SELECT id, path, content_hash, encrypted_hash, version, size, sync_state, last_modified FROM files WHERE path = ?').get(path);
42
+ if (!row)
43
+ return null;
44
+ return {
45
+ id: row.id,
46
+ path: row.path,
47
+ contentHash: row.content_hash,
48
+ encryptedHash: row.encrypted_hash,
49
+ version: row.version,
50
+ size: row.size,
51
+ syncState: row.sync_state,
52
+ lastModified: row.last_modified,
53
+ };
54
+ }
55
+ upsertFile(file) {
56
+ this.db.prepare(`
57
+ INSERT INTO files (id, path, content_hash, encrypted_hash, version, size, sync_state, last_modified)
58
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
59
+ ON CONFLICT(path) DO UPDATE SET
60
+ content_hash = excluded.content_hash,
61
+ encrypted_hash = excluded.encrypted_hash,
62
+ version = excluded.version,
63
+ size = excluded.size,
64
+ sync_state = excluded.sync_state,
65
+ last_modified = excluded.last_modified
66
+ `).run(file.id, file.path, file.contentHash, file.encryptedHash, file.version, file.size, file.syncState, file.lastModified);
67
+ }
68
+ getAllFiles() {
69
+ const rows = this.db.prepare('SELECT id, path, content_hash, encrypted_hash, version, size, sync_state, last_modified FROM files').all();
70
+ return rows.map((row) => ({
71
+ id: row.id,
72
+ path: row.path,
73
+ contentHash: row.content_hash,
74
+ encryptedHash: row.encrypted_hash,
75
+ version: row.version,
76
+ size: row.size,
77
+ syncState: row.sync_state,
78
+ lastModified: row.last_modified,
79
+ }));
80
+ }
81
+ getFilesByState(state) {
82
+ const rows = this.db.prepare('SELECT id, path, content_hash, encrypted_hash, version, size, sync_state, last_modified FROM files WHERE sync_state = ?').all(state);
83
+ return rows.map((row) => ({
84
+ id: row.id,
85
+ path: row.path,
86
+ contentHash: row.content_hash,
87
+ encryptedHash: row.encrypted_hash,
88
+ version: row.version,
89
+ size: row.size,
90
+ syncState: row.sync_state,
91
+ lastModified: row.last_modified,
92
+ }));
93
+ }
94
+ getModifiedFiles() {
95
+ const rows = this.db.prepare("SELECT id, path, content_hash, encrypted_hash, version, size, sync_state, last_modified FROM files WHERE sync_state IN ('modified', 'pending')").all();
96
+ return rows.map((row) => ({
97
+ id: row.id,
98
+ path: row.path,
99
+ contentHash: row.content_hash,
100
+ encryptedHash: row.encrypted_hash,
101
+ version: row.version,
102
+ size: row.size,
103
+ syncState: row.sync_state,
104
+ lastModified: row.last_modified,
105
+ }));
106
+ }
107
+ getConflicts() {
108
+ return this.getFilesByState('conflict');
109
+ }
110
+ markSynced(path, version, encryptedHash) {
111
+ this.db.prepare("UPDATE files SET sync_state = 'synced', version = ?, encrypted_hash = ?, last_synced = ? WHERE path = ?").run(version, encryptedHash, Date.now(), path);
112
+ }
113
+ markConflict(path) {
114
+ this.db.prepare("UPDATE files SET sync_state = 'conflict' WHERE path = ?").run(path);
115
+ }
116
+ removeFile(path) {
117
+ this.db.prepare('DELETE FROM files WHERE path = ?').run(path);
118
+ }
119
+ addSyncLog(action, path, details) {
120
+ this.db.prepare('INSERT INTO sync_log (action, path, timestamp, details) VALUES (?, ?, ?, ?)').run(action, path, Date.now(), details ?? null);
121
+ }
122
+ getSyncLog(options = {}) {
123
+ const conditions = [];
124
+ const params = [];
125
+ if (options.action) {
126
+ conditions.push('action = ?');
127
+ params.push(options.action);
128
+ }
129
+ if (options.path) {
130
+ conditions.push('path LIKE ?');
131
+ params.push(options.path + '%');
132
+ }
133
+ if (options.since) {
134
+ conditions.push('timestamp >= ?');
135
+ params.push(options.since);
136
+ }
137
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
138
+ const limit = options.limit ?? 50;
139
+ const offset = options.offset ?? 0;
140
+ return this.db.prepare(`SELECT id, action, path, timestamp, details FROM sync_log ${where} ORDER BY timestamp DESC, id DESC LIMIT ? OFFSET ?`).all(...params, limit, offset);
141
+ }
142
+ close() {
143
+ this.db.close();
144
+ }
145
+ }
146
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/sync/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { EventEmitter } from 'node:events';
2
+ export declare class FileWatcher extends EventEmitter {
3
+ private watcher;
4
+ private readonly watchPath;
5
+ private readonly debounceMs;
6
+ private pendingChanges;
7
+ private debounceTimer;
8
+ constructor(watchPath: string, debounceMs?: number);
9
+ start(): void;
10
+ stop(): Promise<void>;
11
+ private queueChange;
12
+ private flushChanges;
13
+ }
14
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../../src/sync/watcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,cAAc,CAA2D;IACjF,OAAO,CAAC,aAAa,CAA8C;gBAEvD,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,MAAY;IAMvD,KAAK,IAAI,IAAI;IAwBP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,YAAY;CAmBrB"}
@@ -0,0 +1,74 @@
1
+ import chokidar from 'chokidar';
2
+ import { EventEmitter } from 'node:events';
3
+ import { relative } from 'node:path';
4
+ export class FileWatcher extends EventEmitter {
5
+ watcher = null;
6
+ watchPath;
7
+ debounceMs;
8
+ pendingChanges = new Map();
9
+ debounceTimer = null;
10
+ constructor(watchPath, debounceMs = 500) {
11
+ super();
12
+ this.watchPath = watchPath;
13
+ this.debounceMs = debounceMs;
14
+ }
15
+ start() {
16
+ this.watcher = chokidar.watch(this.watchPath, {
17
+ ignoreInitial: true,
18
+ persistent: true,
19
+ ignored: [
20
+ /(^|\/)\../,
21
+ /\.conflict\.md$/,
22
+ /node_modules/,
23
+ ],
24
+ });
25
+ this.watcher.on('add', (filePath) => {
26
+ this.queueChange(filePath, 'added');
27
+ });
28
+ this.watcher.on('change', (filePath) => {
29
+ this.queueChange(filePath, 'changed');
30
+ });
31
+ this.watcher.on('unlink', (filePath) => {
32
+ this.queueChange(filePath, 'removed');
33
+ });
34
+ }
35
+ async stop() {
36
+ if (this.debounceTimer) {
37
+ clearTimeout(this.debounceTimer);
38
+ this.debounceTimer = null;
39
+ }
40
+ if (this.watcher) {
41
+ await this.watcher.close();
42
+ this.watcher = null;
43
+ }
44
+ }
45
+ queueChange(absolutePath, type) {
46
+ const relPath = relative(this.watchPath, absolutePath);
47
+ this.pendingChanges.set(relPath, type);
48
+ if (this.debounceTimer) {
49
+ clearTimeout(this.debounceTimer);
50
+ }
51
+ this.debounceTimer = setTimeout(() => {
52
+ this.flushChanges();
53
+ }, this.debounceMs);
54
+ }
55
+ flushChanges() {
56
+ const changes = new Map(this.pendingChanges);
57
+ this.pendingChanges.clear();
58
+ for (const [path, type] of changes) {
59
+ const event = { path };
60
+ switch (type) {
61
+ case 'added':
62
+ this.emit('file-added', event);
63
+ break;
64
+ case 'changed':
65
+ this.emit('file-changed', event);
66
+ break;
67
+ case 'removed':
68
+ this.emit('file-removed', event);
69
+ break;
70
+ }
71
+ }
72
+ }
73
+ }
74
+ //# sourceMappingURL=watcher.js.map