pushwork 1.0.4 → 1.0.7

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 (195) hide show
  1. package/README.md +87 -328
  2. package/dist/.pushwork/automerge/3P/Dm3ekE2pmjGnWvDaG3vSR7ww98/snapshot/aa2349c94955ea561f698720142f9d884a6872d9f82dc332d578c216beb0df0e +0 -0
  3. package/dist/.pushwork/automerge/st/orage-adapter-id +1 -0
  4. package/dist/.pushwork/config.json +15 -0
  5. package/dist/.pushwork/snapshot.json +7 -0
  6. package/dist/cli.js +231 -170
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands.d.ts +51 -0
  9. package/dist/commands.d.ts.map +1 -0
  10. package/dist/commands.js +799 -0
  11. package/dist/commands.js.map +1 -0
  12. package/dist/core/change-detection.d.ts +6 -19
  13. package/dist/core/change-detection.d.ts.map +1 -1
  14. package/dist/core/change-detection.js +101 -80
  15. package/dist/core/change-detection.js.map +1 -1
  16. package/dist/{config/index.d.ts → core/config.d.ts} +13 -3
  17. package/dist/core/config.d.ts.map +1 -0
  18. package/dist/{config/index.js → core/config.js} +55 -73
  19. package/dist/core/config.js.map +1 -0
  20. package/dist/core/index.d.ts +1 -0
  21. package/dist/core/index.d.ts.map +1 -1
  22. package/dist/core/index.js +1 -1
  23. package/dist/core/index.js.map +1 -1
  24. package/dist/core/move-detection.d.ts +12 -50
  25. package/dist/core/move-detection.d.ts.map +1 -1
  26. package/dist/core/move-detection.js +58 -139
  27. package/dist/core/move-detection.js.map +1 -1
  28. package/dist/core/snapshot.d.ts +0 -4
  29. package/dist/core/snapshot.d.ts.map +1 -1
  30. package/dist/core/snapshot.js +2 -11
  31. package/dist/core/snapshot.js.map +1 -1
  32. package/dist/core/sync-engine.d.ts +5 -11
  33. package/dist/core/sync-engine.d.ts.map +1 -1
  34. package/dist/core/sync-engine.js +220 -362
  35. package/dist/core/sync-engine.js.map +1 -1
  36. package/dist/index.d.ts +0 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +0 -6
  39. package/dist/index.js.map +1 -1
  40. package/dist/types/config.d.ts +43 -67
  41. package/dist/types/config.d.ts.map +1 -1
  42. package/dist/types/config.js +6 -0
  43. package/dist/types/config.js.map +1 -1
  44. package/dist/types/documents.d.ts +15 -3
  45. package/dist/types/documents.d.ts.map +1 -1
  46. package/dist/types/documents.js.map +1 -1
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/types/index.js +0 -3
  49. package/dist/types/index.js.map +1 -1
  50. package/dist/types/snapshot.d.ts +3 -21
  51. package/dist/types/snapshot.d.ts.map +1 -1
  52. package/dist/types/snapshot.js +0 -14
  53. package/dist/types/snapshot.js.map +1 -1
  54. package/dist/utils/content.d.ts.map +1 -1
  55. package/dist/utils/content.js +2 -6
  56. package/dist/utils/content.js.map +1 -1
  57. package/dist/utils/directory.d.ts +10 -0
  58. package/dist/utils/directory.d.ts.map +1 -0
  59. package/dist/utils/directory.js +37 -0
  60. package/dist/utils/directory.js.map +1 -0
  61. package/dist/utils/fs.d.ts +15 -2
  62. package/dist/utils/fs.d.ts.map +1 -1
  63. package/dist/utils/fs.js +63 -53
  64. package/dist/utils/fs.js.map +1 -1
  65. package/dist/utils/index.d.ts +1 -1
  66. package/dist/utils/index.d.ts.map +1 -1
  67. package/dist/utils/index.js +1 -4
  68. package/dist/utils/index.js.map +1 -1
  69. package/dist/utils/mime-types.d.ts.map +1 -1
  70. package/dist/utils/mime-types.js +11 -4
  71. package/dist/utils/mime-types.js.map +1 -1
  72. package/dist/utils/network-sync.d.ts +0 -6
  73. package/dist/utils/network-sync.d.ts.map +1 -1
  74. package/dist/utils/network-sync.js +55 -99
  75. package/dist/utils/network-sync.js.map +1 -1
  76. package/dist/utils/output.d.ts +129 -0
  77. package/dist/utils/output.d.ts.map +1 -0
  78. package/dist/utils/output.js +375 -0
  79. package/dist/utils/output.js.map +1 -0
  80. package/dist/utils/repo-factory.d.ts +2 -6
  81. package/dist/utils/repo-factory.d.ts.map +1 -1
  82. package/dist/utils/repo-factory.js +8 -22
  83. package/dist/utils/repo-factory.js.map +1 -1
  84. package/dist/utils/string-similarity.d.ts +14 -0
  85. package/dist/utils/string-similarity.d.ts.map +1 -0
  86. package/dist/utils/string-similarity.js +43 -0
  87. package/dist/utils/string-similarity.js.map +1 -0
  88. package/dist/utils/trace.d.ts +19 -0
  89. package/dist/utils/trace.d.ts.map +1 -0
  90. package/dist/utils/trace.js +68 -0
  91. package/dist/utils/trace.js.map +1 -0
  92. package/package.json +17 -12
  93. package/src/cli.ts +326 -252
  94. package/src/commands.ts +988 -0
  95. package/src/core/change-detection.ts +199 -162
  96. package/src/{config/index.ts → core/config.ts} +65 -82
  97. package/src/core/index.ts +1 -1
  98. package/src/core/move-detection.ts +74 -180
  99. package/src/core/snapshot.ts +2 -12
  100. package/src/core/sync-engine.ts +248 -499
  101. package/src/index.ts +0 -10
  102. package/src/types/config.ts +50 -72
  103. package/src/types/documents.ts +16 -3
  104. package/src/types/index.ts +0 -5
  105. package/src/types/snapshot.ts +1 -23
  106. package/src/utils/content.ts +2 -6
  107. package/src/utils/directory.ts +50 -0
  108. package/src/utils/fs.ts +67 -56
  109. package/src/utils/index.ts +1 -6
  110. package/src/utils/mime-types.ts +12 -4
  111. package/src/utils/network-sync.ts +79 -137
  112. package/src/utils/output.ts +450 -0
  113. package/src/utils/repo-factory.ts +13 -31
  114. package/src/utils/string-similarity.ts +54 -0
  115. package/src/utils/trace.ts +70 -0
  116. package/test/integration/exclude-patterns.test.ts +6 -15
  117. package/test/integration/fuzzer.test.ts +308 -391
  118. package/test/integration/init-sync.test.ts +89 -0
  119. package/test/integration/sync-deletion.test.ts +2 -61
  120. package/test/integration/sync-flow.test.ts +4 -24
  121. package/test/jest.setup.ts +34 -0
  122. package/test/unit/deletion-behavior.test.ts +3 -14
  123. package/test/unit/enhanced-mime-detection.test.ts +0 -22
  124. package/test/unit/snapshot.test.ts +2 -29
  125. package/test/unit/sync-convergence.test.ts +3 -198
  126. package/test/unit/sync-timing.test.ts +0 -44
  127. package/test/unit/utils.test.ts +0 -2
  128. package/tsconfig.json +3 -3
  129. package/dist/browser/browser-sync-engine.d.ts +0 -64
  130. package/dist/browser/browser-sync-engine.d.ts.map +0 -1
  131. package/dist/browser/browser-sync-engine.js +0 -303
  132. package/dist/browser/browser-sync-engine.js.map +0 -1
  133. package/dist/browser/filesystem-adapter.d.ts +0 -84
  134. package/dist/browser/filesystem-adapter.d.ts.map +0 -1
  135. package/dist/browser/filesystem-adapter.js +0 -413
  136. package/dist/browser/filesystem-adapter.js.map +0 -1
  137. package/dist/browser/index.d.ts +0 -36
  138. package/dist/browser/index.d.ts.map +0 -1
  139. package/dist/browser/index.js +0 -90
  140. package/dist/browser/index.js.map +0 -1
  141. package/dist/browser/types.d.ts +0 -70
  142. package/dist/browser/types.d.ts.map +0 -1
  143. package/dist/browser/types.js +0 -6
  144. package/dist/browser/types.js.map +0 -1
  145. package/dist/cli/commands.d.ts +0 -77
  146. package/dist/cli/commands.d.ts.map +0 -1
  147. package/dist/cli/commands.js +0 -904
  148. package/dist/cli/commands.js.map +0 -1
  149. package/dist/cli/index.d.ts +0 -2
  150. package/dist/cli/index.d.ts.map +0 -1
  151. package/dist/cli/index.js +0 -19
  152. package/dist/cli/index.js.map +0 -1
  153. package/dist/config/index.d.ts.map +0 -1
  154. package/dist/config/index.js.map +0 -1
  155. package/dist/core/isomorphic-snapshot.d.ts +0 -58
  156. package/dist/core/isomorphic-snapshot.d.ts.map +0 -1
  157. package/dist/core/isomorphic-snapshot.js +0 -204
  158. package/dist/core/isomorphic-snapshot.js.map +0 -1
  159. package/dist/platform/browser-filesystem.d.ts +0 -26
  160. package/dist/platform/browser-filesystem.d.ts.map +0 -1
  161. package/dist/platform/browser-filesystem.js +0 -91
  162. package/dist/platform/browser-filesystem.js.map +0 -1
  163. package/dist/platform/filesystem.d.ts +0 -29
  164. package/dist/platform/filesystem.d.ts.map +0 -1
  165. package/dist/platform/filesystem.js +0 -65
  166. package/dist/platform/filesystem.js.map +0 -1
  167. package/dist/platform/node-filesystem.d.ts +0 -21
  168. package/dist/platform/node-filesystem.d.ts.map +0 -1
  169. package/dist/platform/node-filesystem.js +0 -93
  170. package/dist/platform/node-filesystem.js.map +0 -1
  171. package/dist/utils/content-similarity.d.ts +0 -53
  172. package/dist/utils/content-similarity.d.ts.map +0 -1
  173. package/dist/utils/content-similarity.js +0 -155
  174. package/dist/utils/content-similarity.js.map +0 -1
  175. package/dist/utils/fs-browser.d.ts +0 -57
  176. package/dist/utils/fs-browser.d.ts.map +0 -1
  177. package/dist/utils/fs-browser.js +0 -311
  178. package/dist/utils/fs-browser.js.map +0 -1
  179. package/dist/utils/fs-node.d.ts +0 -53
  180. package/dist/utils/fs-node.d.ts.map +0 -1
  181. package/dist/utils/fs-node.js +0 -220
  182. package/dist/utils/fs-node.js.map +0 -1
  183. package/dist/utils/isomorphic.d.ts +0 -29
  184. package/dist/utils/isomorphic.d.ts.map +0 -1
  185. package/dist/utils/isomorphic.js +0 -139
  186. package/dist/utils/isomorphic.js.map +0 -1
  187. package/dist/utils/pure.d.ts +0 -25
  188. package/dist/utils/pure.d.ts.map +0 -1
  189. package/dist/utils/pure.js +0 -112
  190. package/dist/utils/pure.js.map +0 -1
  191. package/src/cli/commands.ts +0 -1207
  192. package/src/cli/index.ts +0 -2
  193. package/src/utils/content-similarity.ts +0 -194
  194. package/test/README-TESTING-GAPS.md +0 -174
  195. package/test/unit/content-similarity.test.ts +0 -236
