@floomhq/floom-mcp-sync 1.0.24 → 1.0.26

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/auto-sync.js CHANGED
@@ -17,7 +17,37 @@ const HEARTBEAT_MS = 10 * 60 * 1000; // 10 minutes
17
17
  const AUTH_WARNING_MS = 10 * 60 * 1000;
18
18
  const MANIFEST_SEGMENT_RE = /^[A-Za-z0-9._-]{1,128}$/;
19
19
  const PACKAGE_FILE_SEGMENT_RE = /^[A-Za-z0-9._-]{1,128}$/;
20
- const SUPPORT_DIRS = new Set(["references", "examples", "scripts", "assets"]);
20
+ const SUPPORT_DIRS = new Set([
21
+ "agents",
22
+ "assets",
23
+ "canvas-fonts",
24
+ "checks",
25
+ "core",
26
+ "evidence",
27
+ "examples",
28
+ "helpers",
29
+ "reference",
30
+ "references",
31
+ "schemas",
32
+ "scripts",
33
+ "spreadsheets",
34
+ "templates",
35
+ "tests",
36
+ "themes",
37
+ ]);
38
+ const ROOT_FILE_EXTENSIONS = [
39
+ ".env.example",
40
+ ".js",
41
+ ".json",
42
+ ".md",
43
+ ".py",
44
+ ".sh",
45
+ ".toml",
46
+ ".ts",
47
+ ".txt",
48
+ ".yaml",
49
+ ".yml",
50
+ ];
21
51
  const FD_PATH_ROOT = "/proc/self/fd";
22
52
  const PACKAGE_FILE_LIMIT = 100;
23
53
  const PACKAGE_TOTAL_BYTES_LIMIT = 1_000_000;
