pushwork 1.0.5 → 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.
- package/README.md +87 -335
- package/dist/.pushwork/automerge/3P/Dm3ekE2pmjGnWvDaG3vSR7ww98/snapshot/aa2349c94955ea561f698720142f9d884a6872d9f82dc332d578c216beb0df0e +0 -0
- package/dist/.pushwork/automerge/st/orage-adapter-id +1 -0
- package/dist/.pushwork/config.json +15 -0
- package/dist/.pushwork/snapshot.json +7 -0
- package/dist/cli.js +208 -213
- package/dist/cli.js.map +1 -1
- package/dist/commands.d.ts +51 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +799 -0
- package/dist/commands.js.map +1 -0
- package/dist/core/change-detection.d.ts +2 -23
- package/dist/core/change-detection.d.ts.map +1 -1
- package/dist/core/change-detection.js +73 -115
- package/dist/core/change-detection.js.map +1 -1
- package/dist/{config/index.d.ts → core/config.d.ts} +13 -3
- package/dist/core/config.d.ts.map +1 -0
- package/dist/{config/index.js → core/config.js} +55 -73
- package/dist/core/config.js.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/move-detection.d.ts +4 -3
- package/dist/core/move-detection.d.ts.map +1 -1
- package/dist/core/move-detection.js +8 -7
- package/dist/core/move-detection.js.map +1 -1
- package/dist/core/snapshot.d.ts +0 -4
- package/dist/core/snapshot.d.ts.map +1 -1
- package/dist/core/snapshot.js +2 -11
- package/dist/core/snapshot.js.map +1 -1
- package/dist/core/sync-engine.d.ts +5 -11
- package/dist/core/sync-engine.d.ts.map +1 -1
- package/dist/core/sync-engine.js +211 -308
- package/dist/core/sync-engine.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -6
- package/dist/index.js.map +1 -1
- package/dist/types/config.d.ts +24 -88
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +6 -0
- package/dist/types/config.js.map +1 -1
- package/dist/types/documents.d.ts +15 -2
- package/dist/types/documents.d.ts.map +1 -1
- package/dist/types/documents.js.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/snapshot.d.ts +0 -21
- package/dist/types/snapshot.d.ts.map +1 -1
- package/dist/types/snapshot.js +0 -14
- package/dist/types/snapshot.js.map +1 -1
- package/dist/utils/content.d.ts.map +1 -1
- package/dist/utils/content.js +2 -6
- package/dist/utils/content.js.map +1 -1
- package/dist/utils/directory.d.ts +10 -0
- package/dist/utils/directory.d.ts.map +1 -0
- package/dist/utils/directory.js +37 -0
- package/dist/utils/directory.js.map +1 -0
- package/dist/utils/fs.d.ts +15 -2
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +54 -20
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -3
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/mime-types.d.ts.map +1 -1
- package/dist/utils/mime-types.js +11 -4
- package/dist/utils/mime-types.js.map +1 -1
- package/dist/utils/network-sync.d.ts +0 -6
- package/dist/utils/network-sync.d.ts.map +1 -1
- package/dist/utils/network-sync.js +55 -99
- package/dist/utils/network-sync.js.map +1 -1
- package/dist/utils/output.d.ts +129 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +375 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/repo-factory.d.ts +2 -6
- package/dist/utils/repo-factory.d.ts.map +1 -1
- package/dist/utils/repo-factory.js +8 -31
- package/dist/utils/repo-factory.js.map +1 -1
- package/dist/utils/string-similarity.js +2 -2
- package/dist/utils/string-similarity.js.map +1 -1
- package/dist/utils/trace.d.ts +19 -0
- package/dist/utils/trace.d.ts.map +1 -0
- package/dist/utils/trace.js +68 -0
- package/dist/utils/trace.js.map +1 -0
- package/package.json +11 -11
- package/src/cli.ts +276 -308
- package/src/commands.ts +988 -0
- package/src/core/change-detection.ts +182 -240
- package/src/{config/index.ts → core/config.ts} +65 -82
- package/src/core/index.ts +1 -1
- package/src/core/move-detection.ts +10 -8
- package/src/core/snapshot.ts +2 -12
- package/src/core/sync-engine.ts +237 -427
- package/src/index.ts +0 -10
- package/src/types/config.ts +28 -93
- package/src/types/documents.ts +16 -2
- package/src/types/index.ts +0 -5
- package/src/types/snapshot.ts +0 -23
- package/src/utils/content.ts +2 -6
- package/src/utils/directory.ts +50 -0
- package/src/utils/fs.ts +58 -23
- package/src/utils/index.ts +1 -5
- package/src/utils/mime-types.ts +12 -4
- package/src/utils/network-sync.ts +79 -137
- package/src/utils/output.ts +450 -0
- package/src/utils/repo-factory.ts +13 -44
- package/src/utils/string-similarity.ts +2 -2
- package/src/utils/trace.ts +70 -0
- package/test/integration/exclude-patterns.test.ts +6 -15
- package/test/integration/fuzzer.test.ts +308 -391
- package/test/integration/init-sync.test.ts +89 -0
- package/test/integration/sync-deletion.test.ts +2 -61
- package/test/integration/sync-flow.test.ts +4 -24
- package/test/jest.setup.ts +34 -0
- package/test/unit/deletion-behavior.test.ts +3 -14
- package/test/unit/enhanced-mime-detection.test.ts +0 -22
- package/test/unit/snapshot.test.ts +2 -29
- package/test/unit/sync-convergence.test.ts +3 -198
- package/test/unit/sync-timing.test.ts +0 -44
- package/test/unit/utils.test.ts +0 -2
- package/tsconfig.json +3 -3
- package/bench/filesystem.bench.ts +0 -78
- package/bench/hashing.bench.ts +0 -60
- package/bench/move-detection.bench.ts +0 -130
- package/bench/runner.ts +0 -49
- package/dist/browser/browser-sync-engine.d.ts +0 -64
- package/dist/browser/browser-sync-engine.d.ts.map +0 -1
- package/dist/browser/browser-sync-engine.js +0 -303
- package/dist/browser/browser-sync-engine.js.map +0 -1
- package/dist/browser/filesystem-adapter.d.ts +0 -84
- package/dist/browser/filesystem-adapter.d.ts.map +0 -1
- package/dist/browser/filesystem-adapter.js +0 -413
- package/dist/browser/filesystem-adapter.js.map +0 -1
- package/dist/browser/index.d.ts +0 -36
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/index.js +0 -90
- package/dist/browser/index.js.map +0 -1
- package/dist/browser/types.d.ts +0 -70
- package/dist/browser/types.d.ts.map +0 -1
- package/dist/browser/types.js +0 -6
- package/dist/browser/types.js.map +0 -1
- package/dist/cli/commands.d.ts +0 -67
- package/dist/cli/commands.d.ts.map +0 -1
- package/dist/cli/commands.js +0 -794
- package/dist/cli/commands.js.map +0 -1
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -19
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/output.d.ts +0 -75
- package/dist/cli/output.d.ts.map +0 -1
- package/dist/cli/output.js +0 -182
- package/dist/cli/output.js.map +0 -1
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/index.js.map +0 -1
- package/dist/config/remote-manager.d.ts +0 -65
- package/dist/config/remote-manager.d.ts.map +0 -1
- package/dist/config/remote-manager.js +0 -243
- package/dist/config/remote-manager.js.map +0 -1
- package/dist/core/isomorphic-snapshot.d.ts +0 -58
- package/dist/core/isomorphic-snapshot.d.ts.map +0 -1
- package/dist/core/isomorphic-snapshot.js +0 -204
- package/dist/core/isomorphic-snapshot.js.map +0 -1
- package/dist/platform/browser-filesystem.d.ts +0 -26
- package/dist/platform/browser-filesystem.d.ts.map +0 -1
- package/dist/platform/browser-filesystem.js +0 -91
- package/dist/platform/browser-filesystem.js.map +0 -1
- package/dist/platform/filesystem.d.ts +0 -29
- package/dist/platform/filesystem.d.ts.map +0 -1
- package/dist/platform/filesystem.js +0 -65
- package/dist/platform/filesystem.js.map +0 -1
- package/dist/platform/node-filesystem.d.ts +0 -21
- package/dist/platform/node-filesystem.d.ts.map +0 -1
- package/dist/platform/node-filesystem.js +0 -93
- package/dist/platform/node-filesystem.js.map +0 -1
- package/dist/utils/content-similarity.d.ts +0 -53
- package/dist/utils/content-similarity.d.ts.map +0 -1
- package/dist/utils/content-similarity.js +0 -155
- package/dist/utils/content-similarity.js.map +0 -1
- package/dist/utils/fs-browser.d.ts +0 -57
- package/dist/utils/fs-browser.d.ts.map +0 -1
- package/dist/utils/fs-browser.js +0 -311
- package/dist/utils/fs-browser.js.map +0 -1
- package/dist/utils/fs-node.d.ts +0 -53
- package/dist/utils/fs-node.d.ts.map +0 -1
- package/dist/utils/fs-node.js +0 -220
- package/dist/utils/fs-node.js.map +0 -1
- package/dist/utils/isomorphic.d.ts +0 -29
- package/dist/utils/isomorphic.d.ts.map +0 -1
- package/dist/utils/isomorphic.js +0 -139
- package/dist/utils/isomorphic.js.map +0 -1
- package/dist/utils/pure.d.ts +0 -25
- package/dist/utils/pure.d.ts.map +0 -1
- package/dist/utils/pure.js +0 -112
- package/dist/utils/pure.js.map +0 -1
- package/src/cli/commands.ts +0 -1030
- package/src/cli/index.ts +0 -2
- package/src/cli/output.ts +0 -244
- package/test/README-TESTING-GAPS.md +0 -174
|
@@ -4,34 +4,19 @@ import {
|
|
|
4
4
|
ChangeType,
|
|
5
5
|
FileType,
|
|
6
6
|
SyncSnapshot,
|
|
7
|
-
SnapshotFileEntry,
|
|
8
|
-
SnapshotDirectoryEntry,
|
|
9
7
|
FileDocument,
|
|
10
8
|
DirectoryDocument,
|
|
9
|
+
DetectedChange,
|
|
11
10
|
} from "../types";
|
|
12
11
|
import {
|
|
13
12
|
readFileContent,
|
|
14
|
-
getFileSystemEntry,
|
|
15
13
|
listDirectory,
|
|
16
14
|
getRelativePath,
|
|
17
|
-
|
|
15
|
+
findFileInDirectoryHierarchy,
|
|
16
|
+
joinAndNormalizePath,
|
|
18
17
|
} from "../utils";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export { ChangeType } from "../types";
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Represents a detected change
|
|
25
|
-
*/
|
|
26
|
-
export interface DetectedChange {
|
|
27
|
-
path: string;
|
|
28
|
-
changeType: ChangeType;
|
|
29
|
-
fileType: FileType;
|
|
30
|
-
localContent: string | Uint8Array | null;
|
|
31
|
-
remoteContent: string | Uint8Array | null;
|
|
32
|
-
localHead?: UrlHeads;
|
|
33
|
-
remoteHead?: UrlHeads;
|
|
34
|
-
}
|
|
18
|
+
import { isContentEqual } from "../utils/content";
|
|
19
|
+
import { out } from "../utils/output";
|
|
35
20
|
|
|
36
21
|
/**
|
|
37
22
|
* Change detection engine
|
|
@@ -76,36 +61,82 @@ export class ChangeDetector {
|
|
|
76
61
|
): Promise<DetectedChange[]> {
|
|
77
62
|
const changes: DetectedChange[] = [];
|
|
78
63
|
|
|
79
|
-
// Check for new and modified files
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
64
|
+
// Check for new and modified files in parallel for better performance
|
|
65
|
+
await Promise.all(
|
|
66
|
+
Array.from(currentFiles.entries()).map(
|
|
67
|
+
async ([relativePath, fileInfo]) => {
|
|
68
|
+
const snapshotEntry = snapshot.files.get(relativePath);
|
|
69
|
+
|
|
70
|
+
if (!snapshotEntry) {
|
|
71
|
+
// New file
|
|
72
|
+
changes.push({
|
|
73
|
+
path: relativePath,
|
|
74
|
+
changeType: ChangeType.LOCAL_ONLY,
|
|
75
|
+
fileType: fileInfo.type,
|
|
76
|
+
localContent: fileInfo.content,
|
|
77
|
+
remoteContent: null,
|
|
78
|
+
});
|
|
79
|
+
} else {
|
|
80
|
+
// Check if content changed
|
|
81
|
+
const lastKnownContent = await this.getContentAtHead(
|
|
82
|
+
snapshotEntry.url,
|
|
83
|
+
snapshotEntry.head
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const contentChanged = !isContentEqual(
|
|
87
|
+
fileInfo.content,
|
|
88
|
+
lastKnownContent
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (contentChanged) {
|
|
92
|
+
// Check remote state too
|
|
93
|
+
const currentRemoteContent = await this.getCurrentRemoteContent(
|
|
94
|
+
snapshotEntry.url
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const remoteChanged = !isContentEqual(
|
|
98
|
+
lastKnownContent,
|
|
99
|
+
currentRemoteContent
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const changeType = remoteChanged
|
|
103
|
+
? ChangeType.BOTH_CHANGED
|
|
104
|
+
: ChangeType.LOCAL_ONLY;
|
|
105
|
+
|
|
106
|
+
const remoteHead = await this.getCurrentRemoteHead(
|
|
107
|
+
snapshotEntry.url
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
changes.push({
|
|
111
|
+
path: relativePath,
|
|
112
|
+
changeType,
|
|
113
|
+
fileType: fileInfo.type,
|
|
114
|
+
localContent: fileInfo.content,
|
|
115
|
+
remoteContent: currentRemoteContent,
|
|
116
|
+
localHead: snapshotEntry.head,
|
|
117
|
+
remoteHead,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Check for deleted files in parallel
|
|
126
|
+
await Promise.all(
|
|
127
|
+
Array.from(snapshot.files.entries())
|
|
128
|
+
.filter(([relativePath]) => !currentFiles.has(relativePath))
|
|
129
|
+
.map(async ([relativePath, snapshotEntry]) => {
|
|
130
|
+
// File was deleted locally
|
|
105
131
|
const currentRemoteContent = await this.getCurrentRemoteContent(
|
|
106
132
|
snapshotEntry.url
|
|
107
133
|
);
|
|
108
|
-
const
|
|
134
|
+
const lastKnownContent = await this.getContentAtHead(
|
|
135
|
+
snapshotEntry.url,
|
|
136
|
+
snapshotEntry.head
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const remoteChanged = !isContentEqual(
|
|
109
140
|
lastKnownContent,
|
|
110
141
|
currentRemoteContent
|
|
111
142
|
);
|
|
@@ -117,47 +148,14 @@ export class ChangeDetector {
|
|
|
117
148
|
changes.push({
|
|
118
149
|
path: relativePath,
|
|
119
150
|
changeType,
|
|
120
|
-
fileType:
|
|
121
|
-
localContent:
|
|
151
|
+
fileType: FileType.TEXT, // Will be determined from document
|
|
152
|
+
localContent: null,
|
|
122
153
|
remoteContent: currentRemoteContent,
|
|
123
154
|
localHead: snapshotEntry.head,
|
|
124
155
|
remoteHead: await this.getCurrentRemoteHead(snapshotEntry.url),
|
|
125
156
|
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Check for deleted files
|
|
131
|
-
for (const [relativePath, snapshotEntry] of snapshot.files.entries()) {
|
|
132
|
-
if (!currentFiles.has(relativePath)) {
|
|
133
|
-
// File was deleted locally
|
|
134
|
-
const currentRemoteContent = await this.getCurrentRemoteContent(
|
|
135
|
-
snapshotEntry.url
|
|
136
|
-
);
|
|
137
|
-
const lastKnownContent = await this.getContentAtHead(
|
|
138
|
-
snapshotEntry.url,
|
|
139
|
-
snapshotEntry.head
|
|
140
|
-
);
|
|
141
|
-
const remoteChanged = !this.isContentEqual(
|
|
142
|
-
lastKnownContent,
|
|
143
|
-
currentRemoteContent
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
const changeType = remoteChanged
|
|
147
|
-
? ChangeType.BOTH_CHANGED
|
|
148
|
-
: ChangeType.LOCAL_ONLY;
|
|
149
|
-
|
|
150
|
-
changes.push({
|
|
151
|
-
path: relativePath,
|
|
152
|
-
changeType,
|
|
153
|
-
fileType: FileType.TEXT, // Will be determined from document
|
|
154
|
-
localContent: null,
|
|
155
|
-
remoteContent: currentRemoteContent,
|
|
156
|
-
localHead: snapshotEntry.head,
|
|
157
|
-
remoteHead: await this.getCurrentRemoteHead(snapshotEntry.url),
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}
|
|
157
|
+
})
|
|
158
|
+
);
|
|
161
159
|
|
|
162
160
|
return changes;
|
|
163
161
|
}
|
|
@@ -170,68 +168,72 @@ export class ChangeDetector {
|
|
|
170
168
|
): Promise<DetectedChange[]> {
|
|
171
169
|
const changes: DetectedChange[] = [];
|
|
172
170
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
171
|
+
await Promise.all(
|
|
172
|
+
Array.from(snapshot.files.entries()).map(
|
|
173
|
+
async ([relativePath, snapshotEntry]) => {
|
|
174
|
+
// CRITICAL FIX: Check if file still exists in remote directory listing
|
|
175
|
+
// Files can be removed from the directory without their document heads changing
|
|
176
|
+
const stillExistsInDirectory = await this.fileExistsInRemoteDirectory(
|
|
177
|
+
snapshot.rootDirectoryUrl,
|
|
178
|
+
relativePath
|
|
179
|
+
);
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
if (!stillExistsInDirectory) {
|
|
182
|
+
// File was removed from remote directory listing
|
|
183
|
+
const localContent = await this.getLocalContent(relativePath);
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
185
|
+
// Only report as deleted if local file still exists
|
|
186
|
+
// (if local file is also deleted, detectLocalChanges handles it)
|
|
187
|
+
if (localContent !== null) {
|
|
188
|
+
changes.push({
|
|
189
|
+
path: relativePath,
|
|
190
|
+
changeType: ChangeType.REMOTE_ONLY,
|
|
191
|
+
fileType: FileType.TEXT,
|
|
192
|
+
localContent,
|
|
193
|
+
remoteContent: null, // File deleted remotely
|
|
194
|
+
localHead: snapshotEntry.head,
|
|
195
|
+
remoteHead: snapshotEntry.head,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
200
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
const currentRemoteHead = await this.getCurrentRemoteHead(
|
|
202
|
+
snapshotEntry.url
|
|
203
|
+
);
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
205
|
+
if (!A.equals(currentRemoteHead, snapshotEntry.head)) {
|
|
206
|
+
// Remote document has changed
|
|
207
|
+
const currentRemoteContent = await this.getCurrentRemoteContent(
|
|
208
|
+
snapshotEntry.url
|
|
209
|
+
);
|
|
210
|
+
const localContent = await this.getLocalContent(relativePath);
|
|
211
|
+
const lastKnownContent = await this.getContentAtHead(
|
|
212
|
+
snapshotEntry.url,
|
|
213
|
+
snapshotEntry.head
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const localChanged = localContent
|
|
217
|
+
? !isContentEqual(localContent, lastKnownContent)
|
|
218
|
+
: false;
|
|
219
|
+
|
|
220
|
+
const changeType = localChanged
|
|
221
|
+
? ChangeType.BOTH_CHANGED
|
|
222
|
+
: ChangeType.REMOTE_ONLY;
|
|
223
|
+
|
|
224
|
+
changes.push({
|
|
225
|
+
path: relativePath,
|
|
226
|
+
changeType,
|
|
227
|
+
fileType: await this.getFileTypeFromContent(currentRemoteContent),
|
|
228
|
+
localContent,
|
|
229
|
+
remoteContent: currentRemoteContent,
|
|
230
|
+
localHead: snapshotEntry.head,
|
|
231
|
+
remoteHead: currentRemoteHead,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
);
|
|
235
237
|
|
|
236
238
|
return changes;
|
|
237
239
|
}
|
|
@@ -259,7 +261,7 @@ export class ChangeDetector {
|
|
|
259
261
|
changes
|
|
260
262
|
);
|
|
261
263
|
} catch (error) {
|
|
262
|
-
|
|
264
|
+
out.taskLine(`Failed to discover remote documents: ${error}`, true);
|
|
263
265
|
}
|
|
264
266
|
|
|
265
267
|
return changes;
|
|
@@ -341,7 +343,7 @@ export class ChangeDetector {
|
|
|
341
343
|
}
|
|
342
344
|
}
|
|
343
345
|
} catch (error) {
|
|
344
|
-
|
|
346
|
+
out.taskLine(`Failed to process directory: ${error}`, true);
|
|
345
347
|
}
|
|
346
348
|
}
|
|
347
349
|
|
|
@@ -363,8 +365,12 @@ export class ChangeDetector {
|
|
|
363
365
|
this.excludePatterns
|
|
364
366
|
);
|
|
365
367
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
+
const fileEntries = entries.filter(
|
|
369
|
+
(entry) => entry.type !== FileType.DIRECTORY
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
await Promise.all(
|
|
373
|
+
fileEntries.map(async (entry) => {
|
|
368
374
|
const relativePath = getRelativePath(this.rootPath, entry.path);
|
|
369
375
|
const content = await readFileContent(entry.path);
|
|
370
376
|
|
|
@@ -372,10 +378,17 @@ export class ChangeDetector {
|
|
|
372
378
|
content,
|
|
373
379
|
type: entry.type,
|
|
374
380
|
});
|
|
381
|
+
})
|
|
382
|
+
);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
out.taskLine(`Failed to scan filesystem: ${error}`, true);
|
|
385
|
+
// Log more details about the error
|
|
386
|
+
if (error instanceof Error) {
|
|
387
|
+
out.taskLine(`Error details: ${error.message}`, true);
|
|
388
|
+
if (error.stack) {
|
|
389
|
+
out.taskLine(`Stack: ${error.stack}`, true);
|
|
375
390
|
}
|
|
376
391
|
}
|
|
377
|
-
} catch (error) {
|
|
378
|
-
console.warn(`Failed to scan filesystem: ${error}`);
|
|
379
392
|
}
|
|
380
393
|
|
|
381
394
|
return fileMap;
|
|
@@ -388,7 +401,7 @@ export class ChangeDetector {
|
|
|
388
401
|
relativePath: string
|
|
389
402
|
): Promise<string | Uint8Array | null> {
|
|
390
403
|
try {
|
|
391
|
-
const fullPath =
|
|
404
|
+
const fullPath = joinAndNormalizePath(this.rootPath, relativePath);
|
|
392
405
|
return await readFileContent(fullPath);
|
|
393
406
|
} catch {
|
|
394
407
|
return null;
|
|
@@ -404,7 +417,13 @@ export class ChangeDetector {
|
|
|
404
417
|
): Promise<string | Uint8Array | null> {
|
|
405
418
|
const handle = await this.repo.find<FileDocument>(url);
|
|
406
419
|
const doc = await handle.view(heads).doc();
|
|
407
|
-
|
|
420
|
+
|
|
421
|
+
const content = (doc as FileDocument | undefined)?.content;
|
|
422
|
+
// Convert ImmutableString to regular string
|
|
423
|
+
if (A.isImmutableString(content)) {
|
|
424
|
+
return content.toString();
|
|
425
|
+
}
|
|
426
|
+
return content as string | Uint8Array;
|
|
408
427
|
}
|
|
409
428
|
|
|
410
429
|
/**
|
|
@@ -420,11 +439,14 @@ export class ChangeDetector {
|
|
|
420
439
|
if (!doc) return null;
|
|
421
440
|
|
|
422
441
|
const fileDoc = doc as FileDocument;
|
|
423
|
-
|
|
442
|
+
const content = fileDoc.content;
|
|
443
|
+
// Convert ImmutableString to regular string
|
|
444
|
+
if (A.isImmutableString(content)) {
|
|
445
|
+
return content.toString();
|
|
446
|
+
}
|
|
447
|
+
return content as string | Uint8Array;
|
|
424
448
|
} catch (error) {
|
|
425
|
-
|
|
426
|
-
`❌ Failed to get current remote content for ${url}: ${error}`
|
|
427
|
-
);
|
|
449
|
+
out.taskLine(`Failed to get remote content: ${error}`, true);
|
|
428
450
|
return null;
|
|
429
451
|
}
|
|
430
452
|
}
|
|
@@ -433,7 +455,8 @@ export class ChangeDetector {
|
|
|
433
455
|
* Get current head of Automerge document
|
|
434
456
|
*/
|
|
435
457
|
private async getCurrentRemoteHead(url: AutomergeUrl): Promise<UrlHeads> {
|
|
436
|
-
|
|
458
|
+
const handle = await this.repo.find<FileDocument>(url);
|
|
459
|
+
return handle.heads();
|
|
437
460
|
}
|
|
438
461
|
|
|
439
462
|
/**
|
|
@@ -451,35 +474,6 @@ export class ChangeDetector {
|
|
|
451
474
|
}
|
|
452
475
|
}
|
|
453
476
|
|
|
454
|
-
/**
|
|
455
|
-
* Compare two content pieces for equality
|
|
456
|
-
*/
|
|
457
|
-
private isContentEqual(
|
|
458
|
-
content1: string | Uint8Array | null,
|
|
459
|
-
content2: string | Uint8Array | null
|
|
460
|
-
): boolean {
|
|
461
|
-
if (content1 === content2) return true;
|
|
462
|
-
if (!content1 || !content2) return false;
|
|
463
|
-
|
|
464
|
-
if (typeof content1 !== typeof content2) return false;
|
|
465
|
-
|
|
466
|
-
if (typeof content1 === "string") {
|
|
467
|
-
return content1 === content2;
|
|
468
|
-
} else {
|
|
469
|
-
// Compare Uint8Array
|
|
470
|
-
const buf1 = content1 as Uint8Array;
|
|
471
|
-
const buf2 = content2 as Uint8Array;
|
|
472
|
-
|
|
473
|
-
if (buf1.length !== buf2.length) return false;
|
|
474
|
-
|
|
475
|
-
for (let i = 0; i < buf1.length; i++) {
|
|
476
|
-
if (buf1[i] !== buf2[i]) return false;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
return true;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
477
|
/**
|
|
484
478
|
* Classify change type for a path
|
|
485
479
|
*/
|
|
@@ -504,9 +498,9 @@ export class ChangeDetector {
|
|
|
504
498
|
);
|
|
505
499
|
|
|
506
500
|
const localChanged = localContent
|
|
507
|
-
? !
|
|
501
|
+
? !isContentEqual(localContent, lastKnownContent)
|
|
508
502
|
: true;
|
|
509
|
-
const remoteChanged = !
|
|
503
|
+
const remoteChanged = !isContentEqual(
|
|
510
504
|
lastKnownContent,
|
|
511
505
|
currentRemoteContent
|
|
512
506
|
);
|
|
@@ -530,63 +524,11 @@ export class ChangeDetector {
|
|
|
530
524
|
filePath: string
|
|
531
525
|
): Promise<boolean> {
|
|
532
526
|
if (!rootDirectoryUrl) return false;
|
|
533
|
-
const entry = await
|
|
527
|
+
const entry = await findFileInDirectoryHierarchy(
|
|
528
|
+
this.repo,
|
|
534
529
|
rootDirectoryUrl,
|
|
535
530
|
filePath
|
|
536
531
|
);
|
|
537
532
|
return entry !== null;
|
|
538
533
|
}
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* Find a file in the directory hierarchy by path
|
|
542
|
-
*/
|
|
543
|
-
private async findFileInDirectoryHierarchy(
|
|
544
|
-
directoryUrl: AutomergeUrl,
|
|
545
|
-
filePath: string
|
|
546
|
-
): Promise<{ name: string; type: string; url: AutomergeUrl } | null> {
|
|
547
|
-
try {
|
|
548
|
-
const pathParts = filePath.split("/");
|
|
549
|
-
let currentDirUrl = directoryUrl;
|
|
550
|
-
|
|
551
|
-
// Navigate through directories to find the parent directory
|
|
552
|
-
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
553
|
-
const dirName = pathParts[i];
|
|
554
|
-
const dirHandle = await this.repo.find<DirectoryDocument>(
|
|
555
|
-
currentDirUrl
|
|
556
|
-
);
|
|
557
|
-
const dirDoc = await dirHandle.doc();
|
|
558
|
-
|
|
559
|
-
if (!dirDoc) return null;
|
|
560
|
-
|
|
561
|
-
const subDirEntry = dirDoc.docs.find(
|
|
562
|
-
(entry: { name: string; type: string; url: AutomergeUrl }) =>
|
|
563
|
-
entry.name === dirName && entry.type === "folder"
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
if (!subDirEntry) return null;
|
|
567
|
-
currentDirUrl = subDirEntry.url;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// Now look for the file in the final directory
|
|
571
|
-
const fileName = pathParts[pathParts.length - 1];
|
|
572
|
-
const finalDirHandle = await this.repo.find<DirectoryDocument>(
|
|
573
|
-
currentDirUrl
|
|
574
|
-
);
|
|
575
|
-
const finalDirDoc = await finalDirHandle.doc();
|
|
576
|
-
|
|
577
|
-
if (!finalDirDoc) return null;
|
|
578
|
-
|
|
579
|
-
const fileEntry = finalDirDoc.docs.find(
|
|
580
|
-
(entry: { name: string; type: string; url: AutomergeUrl }) =>
|
|
581
|
-
entry.name === fileName && entry.type === "file"
|
|
582
|
-
);
|
|
583
|
-
|
|
584
|
-
return fileEntry || null;
|
|
585
|
-
} catch (error) {
|
|
586
|
-
console.warn(
|
|
587
|
-
`Failed to find file ${filePath} in directory hierarchy: ${error}`
|
|
588
|
-
);
|
|
589
|
-
return null;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
534
|
}
|