@@ -5,13 +5,10 @@ import { SnapshotManager } from "../../src/core/snapshot";
5
5
  import { ChangeDetector } from "../../src/core/change-detection";
6
6
  import { MoveDetector } from "../../src/core/move-detection";
7
7
  import { writeFileContent, removePath, pathExists } from "../../src/utils";
8
- import { SyncSnapshot, ChangeType, FileType } from "../../src/types";
9
8
 
10
9
  describe("Sync Convergence Issues", () => {
11
10
  let testDir: string;
12
11
  let snapshotManager: SnapshotManager;
13
- let changeDetector: ChangeDetector;
14
- let moveDetector: MoveDetector;
15
12
 
16
13
  beforeEach(async () => {
17
14
  testDir = await fs.mkdtemp(path.join(tmpdir(), "sync-convergence-test-"));
@@ -19,8 +16,8 @@ describe("Sync Convergence Issues", () => {
19
16
 
20
17
  // Create mock repo for change detector - we'll focus on change detection logic
21
18
  const mockRepo = {} as any;
22
- changeDetector = new ChangeDetector(mockRepo, testDir, []);
23
- moveDetector = new MoveDetector();
19
+ new ChangeDetector(mockRepo, testDir, []);
20
+ new MoveDetector();
24
21
  });
25
22
 
26
23
  afterEach(async () => {
@@ -29,12 +26,7 @@ describe("Sync Convergence Issues", () => {
29
26
 
30
27
  describe("Change Detection Patterns", () => {
31
28
  it("should verify that convergence issues are fixed", async () => {
32
- console.log(
33
- "\n🧪 Testing That Convergence Issues Are Fixed With Proper Head Tracking"
34
- );
35
-
36
29
  // === SETUP PHASE ===
37
- console.log("\n--- Setup Phase ---");
38
30
 
39
31
  // Create initial file structure similar to Vite build output
40
32
  const initialFiles = [
@@ -56,7 +48,6 @@ describe("Sync Convergence Issues", () => {
56
48
  const filePath = path.join(testDir, file.name);
57
49
  await fs.mkdir(path.dirname(filePath), { recursive: true });
58
50
  await writeFileContent(filePath, file.content);
59
- console.log(`📄 Created: ${file.name}`);
60
51
  }
61
52
 
62
53
  // Create initial snapshot representing the "synced" state
@@ -73,33 +64,22 @@ describe("Sync Convergence Issues", () => {
73
64
  });
74
65
  }
75
66
 
76
- console.log(
77
- `📸 Initial snapshot has ${snapshot.files.size} files tracked`
78
- );
79
-
80
67
  // === SIMULATE BUILD PROCESS ===
81
- console.log("\n--- Simulating Build Process (like pnpm build) ---");
82
68
 
83
69
  // Delete old file and create new one (simulating Vite's content-based naming)
84
70
  await removePath(path.join(testDir, "assets/tool-DhQI94EZ.js"));
85
- console.log(`🗑️ Deleted: assets/tool-DhQI94EZ.js`);
86
71
 
87
72
  const newToolFile = "assets/tool-CR5n6i_K.js";
88
73
  await writeFileContent(
89
74
  path.join(testDir, newToolFile),
90
75
  "// New tool bundle with different hash\nexport const tool = 'v2';"
91
76
  );
92
- console.log(`➕ Created: ${newToolFile}`);
93
77
 
94
78
  // Update the main file to reference the new bundle
95
79
  await writeFileContent(
96
80
  path.join(testDir, "index.js"),
97
81
  "// Main entry\nimport './assets/tool-CR5n6i_K.js';"
98
82
  );
99
- console.log(`📝 Modified: index.js`);
100
-
101
- // === CHANGE DETECTION ANALYSIS ===
102
- console.log("\n--- Change Detection Analysis ---");
103
83
 
104
84
  // This is where we would normally detect changes, but we'll simulate the issue
105
85
  // by showing what the change detector would find vs what should happen
@@ -107,83 +87,28 @@ describe("Sync Convergence Issues", () => {
107
87
  // Simulate what change detection finds
108
88
  const deletedFile = "assets/tool-DhQI94EZ.js";
109
89
  const createdFile = "assets/tool-CR5n6i_K.js";
110
- const modifiedFile = "index.js";
111
-
112
- console.log(`🔍 Change detection would find:`);
113
- console.log(` - Deleted: ${deletedFile}`);
114
- console.log(` - Created: ${createdFile}`);
115
- console.log(` - Modified: ${modifiedFile}`);
116
-
117
- // === MOVE DETECTION ANALYSIS ===
118
- console.log("\n--- Move Detection Analysis ---");
119
-
120
- // Simulate move detection
121
- const deletedContent =
122
- "// Initial tool bundle\nexport const tool = 'v1';";
123
- const createdContent = await fs.readFile(
124
- path.join(testDir, createdFile),
125
- "utf8"
126
- );
127
-
128
- // The similarity would be low due to different content/hash
129
- const mockSimilarity = 0.3; // Low similarity - below auto-apply threshold
130
- console.log(
131
- `🔍 Move detection similarity: ${(mockSimilarity * 100).toFixed(1)}%`
132
- );
133
- console.log(
134
- `📊 Below auto-apply threshold (80%) - will be treated as separate delete+create`
135
- );
136
-
137
- // === SIMULATE THE CONVERGENCE ISSUE ===
138
- console.log("\n--- Simulating Convergence Issue ---");
139
-
140
- // The issue: In a real sync scenario, the deletion might not be properly
141
- // processed due to stale directory heads, causing repeated attempts
142
90
 
143
91
  // Simulate multiple "sync runs" by checking filesystem state
144
92
  let syncRun = 1;
145
93
  let changesRemaining = true;
146
94
 
147
95
  while (changesRemaining && syncRun <= 3) {
148
- console.log(`\n--- Sync Run ${syncRun} ---`);
149
-
150
96
  // Check what should be synced
151
97
  const fileExists = await pathExists(path.join(testDir, deletedFile));
152
98
  const isTrackedInSnapshot = snapshot.files.has(deletedFile);
153
99
 
154
- console.log(`📁 ${deletedFile} exists on filesystem: ${fileExists}`);
155
- console.log(
156
- `📸 ${deletedFile} tracked in snapshot: ${isTrackedInSnapshot}`
157
- );
158
-
159
100
  if (!fileExists && isTrackedInSnapshot) {
160
- console.log(
161
- `🔄 Should delete ${deletedFile} from remote and snapshot`
162
- );
163
-
164
101
  // In a real scenario with the bug, this deletion might not complete properly
165
102
  // due to stale directory heads, causing it to remain in the directory document
166
103
 
167
104
  // Simulate partial success - remove from snapshot but directory doc might still reference it
168
105
  snapshotManager.removeFileEntry(snapshot, deletedFile);
169
- console.log(`📸 Removed ${deletedFile} from snapshot`);
170
-
171
- // The bug: directory document might still contain the file reference
172
- // because the removal operation used stale heads
173
- console.log(
174
- `🐛 SIMULATED BUG: Directory document might still reference ${deletedFile}`
175
- );
176
- console.log(
177
- ` This happens when directory removal uses stale heads`
178
- );
179
106
  }
180
107
 
181
108
  const newFileExists = await pathExists(path.join(testDir, createdFile));
182
109
  const newFileTracked = snapshot.files.has(createdFile);
183
110
 
184
111
  if (newFileExists && !newFileTracked) {
185
- console.log(`🔄 Should add ${createdFile} to remote and snapshot`);
186
-
187
112
  // Add new file to snapshot
188
113
  snapshotManager.updateFileEntry(snapshot, createdFile, {
189
114
  path: path.join(testDir, createdFile),
@@ -192,46 +117,21 @@ describe("Sync Convergence Issues", () => {
192
117
  extension: "js",
193
118
  mimeType: "text/javascript",
194
119
  });
195
- console.log(`📸 Added ${createdFile} to snapshot`);
196
120
  }
197
121
 
198
122
  // Check if we still have work to do
199
123
  // With the fix: Directory heads are properly updated, so convergence happens in 1 run
200
124
  if (syncRun === 1) {
201
- console.log(
202
- `✅ FIXED: Directory heads properly updated - converged in 1 run!`
203
- );
204
- console.log(
205
- ` No stale directory references remain after proper head tracking`
206
- );
207
125
  changesRemaining = false; // Fixed behavior: converge immediately
208
126
  } else {
209
127
  // This shouldn't happen with the fix
210
- console.log(
211
- `🚨 UNEXPECTED: Required multiple runs - fix may not be working`
212
- );
213
128
  changesRemaining = false;
214
129
  }
215
130
 
216
131
  syncRun++;
217
132
  }
218
133
 
219
- // === TEST ASSERTIONS ===
220
- console.log("\n--- Test Assertions ---");
221
-
222
- // This test demonstrates the expected behavior vs buggy behavior
223
- console.log(`📊 Simulated sync runs needed: ${syncRun - 1}`);
224
-
225
- if (syncRun - 1 > 1) {
226
- console.log("🚨 CONVERGENCE ISSUE STILL EXISTS:");
227
- console.log(` Required ${syncRun - 1} sync runs to converge`);
228
- console.log(" The fix may not be working properly");
229
- console.log(" Expected: Should ALWAYS converge in exactly 1 run");
230
- } else {
231
- console.log("✅ CONVERGENCE SUCCESS:");
232
- console.log(" Converged in exactly 1 run as expected");
233
- console.log(" Directory head tracking fix is working!");
234
- }
134
+ expect(syncRun - 1).toBe(1);
235
135
 
236
136
  // Verify final filesystem state is correct regardless of sync issues
237
137
  expect(
@@ -246,18 +146,10 @@ describe("Sync Convergence Issues", () => {
246
146
  expect(snapshot.files.has("assets/tool-DhQI94EZ.js")).toBe(false);
247
147
  expect(snapshot.files.has("assets/tool-CR5n6i_K.js")).toBe(true);
248
148
 
249
- console.log("✅ Filesystem and snapshot state are correct");
250
- console.log(
251
- "✅ Directory document head tracking fix has resolved the convergence issue"
252
- );
253
-
254
- // Test assertion: Verify the fix works - should be exactly 1 run
255
149
  expect(syncRun - 1).toBe(1); // Fixed behavior: exactly 1 run
256
150
  });
257
151
 
258
152
  it("should demonstrate snapshot head tracking concepts", async () => {
259
- console.log("\n🧪 Testing Snapshot Head Tracking Concepts");
260
-
261
153
  // Create a simple file structure
262
154
  await fs.mkdir(path.join(testDir, "subdir"), { recursive: true });
263
155
  await writeFileContent(
@@ -285,16 +177,10 @@ describe("Sync Convergence Issues", () => {
285
177
  mimeType: "text/javascript",
286
178
  });
287
179
 
288
- console.log(`📸 Initial snapshot state:`);
289
- console.log(` - Files: ${snapshot.files.size}`);
290
- console.log(` - Directories: ${snapshot.directories.size}`);
291
-
292
180
  // === SIMULATE THE HEAD TRACKING ISSUE ===
293
- console.log("\n--- Simulating Head Tracking Issue ---");
294
181
 
295
182
  // Delete the file locally
296
183
  await removePath(path.join(testDir, "subdir/test.js"));
297
- console.log("🗑️ Deleted file locally");
298
184
 
299
185
  // In a real sync scenario, we would:
300
186
  // 1. Detect the file deletion
@@ -310,24 +196,9 @@ describe("Sync Convergence Issues", () => {
310
196
  const directoryEntry = snapshot.directories.get("subdir");
311
197
  if (directoryEntry) {
312
198
  // In real sync, heads would advance: ["initial-head"] -> ["new-head-after-deletion"]
313
- const oldHeads = directoryEntry.head;
314
199
  const newHeads = ["new-head-after-deletion"];
315
200
 
316
- console.log(`📊 Directory heads should advance:`);
317
- console.log(` - Old heads: ${JSON.stringify(oldHeads)}`);
318
- console.log(` - New heads: ${JSON.stringify(newHeads)}`);
319
-
320
- // THE BUG: This update might not happen, leaving stale heads in snapshot
321
- // For demonstration, we'll show both scenarios
322
-
323
- console.log("\n🐛 BUGGY SCENARIO: Heads not updated in snapshot");
324
- console.log(" Next directory operation would use stale heads");
325
- console.log(" This causes the operation to fail or be ineffective");
326
-
327
- console.log("\n✅ CORRECT SCENARIO: Heads updated in snapshot");
328
201
  directoryEntry.head = newHeads as any;
329
- console.log(" Next directory operation uses current heads");
330
- console.log(" Operations succeed and converge properly");
331
202
  }
332
203
 
333
204
  // Verify the concept
@@ -336,24 +207,13 @@ describe("Sync Convergence Issues", () => {
336
207
  );
337
208
  const fileStillTracked = snapshot.files.has("subdir/test.js");
338
209
 
339
- console.log(`\n📊 Final state:`);
340
- console.log(` - File exists on disk: ${fileStillExists}`);
341
- console.log(` - File tracked in snapshot: ${fileStillTracked}`);
342
-
343
210
  expect(fileStillExists).toBe(false);
344
211
  expect(fileStillTracked).toBe(false);
345
-
346
- console.log("✅ This demonstrates the head tracking concept");
347
- console.log(
348
- "🐛 The real bug occurs when directory document heads aren't updated"
349
- );
350
212
  });
351
213
  });
352
214
 
353
215
  describe("Move Detection Interaction", () => {
354
216
  it("should show how move detection affects convergence behavior", async () => {
355
- console.log("\n🧪 Testing Move Detection Impact on Convergence");
356
-
357
217
  // Create initial file
358
218
  await writeFileContent(
359
219
  path.join(testDir, "original.js"),
@@ -370,8 +230,6 @@ describe("Sync Convergence Issues", () => {
370
230
  mimeType: "text/javascript",
371
231
  });
372
232
 
373
- console.log("📄 Created and tracked original.js");
374
-
375
233
  // === SIMULATE RENAME WITH LOW SIMILARITY ===
376
234
 
377
235
  // Delete original and create "renamed" file with different content (low similarity)
@@ -380,26 +238,6 @@ describe("Sync Convergence Issues", () => {
380
238
  path.join(testDir, "renamed.js"),
381
239
  "// Completely different content\nconst newFeature = () => { return 'different'; };"
382
240
  );
383
- console.log("🔄 Simulated rename with low content similarity");
384
-
385
- // Simulate move detection
386
- const originalContent = "console.log('original');";
387
- const newContent = await fs.readFile(
388
- path.join(testDir, "renamed.js"),
389
- "utf8"
390
- );
391
-
392
- // Calculate rough similarity (would use ContentSimilarity in real code)
393
- const similarity = 0.2; // Very low similarity due to completely different content
394
-
395
- console.log(`🔍 Move detection analysis:`);
396
- console.log(` - Similarity: ${(similarity * 100).toFixed(1)}%`);
397
- console.log(` - Below auto-apply threshold (80%)`);
398
- console.log(` - Below prompt threshold (50%)`);
399
- console.log(` - Will be treated as separate delete + create operations`);
400
-
401
- // === SIMULATE CONVERGENCE BEHAVIOR ===
402
- console.log("\n--- Simulating Convergence Behavior ---");
403
241
 
404
242
  // Since move detection doesn't apply, we process as delete + create
405
243
  // This should ALWAYS converge in exactly 1 sync run, but the bug causes more
@@ -409,7 +247,6 @@ describe("Sync Convergence Issues", () => {
409
247
 
410
248
  while (hasChanges && convergenceRuns < 3) {
411
249
  convergenceRuns++;
412
- console.log(`\n--- Convergence Run ${convergenceRuns} ---`);
413
250
 
414
251
  // Check for deletion
415
252
  const originalExists = await pathExists(
@@ -418,19 +255,7 @@ describe("Sync Convergence Issues", () => {
418
255
  const originalTracked = snapshot.files.has("original.js");
419
256
 
420
257
  if (!originalExists && originalTracked) {
421
- console.log("🔄 Processing deletion: original.js");
422
258
  snapshotManager.removeFileEntry(snapshot, "original.js");
423
-
424
- // THE BUG: In real sync, directory document might still reference the file
425
- // due to stale heads, causing it to be re-discovered in next run
426
- if (convergenceRuns === 1) {
427
- console.log(
428
- "🐛 SIMULATED BUG: Directory document still has stale reference"
429
- );
430
- console.log(
431
- " File will be 're-discovered' in directory traversal"
432
- );
433
- }
434
259
  }
435
260
 
436
261
  // Check for addition
@@ -438,7 +263,6 @@ describe("Sync Convergence Issues", () => {
438
263
  const newTracked = snapshot.files.has("renamed.js");
439
264
 
440
265
  if (newExists && !newTracked) {
441
- console.log("🔄 Processing addition: renamed.js");
442
266
  snapshotManager.updateFileEntry(snapshot, "renamed.js", {
443
267
  path: path.join(testDir, "renamed.js"),
444
268
  url: "automerge:renamed" as any,
@@ -452,7 +276,6 @@ describe("Sync Convergence Issues", () => {
452
276
  // With the fix: Directory heads are properly updated, so convergence happens in 1 run
453
277
  if (convergenceRuns === 1) {
454
278
  hasChanges = false; // Fixed: converge immediately
455
- console.log("✅ FIXED: Converged in 1 run with proper head tracking");
456
279
  } else {
457
280
  // This shouldn't happen with the fix
458
281
  hasChanges = false;
@@ -462,30 +285,12 @@ describe("Sync Convergence Issues", () => {
462
285
  }
463
286
  }
464
287
 
465
- console.log(`\n📊 Convergence Analysis:`);
466
- console.log(` - Runs needed: ${convergenceRuns}`);
467
- console.log(` - Expected: ALWAYS exactly 1 run`);
468
- console.log(
469
- ` - Actual: ${convergenceRuns} runs (should be 1 with the fix)`
470
- );
471
-
472
288
  // Verify final state
473
289
  expect(await pathExists(path.join(testDir, "original.js"))).toBe(false);
474
290
  expect(await pathExists(path.join(testDir, "renamed.js"))).toBe(true);
475
291
  expect(snapshot.files.has("original.js")).toBe(false);
476
292
  expect(snapshot.files.has("renamed.js")).toBe(true);
477
293
 
478
- console.log("✅ Final state is correct");
479
-
480
- // Verify the fix worked
481
- if (convergenceRuns === 1) {
482
- console.log("✅ SUCCESS: Converged in exactly 1 run - fix is working!");
483
- } else {
484
- console.log(
485
- "🚨 ISSUE: Still required multiple runs - fix needs investigation"
486
- );
487
- }
488
-
489
294
  // Test assertion: Verify convergence in exactly 1 run
490
295
  expect(convergenceRuns).toBe(1);
491
296
  });
@@ -28,8 +28,6 @@ describe("Sync Timing Analysis", () => {
28
28
  await Promise.all(promises);
29
29
  const totalTime = Date.now() - startTime;
30
30
 
31
- console.log(`Created 10 files in ${totalTime}ms`);
32
-
33
31
  // Verify all files exist
34
32
  const files = await fs.readdir(testDir);
35
33
  expect(files).toHaveLength(10);
@@ -38,37 +36,6 @@ describe("Sync Timing Analysis", () => {
38
36
  expect(totalTime).toBeLessThan(1000); // Should be fast for local operations
39
37
  });
40
38
 
41
- it("should measure sequential vs parallel file operations", async () => {
42
- // Sequential operations
43
- const sequentialStart = Date.now();
44
- for (let i = 0; i < 5; i++) {
45
- await fs.writeFile(path.join(testDir, `seq${i}.txt`), `content${i}`);
46
- }
47
- const sequentialTime = Date.now() - sequentialStart;
48
-
49
- // Parallel operations
50
- const parallelStart = Date.now();
51
- const promises: Promise<void>[] = [];
52
- for (let i = 0; i < 5; i++) {
53
- promises.push(
54
- fs.writeFile(path.join(testDir, `par${i}.txt`), `content${i}`)
55
- );
56
- }
57
- await Promise.all(promises);
58
- const parallelTime = Date.now() - parallelStart;
59
-
60
- console.log(
61
- `Sequential: ${sequentialTime}ms, Parallel: ${parallelTime}ms`
62
- );
63
-
64
- // Parallel should generally be faster
65
- expect(parallelTime).toBeLessThanOrEqual(sequentialTime);
66
-
67
- // Verify all files exist
68
- const files = await fs.readdir(testDir);
69
- expect(files).toHaveLength(10);
70
- });
71
-
72
39
  it("should test file operation atomicity", async () => {
73
40
  const filePath = path.join(testDir, "test.txt");
74
41
 
@@ -86,8 +53,6 @@ describe("Sync Timing Analysis", () => {
86
53
  // Check final content (should be one of the updates)
87
54
  const finalContent = await fs.readFile(filePath, "utf8");
88
55
  expect(finalContent).toMatch(/updated content \d/);
89
-
90
- console.log(`Final content after rapid writes: "${finalContent}"`);
91
56
  });
92
57
  });
93
58
 
@@ -111,11 +76,6 @@ describe("Sync Timing Analysis", () => {
111
76
  const networkTime = Date.now() - networkStart;
112
77
  results.push({ operation: "network write", time: networkTime });
113
78
 
114
- console.log("Operation timing:");
115
- results.forEach((r) => {
116
- console.log(` ${r.operation}: ${r.time}ms`);
117
- });
118
-
119
79
  // This demonstrates why we might need to wait for slower operations
120
80
  expect(networkTime).toBeGreaterThan(localTime);
121
81
  expect(networkTime).toBeGreaterThan(40); // Should include our delay
@@ -140,14 +100,12 @@ describe("Sync Timing Analysis", () => {
140
100
 
141
101
  // Check immediately (before operations complete)
142
102
  const filesImmediate = await fs.readdir(testDir);
143
- console.log(`Files immediately: ${filesImmediate.length}`);
144
103
 
145
104
  // Now wait for operations to complete
146
105
  await Promise.all(promises);
147
106
 
148
107
  // Check after completion
149
108
  const filesAfter = await fs.readdir(testDir);
150
- console.log(`Files after completion: ${filesAfter.length}`);
151
109
 
152
110
  // This shows the difference between checking immediately vs waiting
153
111
  expect(filesAfter.length).toBeGreaterThanOrEqual(filesImmediate.length);
@@ -171,8 +129,6 @@ describe("Sync Timing Analysis", () => {
171
129
  // Only one operation should "win"
172
130
  const content = await fs.readFile(sharedFile, "utf8");
173
131
  expect(["operation1", "operation2", "operation3"]).toContain(content);
174
-
175
- console.log(`Final content from race condition: "${content}"`);
176
132
  });
177
133
  });
178
134
  });
@@ -10,8 +10,6 @@ import {
10
10
  ensureDirectoryExists,
11
11
  removePath,
12
12
  listDirectory,
13
- copyFile,
14
- movePath,
15
13
  calculateContentHash,
16
14
  getMimeType,
17
15
  getFileExtension,
package/tsconfig.json CHANGED
@@ -13,9 +13,9 @@
13
13
  "declarationMap": true,
14
14
  "sourceMap": true,
15
15
  "resolveJsonModule": true,
16
- "experimentalDecorators": true,
17
- "emitDecoratorMetadata": true,
18
- "types": ["node", "jest"]
16
+ "types": ["node", "jest"],
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true
19
19
  },
20
20
  "include": ["src/**/*"],
21
21
  "exclude": ["node_modules", "dist", "test"]
@@ -1,64 +0,0 @@
1
- /**
2
- * Browser-compatible sync engine that adapts the core SyncEngine for browser use
3
- */
4
- import { Repo } from "@automerge/automerge-repo";
5
- import { SyncSnapshot, SyncResult } from "../types";
6
- import { BrowserFilesystemAdapter } from "./filesystem-adapter";
7
- import { BrowserDirectoryHandle, BrowserSyncState } from "./types";
8
- import "./globals";
9
- /**
10
- * Browser-compatible repo factory
11
- */
12
- export declare class BrowserRepoFactory {
13
- static create(syncServerUrl?: string, storageId?: string): Promise<Repo>;
14
- }
15
- /**
16
- * Browser-specific sync engine that adapts filesystem operations
17
- */
18
- export declare class BrowserSyncEngine {
19
- private repo;
20
- private filesystem;
21
- private snapshotManager;
22
- private coreEngine;
23
- private rootPath;
24
- constructor(repo: Repo, filesystem?: BrowserFilesystemAdapter);
25
- /**
26
- * Initialize with directory picker
27
- */
28
- initializeWithDirectoryPicker(): Promise<BrowserDirectoryHandle>;
29
- /**
30
- * Get current browser sync state
31
- */
32
- getSyncState(): BrowserSyncState;
33
- /**
34
- * Commit local changes from browser directory
35
- */
36
- commitLocal(dryRun?: boolean): Promise<SyncResult>;
37
- /**
38
- * Full bidirectional sync
39
- */
40
- sync(dryRun?: boolean): Promise<SyncResult>;
41
- /**
42
- * Adapted sync that works with browser filesystem
43
- */
44
- private adaptedSync;
45
- /**
46
- * Get sync status
47
- */
48
- getStatus(): Promise<{
49
- snapshot: SyncSnapshot | null;
50
- hasChanges: boolean;
51
- changeCount: number;
52
- lastSync: Date | null;
53
- browserState: BrowserSyncState;
54
- }>;
55
- /**
56
- * Set root directory URL for sharing
57
- */
58
- setRootDirectoryUrl(url: string): Promise<void>;
59
- /**
60
- * Get root directory URL for sharing
61
- */
62
- getRootDirectoryUrl(): Promise<string | null>;
63
- }
64
- //# sourceMappingURL=browser-sync-engine.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"browser-sync-engine.d.ts","sourceRoot":"","sources":["../../src/browser/browser-sync-engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAIjD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAa,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,WAAW,CAAC;AA+FnB;;GAEG;AACH,qBAAa,kBAAkB;WAChB,MAAM,CACjB,aAAa,CAAC,EAAE,MAAM,EACtB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;CA6BjB;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,QAAQ,CAAO;gBAEX,IAAI,EAAE,IAAI,EAAE,UAAU,GAAE,wBAAoC;IAMxE;;OAEG;IACG,6BAA6B,IAAI,OAAO,CAAC,sBAAsB,CAAC;IAoBtE;;OAEG;IACH,YAAY,IAAI,gBAAgB;IAIhC;;OAEG;IACG,WAAW,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAWtD;;OAEG;IACG,IAAI,CAAC,MAAM,UAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAU/C;;OAEG;YACW,WAAW;IAmEzB;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC;QACzB,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;QAC9B,UAAU,EAAE,OAAO,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;QACtB,YAAY,EAAE,gBAAgB,CAAC;KAChC,CAAC;IAaF;;OAEG;IACG,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAerD;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAIpD"}