@@ -173,6 +203,8 @@ function normalizePackageFilePath(path) {
173
203
  const segments = path.split("/").filter(Boolean);
174
204
  if (segments.length === 1 && segments[0] === "SKILL.md")
175
205
  return "SKILL.md";
206
+ if (segments.length === 1 && isAllowedRootPackageFile(segments[0] ?? ""))
207
+ return segments[0] ?? "";
176
208
  const first = segments[0];
177
209
  if (segments.length < 2 || first === undefined || !SUPPORT_DIRS.has(first)) {
178
210
  throw new Error("Invalid package file path");
@@ -182,6 +214,11 @@ function normalizePackageFilePath(path) {
182
214
  }
183
215
  return segments.join("/");
184
216
  }
217
+ function isAllowedRootPackageFile(name) {
218
+ if (!name || (name.startsWith(".") && name !== ".env.example"))
219
+ return false;
220
+ return ROOT_FILE_EXTENSIONS.some((ext) => name.toLowerCase().endsWith(ext));
221
+ }
185
222
  async function planPackageSync(root, files, manifest) {
186
223
  let missing = 0;
187
224
  let unchanged = 0;
@@ -33,13 +33,51 @@ function isEntryForKey(key, value) {
33
33
  function isPackageFilePath(packagePath) {
34
34
  if (packagePath.length === 1 && packagePath[0] === "SKILL.md")
35
35
  return true;
36
+ if (packagePath.length === 1 && isAllowedRootPackageFile(packagePath[0] ?? ""))
37
+ return true;
36
38
  if (packagePath.length < 2)
37
39
  return false;
38
40
  const first = packagePath[0];
39
- if (first === undefined || !["references", "examples", "scripts", "assets"].includes(first))
41
+ if (first === undefined || !SUPPORT_DIRS.has(first))
40
42
  return false;
41
43
  return packagePath.every((segment) => segment !== "." && segment !== ".." && segment.length > 0);
42
44
  }
45
+ const SUPPORT_DIRS = new Set([
46
+ "agents",
47
+ "assets",
48
+ "canvas-fonts",
49
+ "checks",
50
+ "core",
51
+ "evidence",
52
+ "examples",
53
+ "helpers",
54
+ "reference",
55
+ "references",
56
+ "schemas",
57
+ "scripts",
58
+ "spreadsheets",
59
+ "templates",
60
+ "tests",
61
+ "themes",
62
+ ]);
63
+ const ROOT_FILE_EXTENSIONS = [
64
+ ".env.example",
65
+ ".js",
66
+ ".json",
67
+ ".md",
68
+ ".py",
69
+ ".sh",
70
+ ".toml",
71
+ ".ts",
72
+ ".txt",
73
+ ".yaml",
74
+ ".yml",
75
+ ];
76
+ function isAllowedRootPackageFile(name) {
77
+ if (!name || (name.startsWith(".") && name !== ".env.example"))
78
+ return false;
79
+ return ROOT_FILE_EXTENSIONS.some((ext) => name.toLowerCase().endsWith(ext));
80
+ }
43
81
  export async function readSyncManifest() {
44
82
  try {
45
83
  await ensureSyncManifestDir();
package/dist/server.js CHANGED
@@ -5,7 +5,7 @@ import { autoSync } from "./auto-sync.js";
5
5
  import { getSkill } from "./tools/get.js";
6
6
  import { searchSkills } from "./tools/search.js";
7
7
  import { syncStatus } from "./tools/status.js";
8
- const SERVER_VERSION = "1.0.24";
8
+ const SERVER_VERSION = "1.0.26";
9
9
  const DEFAULT_INTERVAL_MS = 60_000;
10
10
  const MIN_INTERVAL_MS = 10_000;
11
11
  const SEARCH_TYPES = new Set(["knowledge", "instruction", "workflow", "skill"]);
package/dist/tools/get.js CHANGED
@@ -6,7 +6,37 @@ const PACKAGE_FILE_LIMIT = 100;
6
6
  const PACKAGE_FILE_BYTES_LIMIT = 500_000;
7
7
  const PACKAGE_TOTAL_BYTES_LIMIT = 1_000_000;
8
8
  const PATH_SEGMENT_RE = /^[A-Za-z0-9._-]{1,128}$/;
9
- const SUPPORT_DIRS = new Set(["references", "examples", "scripts", "assets"]);
9
+ const SUPPORT_DIRS = new Set([
10
+ "agents",
11
+ "assets",
12
+ "canvas-fonts",
13
+ "checks",
14
+ "core",
15
+ "evidence",
16
+ "examples",
17
+ "helpers",
18
+ "reference",
19
+ "references",
20
+ "schemas",
21
+ "scripts",
22
+ "spreadsheets",
23
+ "templates",
24
+ "tests",
25
+ "themes",
26
+ ]);
27
+ const ROOT_FILE_EXTENSIONS = [
28
+ ".env.example",
29
+ ".js",
30
+ ".json",
31
+ ".md",
32
+ ".py",
33
+ ".sh",
34
+ ".toml",
35
+ ".ts",
36
+ ".txt",
37
+ ".yaml",
38
+ ".yml",
39
+ ];
10
40
  const SHA256_RE = /^[a-f0-9]{64}$/i;
11
41
  const BASE64_RE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
12
42
  export async function getSkill(slug) {
@@ -30,7 +60,7 @@ export async function getSkill(slug) {
30
60
  content: detail.body_md,
31
61
  package: {
32
62
  main: "SKILL.md",
33
- supporting_dirs: ["references", "examples", "scripts", "assets"],
63
+ supporting_dirs: Array.from(SUPPORT_DIRS),
34
64
  },
35
65
  package_files: normalizePackageFiles(detail.package_files ?? detail.files),
36
66
  };
@@ -103,9 +133,16 @@ function isSafePackagePath(path) {
103
133
  if (!path || path.length > 512 || path.startsWith("/") || path.includes("\\") || path.includes("//"))
104
134
  return false;
105
135
  const segments = path.split("/");
136
+ if (segments.length === 1)
137
+ return isAllowedRootPackageFile(segments[0] ?? "") && PATH_SEGMENT_RE.test(segments[0] ?? "");
106
138
  if (segments.length < 2)
107
139
  return false;
108
140
  if (!SUPPORT_DIRS.has(segments[0] ?? ""))
109
141
  return false;
110
142
  return segments.every((segment) => PATH_SEGMENT_RE.test(segment) && segment !== "." && segment !== "..");
111
143
  }
144
+ function isAllowedRootPackageFile(name) {
145
+ if (!name || (name.startsWith(".") && name !== ".env.example"))
146
+ return false;
147
+ return ROOT_FILE_EXTENSIONS.some((ext) => name.toLowerCase().endsWith(ext));
148
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/floom-mcp-sync",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
4
4
  "description": "Lightweight Floom MCP server for search, on-demand skill fetch, status, and sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",