@gobi-ai/cli 0.6.13 → 0.6.14
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/dist/commands/sync.js +29 -37
- package/package.json +1 -1
package/dist/commands/sync.js
CHANGED
|
@@ -272,6 +272,7 @@ async function webdriveDelete(baseUrl, vaultSlug, filePath, token) {
|
|
|
272
272
|
}
|
|
273
273
|
async function webdriveSync(baseUrl, vaultSlug, body, token) {
|
|
274
274
|
const url = `${baseUrl}/api/v1/vaults/${vaultSlug}/sync`;
|
|
275
|
+
process.stderr.write(`[gobi-sync] syncfiles: body=${JSON.stringify(body)}\n`);
|
|
275
276
|
const res = await fetch(url, {
|
|
276
277
|
method: "POST",
|
|
277
278
|
headers: {
|
|
@@ -342,8 +343,9 @@ function matchesPaths(filePath, paths) {
|
|
|
342
343
|
async function performSync(baseUrl, vaultSlug, state, syncfilesChanges, privatefilesChanges, localFiles, opts, token) {
|
|
343
344
|
const body = {
|
|
344
345
|
cursor: state.cursor,
|
|
345
|
-
|
|
346
|
-
|
|
346
|
+
// dryRun: don't mutate server-side syncfiles/privatefiles
|
|
347
|
+
syncfilesChanges: opts.dryRun ? { added: [], removed: [] } : syncfilesChanges,
|
|
348
|
+
privatefilesChanges: opts.dryRun ? { added: [], removed: [] } : privatefilesChanges,
|
|
347
349
|
clientFiles: localFiles,
|
|
348
350
|
uploadOnly: opts.uploadOnly,
|
|
349
351
|
downloadOnly: opts.downloadOnly,
|
|
@@ -364,51 +366,41 @@ export async function runSync(opts) {
|
|
|
364
366
|
console.log("Full sync: ignoring cursor and hash cache.");
|
|
365
367
|
}
|
|
366
368
|
const token = opts.authToken ?? (await getValidToken());
|
|
367
|
-
// Sync privatefiles with server
|
|
368
369
|
// Read syncfiles whitelist
|
|
370
|
+
const syncfilesExistsLocally = existsSync(join(gobiDir, "syncfiles"));
|
|
369
371
|
const { patterns: currPatterns, contentHash: currSyncfilesHash } = readSyncfiles(gobiDir);
|
|
370
372
|
if (currPatterns.length === 0 && !jsonMode) {
|
|
371
373
|
console.warn("Warning: No patterns found in .gobi/syncfiles. Nothing will be synced.\n" +
|
|
372
374
|
"Add gitignore-style patterns to .gobi/syncfiles to select files for sync.");
|
|
373
375
|
}
|
|
374
376
|
const isWhitelisted = buildWhitelistMatcher(currPatterns);
|
|
375
|
-
// On bootstrap (no prior state), fetch server's current syncfiles so removals
|
|
376
|
-
// relative to the server are captured correctly in the delta.
|
|
377
377
|
let baseSyncPatterns = state.patterns;
|
|
378
|
-
if (
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
378
|
+
if (state.syncfilesHash === null) {
|
|
379
|
+
// Bootstrap: use empty base so local patterns are sent as "added" only.
|
|
380
|
+
// This avoids spuriously removing server-only patterns from other devices.
|
|
381
|
+
// The server returns its current syncfilesHash, which then triggers a download
|
|
382
|
+
// to pull any server patterns the client doesn't have yet.
|
|
383
|
+
baseSyncPatterns = [];
|
|
384
|
+
}
|
|
385
|
+
else if (!syncfilesExistsLocally) {
|
|
386
|
+
// File deleted after a prior sync. Produce empty diff to avoid removing patterns
|
|
387
|
+
// from server. The download condition below re-fetches the missing file.
|
|
388
|
+
currPatterns.length = 0;
|
|
389
|
+
currPatterns.push(...state.patterns);
|
|
390
|
+
baseSyncPatterns = [...state.patterns];
|
|
391
391
|
}
|
|
392
392
|
const syncfilesChanges = computeSyncfilesChanges(baseSyncPatterns, currPatterns);
|
|
393
|
-
// Compute privatefiles delta
|
|
393
|
+
// Compute privatefiles delta
|
|
394
|
+
const privatefilesExistsLocally = existsSync(join(gobiDir, "privatefiles"));
|
|
394
395
|
const currPrivatePatterns = readPrivatefiles(gobiDir);
|
|
395
|
-
// On bootstrap (no prior state), fetch server's current patterns so we can compute
|
|
396
|
-
// correct removals. Without this, patterns the user deleted would stay on the server
|
|
397
|
-
// because we'd have no baseline to diff against.
|
|
398
396
|
let basePrivatePatterns = state.privatePatterns;
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
.filter((l) => l.length > 0 && !l.startsWith("#"));
|
|
407
|
-
process.stderr.write(`[gobi-sync] bootstrap: fetched server privatefiles, patterns=${JSON.stringify(basePrivatePatterns)}\n`);
|
|
408
|
-
}
|
|
409
|
-
catch {
|
|
410
|
-
basePrivatePatterns = []; // server has no privatefiles yet
|
|
411
|
-
}
|
|
397
|
+
if (state.privatefilesHash === null) {
|
|
398
|
+
// Bootstrap: same as syncfiles — empty base, rely on hash comparison for download.
|
|
399
|
+
basePrivatePatterns = [];
|
|
400
|
+
}
|
|
401
|
+
else if (!privatefilesExistsLocally) {
|
|
402
|
+
// File deleted after a prior sync. Produce empty diff.
|
|
403
|
+
basePrivatePatterns = [...currPrivatePatterns];
|
|
412
404
|
}
|
|
413
405
|
const privatefilesChanges = computeSyncfilesChanges(basePrivatePatterns, currPrivatePatterns);
|
|
414
406
|
// Walk local files (only whitelisted, non-ignored)
|
|
@@ -603,7 +595,7 @@ export async function runSync(opts) {
|
|
|
603
595
|
// Download syncfiles from server if the server's hash changed since last sync
|
|
604
596
|
let effectivePatterns = currPatterns;
|
|
605
597
|
process.stderr.write(`[gobi-sync] syncfiles: state=${state.syncfilesHash ?? "null"} server=${syncResp.syncfilesHash ?? "null"}\n`);
|
|
606
|
-
if (!opts.dryRun && syncResp.syncfilesHash && syncResp.syncfilesHash !== state.syncfilesHash) {
|
|
598
|
+
if (!opts.dryRun && !opts.uploadOnly && syncResp.syncfilesHash && (syncResp.syncfilesHash !== state.syncfilesHash || !syncfilesExistsLocally)) {
|
|
607
599
|
process.stderr.write(`[gobi-sync] syncfiles hash changed — downloading from server\n`);
|
|
608
600
|
try {
|
|
609
601
|
const syncfilesContent = await webdriveGet(baseUrl, vaultSlug, ".gobi/syncfiles", token);
|
|
@@ -623,7 +615,7 @@ export async function runSync(opts) {
|
|
|
623
615
|
// Download privatefiles from server if the server's hash changed since last sync
|
|
624
616
|
let effectivePrivatePatterns = currPrivatePatterns;
|
|
625
617
|
process.stderr.write(`[gobi-sync] privatefiles: state=${state.privatefilesHash ?? "null"} server=${syncResp.privatefilesHash ?? "null"}\n`);
|
|
626
|
-
if (!opts.dryRun && syncResp.privatefilesHash && syncResp.privatefilesHash !== state.privatefilesHash) {
|
|
618
|
+
if (!opts.dryRun && !opts.uploadOnly && syncResp.privatefilesHash && (syncResp.privatefilesHash !== state.privatefilesHash || !privatefilesExistsLocally)) {
|
|
627
619
|
process.stderr.write(`[gobi-sync] privatefiles hash changed — downloading from server\n`);
|
|
628
620
|
try {
|
|
629
621
|
const privatefilesContent = await webdriveGet(baseUrl, vaultSlug, ".gobi/privatefiles", token);
|