@floomhq/floom 1.0.33 → 1.0.35

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
@@ -216,7 +216,7 @@ async function collectPackageFiles(root) {
216
216
  continue;
217
217
  if (await isIgnored(entry.name))
218
218
  continue;
219
- if (entry.isDirectory() && await isNestedSkillDir(join(root, entry.name)))
219
+ if (entry.isDirectory() && await hasNestedSkillDir(join(root, entry.name)))
220
220
  continue;
221
221
  if (entry.isSymbolicLink())
222
222
  continue;
@@ -287,16 +287,39 @@ async function collectDir(root, dir, files, isIgnored, addBytes) {
287
287
  await collectFile(fullPath, rel, files, addBytes);
288
288
  }
289
289
  }
290
- async function isNestedSkillDir(path) {
290
+ async function hasNestedSkillDir(path) {
291
+ return hasNestedSkillDirInner(path, 0);
292
+ }
293
+ async function hasNestedSkillDirInner(path, depth) {
294
+ if (depth > 8)
295
+ return false;
291
296
  try {
292
297
  const stat = await lstat(join(path, "SKILL.md"));
293
- return stat.isFile();
298
+ if (stat.isFile())
299
+ return true;
300
+ }
301
+ catch (err) {
302
+ if (err.code !== "ENOENT")
303
+ throw err;
304
+ }
305
+ let entries;
306
+ try {
307
+ entries = await readdir(path, { withFileTypes: true });
294
308
  }
295
309
  catch (err) {
296
310
  if (err.code === "ENOENT")
297
311
  return false;
298
312
  throw err;
299
313
  }
314
+ for (const entry of entries) {
315
+ if (!entry.isDirectory() || entry.isSymbolicLink())
316
+ continue;
317
+ if (isGeneratedPackageEntry(entry.name, true))
318
+ continue;
319
+ if (await hasNestedSkillDirInner(join(path, entry.name), depth + 1))
320
+ return true;
321
+ }
322
+ return false;
300
323
  }
301
324
  async function collectFile(fullPath, rel, files, addBytes) {
302
325
  const normalized = rel.split(sep).join("/");
@@ -155,7 +155,14 @@ export async function pushWatchOnce(opts) {
155
155
  const hash = hashPackage(key, skillPackage.skillBody, skillPackage.packageFiles);
156
156
  const pushed = pushManifest.files[pushKey];
157
157
  if (pushed?.hash === hash) {
158
- skipped += 1;
158
+ if (!isUnchangedSyncedPackage(root, skillPackage, syncManifest)) {
159
+ markPackageSynced(root, skillPackage, syncManifest, pushed.slug);
160
+ await writeSyncManifest(syncManifest);
161
+ adopted += 1;
162
+ }
163
+ else {
164
+ skipped += 1;
165
+ }
159
166
  continue;
160
167
  }
161
168
  if (!opts.yolo) {
package/dist/secrets.js CHANGED
@@ -23,7 +23,6 @@ const PROMPT_INJECTION_PATTERNS = [
23
23
  ];
24
24
  const DATA_EXFILTRATION_PATTERNS = [
25
25
  { label: "Data exfiltration instruction", regex: /\b(?:send|post|upload|exfiltrate|copy) (?:[^.\n]{0,80})\b(?:api keys?|tokens?|secrets?|environment variables|\.env|credentials)\b(?:[^.\n]{0,120})\b(?:to|into) https?:\/\//gi },
26
- { label: "Data exfiltration instruction", regex: /\b(?:curl|wget|fetch)\b[^\n]{0,160}\b(?:api keys?|tokens?|secrets?|environment variables|\.env|credentials)\b/gi },
27
26
  { label: "Credential harvesting instruction", regex: /\b(?:collect|harvest|steal|extract) (?:[^.\n]{0,80})\b(?:api keys?|tokens?|secrets?|environment variables|\.env|credentials)\b/gi },
28
27
  ];
29
28
  function redact(value) {
@@ -46,6 +45,9 @@ function pushFinding(findings, seen, label, line, value) {
46
45
  seen.add(key);
47
46
  findings.push({ label, line, preview: redact(value) });
48
47
  }
48
+ function isDocumentedEnvReference(value) {
49
+ return /\b(?:process\.env|import\.meta\.env|os\.environ)\b/.test(value);
50
+ }
49
51
  export function detectSecrets(input) {
50
52
  const findings = [];
51
53
  const seen = new Set();
@@ -61,6 +63,8 @@ export function detectSecrets(input) {
61
63
  const value = match[1] ?? "";
62
64
  if (!value || PLACEHOLDER_RE.test(value))
63
65
  continue;
66
+ if (isDocumentedEnvReference(value))
67
+ continue;
64
68
  pushFinding(findings, seen, "Possible secret assignment", lineNumberAt(input, match.index ?? 0), value);
65
69
  }
66
70
  PROVIDER_LIKE_ASSIGNMENT_RE.lastIndex = 0;
@@ -68,6 +72,8 @@ export function detectSecrets(input) {
68
72
  const value = match[1] ?? "";
69
73
  if (!value)
70
74
  continue;
75
+ if (isDocumentedEnvReference(value))
76
+ continue;
71
77
  pushFinding(findings, seen, "Provider-like secret assignment", lineNumberAt(input, match.index ?? 0), value);
72
78
  }
73
79
  return findings.sort((a, b) => a.line - b.line || a.label.localeCompare(b.label));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/floom",
3
- "version": "1.0.33",
3
+ "version": "1.0.35",
4
4
  "description": "Sync AI skills across agents and machines.",
5
5
  "license": "MIT",
6
6
  "type": "module",