pushwork 1.1.2 → 1.1.4
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.
- package/.prettierrc +9 -0
- package/dist/cli/commands.d.ts +71 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +794 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +19 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/index.d.ts +71 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +314 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/change-detection.d.ts +4 -3
- package/dist/core/change-detection.d.ts.map +1 -1
- package/dist/core/change-detection.js +78 -25
- package/dist/core/change-detection.js.map +1 -1
- package/dist/core/sync-engine.d.ts.map +1 -1
- package/dist/core/sync-engine.js +22 -5
- package/dist/core/sync-engine.js.map +1 -1
- package/dist/types/documents.d.ts +2 -0
- package/dist/types/documents.d.ts.map +1 -1
- package/dist/utils/content-similarity.d.ts +53 -0
- package/dist/utils/content-similarity.d.ts.map +1 -0
- package/dist/utils/content-similarity.js +155 -0
- package/dist/utils/content-similarity.js.map +1 -0
- package/dist/utils/network-sync.js +5 -5
- package/dist/utils/network-sync.js.map +1 -1
- package/package.json +1 -1
- package/src/core/change-detection.ts +108 -43
- package/src/core/sync-engine.ts +22 -5
- package/src/types/documents.ts +4 -2
- package/src/utils/network-sync.ts +5 -5
- package/test/integration/in-memory-sync.test.ts +201 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content similarity calculation for move detection
|
|
3
|
+
*/
|
|
4
|
+
export declare class ContentSimilarity {
|
|
5
|
+
private static readonly CHUNK_SIZE;
|
|
6
|
+
private static readonly AUTO_THRESHOLD;
|
|
7
|
+
private static readonly PROMPT_THRESHOLD;
|
|
8
|
+
/**
|
|
9
|
+
* Calculate similarity between two content pieces
|
|
10
|
+
*/
|
|
11
|
+
static calculateSimilarity(content1: string | Uint8Array, content2: string | Uint8Array): Promise<number>;
|
|
12
|
+
/**
|
|
13
|
+
* Check if two content pieces are identical
|
|
14
|
+
*/
|
|
15
|
+
private static areIdentical;
|
|
16
|
+
/**
|
|
17
|
+
* Calculate similarity for small files using full content
|
|
18
|
+
*/
|
|
19
|
+
private static calculateFullSimilarity;
|
|
20
|
+
/**
|
|
21
|
+
* Calculate similarity for large files using sampling
|
|
22
|
+
*/
|
|
23
|
+
private static calculateSampledSimilarity;
|
|
24
|
+
/**
|
|
25
|
+
* Get representative samples from content
|
|
26
|
+
*/
|
|
27
|
+
private static getSamples;
|
|
28
|
+
/**
|
|
29
|
+
* Calculate Levenshtein similarity (0-1 scale)
|
|
30
|
+
*/
|
|
31
|
+
private static levenshteinSimilarity;
|
|
32
|
+
/**
|
|
33
|
+
* Calculate Levenshtein distance
|
|
34
|
+
*/
|
|
35
|
+
private static levenshteinDistance;
|
|
36
|
+
/**
|
|
37
|
+
* Convert buffer to string for comparison
|
|
38
|
+
*/
|
|
39
|
+
private static bufferToString;
|
|
40
|
+
/**
|
|
41
|
+
* Determine confidence level based on similarity score
|
|
42
|
+
*/
|
|
43
|
+
static getConfidenceLevel(similarity: number): "auto" | "prompt" | "low";
|
|
44
|
+
/**
|
|
45
|
+
* Should auto-apply move based on similarity
|
|
46
|
+
*/
|
|
47
|
+
static shouldAutoApply(similarity: number): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Should prompt user for move confirmation
|
|
50
|
+
*/
|
|
51
|
+
static shouldPromptUser(similarity: number): boolean;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=content-similarity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-similarity.d.ts","sourceRoot":"","sources":["../../src/utils/content-similarity.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAQ;IAC1C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAO;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAO;IAE/C;;OAEG;WACU,mBAAmB,CAC9B,QAAQ,EAAE,MAAM,GAAG,UAAU,EAC7B,QAAQ,EAAE,MAAM,GAAG,UAAU,GAC5B,OAAO,CAAC,MAAM,CAAC;IA0BlB;;OAEG;mBACkB,YAAY;IASjC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAYtC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,0BAA0B;IAkBzC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;IAwBzB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAUpC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAsBlC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAO7B;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK;IAUxE;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAInD;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;CAKrD"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContentSimilarity = void 0;
|
|
4
|
+
const fs_1 = require("./fs");
|
|
5
|
+
/**
|
|
6
|
+
* Content similarity calculation for move detection
|
|
7
|
+
*/
|
|
8
|
+
class ContentSimilarity {
|
|
9
|
+
/**
|
|
10
|
+
* Calculate similarity between two content pieces
|
|
11
|
+
*/
|
|
12
|
+
static async calculateSimilarity(content1, content2) {
|
|
13
|
+
// Quick early exit for identical content
|
|
14
|
+
if (await this.areIdentical(content1, content2)) {
|
|
15
|
+
return 1.0;
|
|
16
|
+
}
|
|
17
|
+
// Size-based quick rejection
|
|
18
|
+
const size1 = typeof content1 === "string" ? content1.length : content1.length;
|
|
19
|
+
const size2 = typeof content2 === "string" ? content2.length : content2.length;
|
|
20
|
+
const sizeDiff = Math.abs(size1 - size2) / Math.max(size1, size2);
|
|
21
|
+
if (sizeDiff > 0.5) {
|
|
22
|
+
return 0.0; // Too different in size
|
|
23
|
+
}
|
|
24
|
+
// For small files, use full content comparison
|
|
25
|
+
if (size1 < this.CHUNK_SIZE * 4 && size2 < this.CHUNK_SIZE * 4) {
|
|
26
|
+
return this.calculateFullSimilarity(content1, content2);
|
|
27
|
+
}
|
|
28
|
+
// For large files, use sampling
|
|
29
|
+
return this.calculateSampledSimilarity(content1, content2);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if two content pieces are identical
|
|
33
|
+
*/
|
|
34
|
+
static async areIdentical(content1, content2) {
|
|
35
|
+
const hash1 = await (0, fs_1.calculateContentHash)(content1);
|
|
36
|
+
const hash2 = await (0, fs_1.calculateContentHash)(content2);
|
|
37
|
+
return hash1 === hash2;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Calculate similarity for small files using full content
|
|
41
|
+
*/
|
|
42
|
+
static calculateFullSimilarity(content1, content2) {
|
|
43
|
+
const str1 = typeof content1 === "string" ? content1 : this.bufferToString(content1);
|
|
44
|
+
const str2 = typeof content2 === "string" ? content2 : this.bufferToString(content2);
|
|
45
|
+
return this.levenshteinSimilarity(str1, str2);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Calculate similarity for large files using sampling
|
|
49
|
+
*/
|
|
50
|
+
static calculateSampledSimilarity(content1, content2) {
|
|
51
|
+
const samples1 = this.getSamples(content1);
|
|
52
|
+
const samples2 = this.getSamples(content2);
|
|
53
|
+
let totalSimilarity = 0;
|
|
54
|
+
let comparisons = 0;
|
|
55
|
+
for (let i = 0; i < Math.min(samples1.length, samples2.length); i++) {
|
|
56
|
+
totalSimilarity += this.levenshteinSimilarity(samples1[i], samples2[i]);
|
|
57
|
+
comparisons++;
|
|
58
|
+
}
|
|
59
|
+
return comparisons > 0 ? totalSimilarity / comparisons : 0;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get representative samples from content
|
|
63
|
+
*/
|
|
64
|
+
static getSamples(content) {
|
|
65
|
+
const str = typeof content === "string" ? content : this.bufferToString(content);
|
|
66
|
+
const length = str.length;
|
|
67
|
+
const samples = [];
|
|
68
|
+
if (length <= this.CHUNK_SIZE) {
|
|
69
|
+
samples.push(str);
|
|
70
|
+
return samples;
|
|
71
|
+
}
|
|
72
|
+
// Beginning
|
|
73
|
+
samples.push(str.slice(0, this.CHUNK_SIZE));
|
|
74
|
+
// Middle
|
|
75
|
+
const midStart = Math.floor(length / 2) - Math.floor(this.CHUNK_SIZE / 2);
|
|
76
|
+
samples.push(str.slice(midStart, midStart + this.CHUNK_SIZE));
|
|
77
|
+
// End
|
|
78
|
+
samples.push(str.slice(-this.CHUNK_SIZE));
|
|
79
|
+
return samples;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Calculate Levenshtein similarity (0-1 scale)
|
|
83
|
+
*/
|
|
84
|
+
static levenshteinSimilarity(str1, str2) {
|
|
85
|
+
if (str1 === str2)
|
|
86
|
+
return 1.0;
|
|
87
|
+
if (str1.length === 0 || str2.length === 0)
|
|
88
|
+
return 0.0;
|
|
89
|
+
const distance = this.levenshteinDistance(str1, str2);
|
|
90
|
+
const maxLength = Math.max(str1.length, str2.length);
|
|
91
|
+
return 1 - distance / maxLength;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Calculate Levenshtein distance
|
|
95
|
+
*/
|
|
96
|
+
static levenshteinDistance(str1, str2) {
|
|
97
|
+
const matrix = Array(str2.length + 1)
|
|
98
|
+
.fill(null)
|
|
99
|
+
.map(() => Array(str1.length + 1).fill(null));
|
|
100
|
+
for (let i = 0; i <= str1.length; i++)
|
|
101
|
+
matrix[0][i] = i;
|
|
102
|
+
for (let j = 0; j <= str2.length; j++)
|
|
103
|
+
matrix[j][0] = j;
|
|
104
|
+
for (let j = 1; j <= str2.length; j++) {
|
|
105
|
+
for (let i = 1; i <= str1.length; i++) {
|
|
106
|
+
const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
107
|
+
matrix[j][i] = Math.min(matrix[j][i - 1] + 1, // deletion
|
|
108
|
+
matrix[j - 1][i] + 1, // insertion
|
|
109
|
+
matrix[j - 1][i - 1] + indicator // substitution
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return matrix[str2.length][str1.length];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Convert buffer to string for comparison
|
|
117
|
+
*/
|
|
118
|
+
static bufferToString(buffer) {
|
|
119
|
+
// For binary content, use hex representation for comparison
|
|
120
|
+
return Array.from(buffer)
|
|
121
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
122
|
+
.join("");
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Determine confidence level based on similarity score
|
|
126
|
+
*/
|
|
127
|
+
static getConfidenceLevel(similarity) {
|
|
128
|
+
if (similarity >= this.AUTO_THRESHOLD) {
|
|
129
|
+
return "auto";
|
|
130
|
+
}
|
|
131
|
+
else if (similarity >= this.PROMPT_THRESHOLD) {
|
|
132
|
+
return "prompt";
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return "low";
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Should auto-apply move based on similarity
|
|
140
|
+
*/
|
|
141
|
+
static shouldAutoApply(similarity) {
|
|
142
|
+
return similarity >= this.AUTO_THRESHOLD;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Should prompt user for move confirmation
|
|
146
|
+
*/
|
|
147
|
+
static shouldPromptUser(similarity) {
|
|
148
|
+
return (similarity >= this.PROMPT_THRESHOLD && similarity < this.AUTO_THRESHOLD);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.ContentSimilarity = ContentSimilarity;
|
|
152
|
+
ContentSimilarity.CHUNK_SIZE = 1024; // 1KB chunks for sampling
|
|
153
|
+
ContentSimilarity.AUTO_THRESHOLD = 0.8;
|
|
154
|
+
ContentSimilarity.PROMPT_THRESHOLD = 0.5;
|
|
155
|
+
//# sourceMappingURL=content-similarity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-similarity.js","sourceRoot":"","sources":["../../src/utils/content-similarity.ts"],"names":[],"mappings":"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"}
|
|
@@ -96,7 +96,7 @@ async function waitForBidirectionalSync(repo, rootDirectoryUrl, syncServerStorag
|
|
|
96
96
|
const changedDocs = [];
|
|
97
97
|
for (const [url, heads] of currentHeads) {
|
|
98
98
|
if (lastSeenHeads.get(url) !== heads) {
|
|
99
|
-
changedDocs.push(url
|
|
99
|
+
changedDocs.push(url);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
const newDocs = currentHeads.size - lastSeenHeads.size;
|
|
@@ -212,12 +212,12 @@ function waitForHandleSync(handle, syncServerStorageId, timeoutMs, startTime) {
|
|
|
212
212
|
handle.off("remote-heads", onRemoteHeads);
|
|
213
213
|
};
|
|
214
214
|
const onConverged = () => {
|
|
215
|
-
debug(`waitForSync: ${handle.url
|
|
215
|
+
debug(`waitForSync: ${handle.url}... converged in ${Date.now() - startTime}ms`);
|
|
216
216
|
cleanup();
|
|
217
217
|
resolve(handle);
|
|
218
218
|
};
|
|
219
219
|
const timeout = setTimeout(() => {
|
|
220
|
-
debug(`waitForSync: ${handle.url
|
|
220
|
+
debug(`waitForSync: ${handle.url}... timed out after ${timeoutMs}ms`);
|
|
221
221
|
cleanup();
|
|
222
222
|
reject(handle);
|
|
223
223
|
}, timeoutMs);
|
|
@@ -272,10 +272,10 @@ async function waitForSync(handlesToWaitOn, syncServerStorageId, timeoutMs = 600
|
|
|
272
272
|
const remoteHeads = syncInfo?.lastHeads;
|
|
273
273
|
if (A.equals(heads, remoteHeads)) {
|
|
274
274
|
alreadySynced++;
|
|
275
|
-
debug(`waitForSync: ${handle.url
|
|
275
|
+
debug(`waitForSync: ${handle.url}... already synced`);
|
|
276
276
|
}
|
|
277
277
|
else {
|
|
278
|
-
debug(`waitForSync: ${handle.url
|
|
278
|
+
debug(`waitForSync: ${handle.url}... needs sync (remoteHeads=${remoteHeads ? 'present' : 'missing'})`);
|
|
279
279
|
needsSync.push(handle);
|
|
280
280
|
}
|
|
281
281
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-sync.js","sourceRoot":"","sources":["../../src/utils/network-sync.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"network-sync.js","sourceRoot":"","sources":["../../src/utils/network-sync.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AutomergeUrl,
|
|
3
|
+
DocHandle,
|
|
4
|
+
Repo,
|
|
5
|
+
UrlHeads,
|
|
6
|
+
} from "@automerge/automerge-repo"
|
|
2
7
|
import * as A from "@automerge/automerge"
|
|
3
8
|
import {
|
|
4
9
|
ChangeType,
|
|
@@ -20,6 +25,11 @@ import {
|
|
|
20
25
|
import {isContentEqual, contentHash} from "../utils/content"
|
|
21
26
|
import {out} from "../utils/output"
|
|
22
27
|
|
|
28
|
+
const isDebug = !!process.env.DEBUG
|
|
29
|
+
function debug(...args: any[]) {
|
|
30
|
+
if (isDebug) console.error("[pushwork:change-detection]", ...args)
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
/**
|
|
24
34
|
* Change detection engine
|
|
25
35
|
*/
|
|
@@ -45,7 +55,7 @@ export class ChangeDetector {
|
|
|
45
55
|
/**
|
|
46
56
|
* Detect all changes between local filesystem and snapshot
|
|
47
57
|
*/
|
|
48
|
-
async detectChanges(snapshot: SyncSnapshot): Promise<DetectedChange[]> {
|
|
58
|
+
async detectChanges(snapshot: SyncSnapshot, excludePaths?: Set<string>): Promise<DetectedChange[]> {
|
|
49
59
|
const changes: DetectedChange[] = []
|
|
50
60
|
|
|
51
61
|
// Get current filesystem state
|
|
@@ -60,7 +70,7 @@ export class ChangeDetector {
|
|
|
60
70
|
changes.push(...remoteChanges)
|
|
61
71
|
|
|
62
72
|
// Check for new remote documents not in snapshot (critical for clone scenarios)
|
|
63
|
-
const newRemoteDocuments = await this.detectNewRemoteDocuments(snapshot)
|
|
73
|
+
const newRemoteDocuments = await this.detectNewRemoteDocuments(snapshot, excludePaths)
|
|
64
74
|
changes.push(...newRemoteDocuments)
|
|
65
75
|
|
|
66
76
|
return changes
|
|
@@ -107,11 +117,12 @@ export class ChangeDetector {
|
|
|
107
117
|
if (localChanged || remoteChanged) {
|
|
108
118
|
changes.push({
|
|
109
119
|
path: relativePath,
|
|
110
|
-
changeType:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
120
|
+
changeType:
|
|
121
|
+
localChanged && remoteChanged
|
|
122
|
+
? ChangeType.BOTH_CHANGED
|
|
123
|
+
: localChanged
|
|
124
|
+
? ChangeType.LOCAL_ONLY
|
|
125
|
+
: ChangeType.REMOTE_ONLY,
|
|
115
126
|
fileType: fileInfo.type,
|
|
116
127
|
localContent: fileInfo.content,
|
|
117
128
|
remoteContent: null,
|
|
@@ -235,13 +246,13 @@ export class ChangeDetector {
|
|
|
235
246
|
await Promise.all(
|
|
236
247
|
Array.from(snapshot.files.entries()).map(
|
|
237
248
|
async ([relativePath, snapshotEntry]) => {
|
|
238
|
-
//
|
|
239
|
-
const
|
|
249
|
+
// Find the file's current entry in the remote directory hierarchy
|
|
250
|
+
const remoteEntry = await this.findInRemoteDirectory(
|
|
240
251
|
snapshot.rootDirectoryUrl,
|
|
241
252
|
relativePath
|
|
242
253
|
)
|
|
243
254
|
|
|
244
|
-
if (!
|
|
255
|
+
if (!remoteEntry) {
|
|
245
256
|
// File was removed from remote directory listing
|
|
246
257
|
const localContent = await this.getLocalContent(relativePath)
|
|
247
258
|
|
|
@@ -261,41 +272,48 @@ export class ChangeDetector {
|
|
|
261
272
|
return
|
|
262
273
|
}
|
|
263
274
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
275
|
+
// Check if the document was replaced entirely (new URL).
|
|
276
|
+
// This happens when a peer replaces an artifact file, fixes a
|
|
277
|
+
// legacy immutable string, or recreates a failed document.
|
|
278
|
+
// The old snapshot URL is now orphaned — read from the new one.
|
|
279
|
+
const urlReplaced = getPlainUrl(remoteEntry.url) !== getPlainUrl(snapshotEntry.url)
|
|
280
|
+
const remoteUrl = urlReplaced ? remoteEntry.url : snapshotEntry.url
|
|
267
281
|
|
|
268
|
-
|
|
282
|
+
const currentRemoteHead = await this.getCurrentRemoteHead(remoteUrl)
|
|
283
|
+
|
|
284
|
+
if (urlReplaced || !A.equals(currentRemoteHead, snapshotEntry.head)) {
|
|
269
285
|
if (this.isArtifactPath(relativePath)) {
|
|
270
286
|
// Artifact: skip content reads, just report head change
|
|
271
287
|
const localContent = await this.getLocalContent(relativePath)
|
|
272
288
|
changes.push({
|
|
273
289
|
path: relativePath,
|
|
274
|
-
changeType:
|
|
275
|
-
|
|
276
|
-
|
|
290
|
+
changeType:
|
|
291
|
+
localContent !== null
|
|
292
|
+
? ChangeType.BOTH_CHANGED
|
|
293
|
+
: ChangeType.REMOTE_ONLY,
|
|
277
294
|
fileType: FileType.TEXT,
|
|
278
295
|
localContent,
|
|
279
296
|
remoteContent: null,
|
|
280
297
|
localHead: snapshotEntry.head,
|
|
281
298
|
remoteHead: currentRemoteHead,
|
|
299
|
+
...(urlReplaced ? {remoteUrl: remoteEntry.url} : {}),
|
|
282
300
|
})
|
|
283
301
|
return
|
|
284
302
|
}
|
|
285
303
|
|
|
286
304
|
// Remote document has changed
|
|
287
|
-
const currentRemoteContent = await this.getCurrentRemoteContent(
|
|
288
|
-
snapshotEntry.url
|
|
289
|
-
)
|
|
305
|
+
const currentRemoteContent = await this.getCurrentRemoteContent(remoteUrl)
|
|
290
306
|
const localContent = await this.getLocalContent(relativePath)
|
|
291
|
-
const lastKnownContent =
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
307
|
+
const lastKnownContent = urlReplaced
|
|
308
|
+
? null // Can't diff against old doc when URL changed
|
|
309
|
+
: await this.getContentAtHead(
|
|
310
|
+
snapshotEntry.url,
|
|
311
|
+
snapshotEntry.head
|
|
312
|
+
)
|
|
295
313
|
|
|
296
|
-
const localChanged = localContent
|
|
314
|
+
const localChanged = localContent && lastKnownContent
|
|
297
315
|
? !isContentEqual(localContent, lastKnownContent)
|
|
298
|
-
:
|
|
316
|
+
: localContent !== null
|
|
299
317
|
|
|
300
318
|
const changeType = localChanged
|
|
301
319
|
? ChangeType.BOTH_CHANGED
|
|
@@ -309,6 +327,7 @@ export class ChangeDetector {
|
|
|
309
327
|
remoteContent: currentRemoteContent,
|
|
310
328
|
localHead: snapshotEntry.head,
|
|
311
329
|
remoteHead: currentRemoteHead,
|
|
330
|
+
...(urlReplaced ? {remoteUrl: remoteEntry.url} : {}),
|
|
312
331
|
})
|
|
313
332
|
}
|
|
314
333
|
}
|
|
@@ -323,7 +342,8 @@ export class ChangeDetector {
|
|
|
323
342
|
* This is critical for clone scenarios where local snapshot is empty
|
|
324
343
|
*/
|
|
325
344
|
private async detectNewRemoteDocuments(
|
|
326
|
-
snapshot: SyncSnapshot
|
|
345
|
+
snapshot: SyncSnapshot,
|
|
346
|
+
excludePaths?: Set<string>
|
|
327
347
|
): Promise<DetectedChange[]> {
|
|
328
348
|
const changes: DetectedChange[] = []
|
|
329
349
|
|
|
@@ -338,7 +358,8 @@ export class ChangeDetector {
|
|
|
338
358
|
snapshot.rootDirectoryUrl,
|
|
339
359
|
"",
|
|
340
360
|
snapshot,
|
|
341
|
-
changes
|
|
361
|
+
changes,
|
|
362
|
+
excludePaths
|
|
342
363
|
)
|
|
343
364
|
} catch (error) {
|
|
344
365
|
out.taskLine(`Failed to discover remote documents: ${error}`, true)
|
|
@@ -354,7 +375,8 @@ export class ChangeDetector {
|
|
|
354
375
|
directoryUrl: AutomergeUrl,
|
|
355
376
|
currentPath: string,
|
|
356
377
|
snapshot: SyncSnapshot,
|
|
357
|
-
changes: DetectedChange[]
|
|
378
|
+
changes: DetectedChange[],
|
|
379
|
+
excludePaths?: Set<string>
|
|
358
380
|
): Promise<void> {
|
|
359
381
|
try {
|
|
360
382
|
// Find and wait for document to be available (retries on "unavailable")
|
|
@@ -373,6 +395,12 @@ export class ChangeDetector {
|
|
|
373
395
|
: entry.name
|
|
374
396
|
|
|
375
397
|
if (entry.type === "file") {
|
|
398
|
+
// Skip files that were deliberately deleted during this sync cycle
|
|
399
|
+
if (excludePaths?.has(entryPath)) {
|
|
400
|
+
debug(`skipping deleted path during re-detection: ${entryPath}`)
|
|
401
|
+
continue
|
|
402
|
+
}
|
|
403
|
+
|
|
376
404
|
// Check if this file is already tracked in the snapshot
|
|
377
405
|
const existingEntry = snapshot.files.get(entryPath)
|
|
378
406
|
|
|
@@ -412,7 +440,43 @@ export class ChangeDetector {
|
|
|
412
440
|
remoteHead,
|
|
413
441
|
})
|
|
414
442
|
}
|
|
415
|
-
|
|
443
|
+
// Only ignore if neither local nor remote content exists (ghost entry)
|
|
444
|
+
} else if (
|
|
445
|
+
getPlainUrl(entry.url) !== getPlainUrl(existingEntry.url)
|
|
446
|
+
) {
|
|
447
|
+
// HACK: URL replacement detection bolted onto the "discover new docs" walk.
|
|
448
|
+
//
|
|
449
|
+
// A peer can replace a document entirely (creating a new URL) rather than mutating
|
|
450
|
+
// the existing one. This happens in several cases in updateRemoteFile(): artifact
|
|
451
|
+
// paths are always replaced; non-artifact docs with legacy immutable string content
|
|
452
|
+
// are also replaced; and recreateFailedDocuments() replaces docs that timed out
|
|
453
|
+
// during network sync. The two normal remote-change scans both miss this:
|
|
454
|
+
// - detectRemoteChanges() is snapshot-centric: it checks the old (now orphaned)
|
|
455
|
+
// doc's heads, which haven't changed, so it reports no change.
|
|
456
|
+
// - The "new doc" branch above is directory-centric: it skips paths already in
|
|
457
|
+
// the snapshot, assuming they're handled by detectRemoteChanges().
|
|
458
|
+
//
|
|
459
|
+
// A cleaner fix would be to have detectRemoteChanges() also verify that the
|
|
460
|
+
// directory still points to the same URL for each snapshot entry, treating a
|
|
461
|
+
// mismatch as a first-class URL-replacement change rather than a special case here.
|
|
462
|
+
const localContent = await this.getLocalContent(entryPath)
|
|
463
|
+
const remoteContent = await this.getCurrentRemoteContent(entry.url)
|
|
464
|
+
const remoteHead = await this.getCurrentRemoteHead(entry.url)
|
|
465
|
+
|
|
466
|
+
if (remoteContent !== null) {
|
|
467
|
+
changes.push({
|
|
468
|
+
path: entryPath,
|
|
469
|
+
changeType:
|
|
470
|
+
localContent !== null
|
|
471
|
+
? ChangeType.BOTH_CHANGED
|
|
472
|
+
: ChangeType.REMOTE_ONLY,
|
|
473
|
+
fileType: await this.getFileTypeFromContent(remoteContent),
|
|
474
|
+
localContent: localContent ?? null,
|
|
475
|
+
remoteContent,
|
|
476
|
+
remoteHead,
|
|
477
|
+
remoteUrl: entry.url,
|
|
478
|
+
})
|
|
479
|
+
}
|
|
416
480
|
}
|
|
417
481
|
} else if (entry.type === "folder") {
|
|
418
482
|
// Recursively process subdirectory
|
|
@@ -420,7 +484,8 @@ export class ChangeDetector {
|
|
|
420
484
|
entry.url,
|
|
421
485
|
entryPath,
|
|
422
486
|
snapshot,
|
|
423
|
-
changes
|
|
487
|
+
changes,
|
|
488
|
+
excludePaths
|
|
424
489
|
)
|
|
425
490
|
}
|
|
426
491
|
}
|
|
@@ -456,10 +521,7 @@ export class ChangeDetector {
|
|
|
456
521
|
const relativePath = getRelativePath(this.rootPath, entry.path)
|
|
457
522
|
const content = await readFileContent(entry.path)
|
|
458
523
|
|
|
459
|
-
fileMap.set(relativePath, {
|
|
460
|
-
content,
|
|
461
|
-
type: entry.type,
|
|
462
|
-
})
|
|
524
|
+
fileMap.set(relativePath, {content, type: entry.type})
|
|
463
525
|
})
|
|
464
526
|
)
|
|
465
527
|
} catch (error) {
|
|
@@ -564,7 +626,10 @@ export class ChangeDetector {
|
|
|
564
626
|
private async getCurrentRemoteHead(url: AutomergeUrl): Promise<UrlHeads> {
|
|
565
627
|
try {
|
|
566
628
|
const plainUrl = getPlainUrl(url)
|
|
567
|
-
const result = await this.findDocument<FileDocument>(plainUrl, {
|
|
629
|
+
const result = await this.findDocument<FileDocument>(plainUrl, {
|
|
630
|
+
maxRetries: 3,
|
|
631
|
+
retryDelayMs: 200,
|
|
632
|
+
})
|
|
568
633
|
if (!result) return [] as unknown as UrlHeads
|
|
569
634
|
return result.handle.heads()
|
|
570
635
|
} catch {
|
|
@@ -630,18 +695,18 @@ export class ChangeDetector {
|
|
|
630
695
|
}
|
|
631
696
|
|
|
632
697
|
/**
|
|
633
|
-
*
|
|
698
|
+
* Find a file's entry in the remote directory hierarchy.
|
|
699
|
+
* Returns the entry (with name, type, url) or null if not found.
|
|
634
700
|
*/
|
|
635
|
-
private async
|
|
701
|
+
private async findInRemoteDirectory(
|
|
636
702
|
rootDirectoryUrl: AutomergeUrl | undefined,
|
|
637
703
|
filePath: string
|
|
638
|
-
): Promise<
|
|
639
|
-
if (!rootDirectoryUrl) return
|
|
640
|
-
|
|
704
|
+
): Promise<{ name: string; type: string; url: AutomergeUrl } | null> {
|
|
705
|
+
if (!rootDirectoryUrl) return null
|
|
706
|
+
return findFileInDirectoryHierarchy(
|
|
641
707
|
this.repo,
|
|
642
708
|
rootDirectoryUrl,
|
|
643
709
|
filePath
|
|
644
710
|
)
|
|
645
|
-
return entry !== null
|
|
646
711
|
}
|
|
647
712
|
}
|