@floomhq/floom 1.0.52 → 1.0.53

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 (2) hide show
  1. package/dist/sync.js +55 -1
  2. package/package.json +1 -1
package/dist/sync.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { constants } from "node:fs";
2
- import { lstat, mkdir, open } from "node:fs/promises";
2
+ import { lstat, mkdir, open, rm, rmdir } from "node:fs/promises";
3
3
  import { createHash } from "node:crypto";
4
4
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
5
  import ora from "ora";
@@ -224,6 +224,40 @@ async function overwriteTrackedFile(root, target, body, expectedHash) {
224
224
  await parent.close();
225
225
  }
226
226
  }
227
+ async function deleteSyncedFile(root, target, expectedHash) {
228
+ const state = await localState(target);
229
+ if (state.kind === "missing")
230
+ return;
231
+ if (state.kind === "conflict")
232
+ throw conflictError(state.reason, "EEXIST");
233
+ if (state.hash !== expectedHash)
234
+ throw conflictError("local file changed since the last Floom sync", "EEXIST");
235
+ await rm(target);
236
+ await pruneEmptyParents(root, dirname(target));
237
+ }
238
+ async function pruneEmptyParents(root, startDir) {
239
+ const resolvedRoot = resolve(root);
240
+ let current = resolve(startDir);
241
+ for (;;) {
242
+ const relativeCurrent = relative(resolvedRoot, current);
243
+ if (!relativeCurrent || relativeCurrent === ".." || relativeCurrent.startsWith(`..${sep}`) || isAbsolute(relativeCurrent))
244
+ return;
245
+ try {
246
+ await rmdir(current);
247
+ }
248
+ catch (err) {
249
+ const code = err.code;
250
+ if (code === "ENOENT") {
251
+ current = dirname(current);
252
+ continue;
253
+ }
254
+ if (code === "ENOTEMPTY" || code === "EEXIST" || code === "ENOTDIR")
255
+ return;
256
+ throw err;
257
+ }
258
+ current = dirname(current);
259
+ }
260
+ }
227
261
  async function ensureSafeParentDirectory(root, target) {
228
262
  const resolvedRoot = resolve(root);
229
263
  const resolvedParent = resolve(dirname(target));
@@ -446,6 +480,26 @@ export async function sync(opts = {}) {
446
480
  noteConflict(target, "local file changed since the last Floom sync");
447
481
  continue;
448
482
  }
483
+ try {
484
+ await deleteSyncedFile(root, target, entry.hash);
485
+ }
486
+ catch (err) {
487
+ const code = err.code;
488
+ if (code === "ENOENT") {
489
+ unmarkSynced(manifest, key);
490
+ manifestChanged = true;
491
+ continue;
492
+ }
493
+ if (code === "ELOOP") {
494
+ noteManifestConflict(key, "path contains a symbolic link");
495
+ continue;
496
+ }
497
+ if (code === "ENOTDIR" || code === "EISDIR" || code === "EEXIST") {
498
+ noteManifestConflict(key, err instanceof Error ? err.message : "local file changed since the last Floom sync");
499
+ continue;
500
+ }
501
+ throw err;
502
+ }
449
503
  unmarkSynced(manifest, key);
450
504
  manifestChanged = true;
451
505
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/floom",
3
- "version": "1.0.52",
3
+ "version": "1.0.53",
4
4
  "description": "Sync AI skills across agents and machines.",
5
5
  "license": "MIT",
6
6
  "type": "module",