@floomhq/floom 1.0.16 → 1.0.17

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/package.js CHANGED
@@ -253,6 +253,7 @@ export function normalizeRemotePackageFiles(input) {
253
253
  throw new FloomError("Skill package response has too many files.");
254
254
  }
255
255
  let totalBytes = 0;
256
+ const seenPaths = new Set();
256
257
  return input.map((raw) => {
257
258
  if (!raw || typeof raw !== "object")
258
259
  throw new FloomError("Invalid skill package response.");
@@ -260,6 +261,10 @@ export function normalizeRemotePackageFiles(input) {
260
261
  if (typeof file.path !== "string")
261
262
  throw new FloomError("Invalid skill package response.");
262
263
  validatePackageRelativePath(file.path);
264
+ const pathKey = file.path.toLowerCase();
265
+ if (seenPaths.has(pathKey))
266
+ throw new FloomError(`Duplicate package file: ${file.path}`);
267
+ seenPaths.add(pathKey);
263
268
  let bytes;
264
269
  if (typeof file.content_base64 === "string") {
265
270
  if (file.encoding !== undefined && file.encoding !== "base64") {
package/dist/sync.js CHANGED
@@ -159,6 +159,7 @@ function syncPackageFiles(target, body, files) {
159
159
  async function planPackageSync(root, files, manifest) {
160
160
  let missing = 0;
161
161
  let unchanged = 0;
162
+ let firstMissingTarget = null;
162
163
  for (const file of files) {
163
164
  const targetKey = manifestKey(root, file.target);
164
165
  const tracked = manifest.files[targetKey];
@@ -179,8 +180,7 @@ async function planPackageSync(root, files, manifest) {
179
180
  if (state.kind === "conflict")
180
181
  return { kind: "conflict", target: state.conflictTarget ?? file.target, reason: state.reason };
181
182
  if (state.kind === "missing") {
182
- if (tracked && files.length > 1)
183
- return { kind: "conflict", target: file.target, reason: "local package file missing since the last Floom sync" };
183
+ firstMissingTarget ??= file.target;
184
184
  missing += 1;
185
185
  continue;
186
186
  }
@@ -196,10 +196,9 @@ async function planPackageSync(root, files, manifest) {
196
196
  return { kind: "unchanged" };
197
197
  if (missing === files.length)
198
198
  return { kind: "write" };
199
- const missingFile = files.find((file) => !manifest.files[manifestKey(root, file.target)]);
200
199
  return {
201
200
  kind: "conflict",
202
- target: missingFile?.target ?? files[0]?.target ?? root,
201
+ target: firstMissingTarget ?? files[0]?.target ?? root,
203
202
  reason: "local package is only partially installed",
204
203
  };
205
204
  }
@@ -301,6 +300,7 @@ export async function sync(opts = {}) {
301
300
  const activeTargetKeys = new Set();
302
301
  const pruneBlockedSlugs = new Set();
303
302
  let manifestChanged = false;
303
+ let synced = 0;
304
304
  const noteConflict = (target, reason) => {
305
305
  conflicts += 1;
306
306
  const rel = manifestKey(root, target);
@@ -334,6 +334,7 @@ export async function sync(opts = {}) {
334
334
  }
335
335
  const remotePackageFiles = normalizeRemotePackageFiles(skill.package_files ?? skill.files);
336
336
  const packageFiles = syncPackageFiles(target, skill.body_md, remotePackageFiles);
337
+ synced += 1;
337
338
  for (const file of packageFiles)
338
339
  activeTargetKeys.add(manifestKey(root, file.target));
339
340
  const plan = await planPackageSync(root, packageFiles, manifest);
@@ -421,7 +422,6 @@ export async function sync(opts = {}) {
421
422
  throw err;
422
423
  }
423
424
  spinner?.stop();
424
- const synced = activeTargetKeys.size;
425
425
  const skippedNote = skipped > 0 ? c.dim(` (${skipped} skipped — invalid path)`) : "";
426
426
  const conflictNote = conflicts > 0 ? c.dim(`, ${conflicts} conflict${conflicts === 1 ? "" : "s"} skipped`) : "";
427
427
  const result = { synced, unchanged, updated, skipped, conflicts };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/floom",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "Sync AI skills across agents and machines.",
5
5
  "license": "MIT",
6
6
  "type": "module",