figma-relai 0.7.3 → 0.7.4

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.
@@ -16,7 +16,7 @@ function createServer() {
16
16
  return new McpServer(
17
17
  {
18
18
  name: "Relai",
19
- version: "0.7.3"
19
+ version: "0.7.4"
20
20
  },
21
21
  {
22
22
  instructions: `
@@ -1885,7 +1885,7 @@ import { z as z12 } from "zod";
1885
1885
  function register11(server, sendCommand) {
1886
1886
  server.tool(
1887
1887
  "import_from_library",
1888
- "Import a component, style, or variable from an enabled team library by its key. Component keys come from the design system or get_local_components; imported components can then be instantiated with manage_components.",
1888
+ "Import a component, style, or variable from an enabled team library by its key. Keys come from get_design_system's libraryCatalog, which resolves each library this file draws from and lists everything it publishes \u2014 not just what the file already uses. If the library you want is not in that catalog, it is listed under librariesNotCatalogued with what to do about it. Imported components can then be instantiated with manage_components.",
1889
1889
  {
1890
1890
  kind: z12.enum(["component", "style", "variable"]),
1891
1891
  key: z12.string().describe("Library key")
@@ -2195,13 +2195,15 @@ function register15(server, sendCommand) {
2195
2195
  var design_system_exports = {};
2196
2196
  __export(design_system_exports, {
2197
2197
  discoverLibraryFiles: () => discoverLibraryFiles,
2198
+ librariesNotCatalogued: () => librariesNotCatalogued,
2199
+ probeFailureNote: () => probeFailureNote,
2198
2200
  register: () => register16
2199
2201
  });
2200
2202
  import { z as z17 } from "zod";
2201
2203
  function register16(server, sendCommand) {
2202
2204
  server.tool(
2203
2205
  "get_design_system",
2204
- "Inventory the design system available to this file \u2014 call this BEFORE building UI, then prefer instantiating existing components (manage_components action:instantiate takes local and library keys) and binding existing variables over drawing raw shapes. Reports: local components/styles/variable collections with usage counts, remote components/styles the file already uses, enabled libraries' variable collections, and \u2014 with a token stored (`npx figma-relai login`) \u2014 the FULL published catalog of every library this file consumes, resolved automatically. What the file already uses is never the whole library: a component the file has not placed yet is invisible until this catalog is read. Results are cached per session \u2014 pass refresh:true after big library changes.",
2206
+ "Inventory the design system available to this file \u2014 call this BEFORE building UI, then prefer instantiating existing components (manage_components action:instantiate takes local and library keys) and binding existing variables over drawing raw shapes. Reports: local components/styles/variable collections with usage counts, remote components/styles the file already uses, enabled libraries' variable collections, and \u2014 with a token stored (`npx figma-relai login`) \u2014 the FULL published catalog of every library this file consumes, resolved automatically. What the file already uses is never the whole library: a component the file has not placed yet is invisible until this catalog is read. A library the file has drawn from NOTHING at all cannot be resolved either \u2014 those are named under librariesNotCatalogued, with the one step that fixes it. Results are cached per session \u2014 pass refresh:true after big library changes.",
2205
2207
  {
2206
2208
  refresh: z17.boolean().optional().describe("Rescan instead of using the session cache"),
2207
2209
  libraryFileUrl: z17.string().optional().describe(
@@ -2217,6 +2219,10 @@ function register16(server, sendCommand) {
2217
2219
  12e4
2218
2220
  );
2219
2221
  data.libraryCatalog = await fetchLibraryCatalogs(libraryFileUrl, data);
2222
+ if (!libraryFileUrl) {
2223
+ const missed = librariesNotCatalogued(data);
2224
+ if (missed.length) data.librariesNotCatalogued = missedNote(missed);
2225
+ }
2220
2226
  const truncNotes = [];
2221
2227
  const components = data.components;
2222
2228
  for (const [group, entry] of Object.entries(components ?? {})) {
@@ -2308,9 +2314,10 @@ function apiFor(token) {
2308
2314
  return { ok: res.ok, status: res.status, json };
2309
2315
  };
2310
2316
  }
2311
- function authFailure(statuses) {
2312
- if (statuses.length === 0 || !statuses.every((s) => s === 401 || s === 403)) return null;
2313
- return "Figma rejected the token on every probe (401/403) \u2014 it is expired or lacks the file content read scope. Re-run `npx -y figma-relai@latest login`, then retry.";
2317
+ function probeFailureNote(statuses) {
2318
+ const denied = statuses.filter((s) => s === 401 || s === 403).length;
2319
+ if (denied === 0) return null;
2320
+ return denied === statuses.length ? "Figma rejected the token on every probe (401/403) \u2014 it is expired or lacks the file content read scope. Re-run `npx -y figma-relai@latest login`, then retry." : `Figma refused ${denied} of ${statuses.length} probes with 401/403 \u2014 the token works, but it cannot read the libraries this file draws from (they belong to a team or organisation it has no access to). Ask for access to that library file, or pass libraryFileUrl for one you can read.`;
2314
2321
  }
2315
2322
  var metaOf = (r) => r.json.meta ?? {};
2316
2323
  async function discoverLibraryFiles(api, scan) {
@@ -2334,7 +2341,7 @@ async function discoverLibraryFiles(api, scan) {
2334
2341
  }
2335
2342
  }
2336
2343
  if (found.size === 0) {
2337
- const denied = authFailure(statuses);
2344
+ const denied = probeFailureNote(statuses);
2338
2345
  if (denied) throw new Error(denied);
2339
2346
  }
2340
2347
  return [...found].map(([fileKey, via]) => ({ fileKey, via }));
@@ -2376,6 +2383,29 @@ async function catalogOne(api, fileKey) {
2376
2383
  }))
2377
2384
  };
2378
2385
  }
2386
+ function librariesNotCatalogued(data) {
2387
+ const catalog = data.libraryCatalog;
2388
+ if (!catalog?.libraries) return [];
2389
+ const norm = (s) => s.trim().toLowerCase();
2390
+ const seen = new Set(catalog.libraries.map((l) => norm(l.name ?? "")));
2391
+ const enabled = data.variables?.libraryCollections;
2392
+ const names = /* @__PURE__ */ new Set();
2393
+ for (const c of enabled ?? []) {
2394
+ const name = c.libraryName?.trim();
2395
+ if (name && !seen.has(norm(name))) names.add(name);
2396
+ }
2397
+ return [...names];
2398
+ }
2399
+ function missedNote(names) {
2400
+ return {
2401
+ libraries: names,
2402
+ why: "Enabled, but absent from the catalog above \u2014 usually because this file has not placed a single component or style from them, so there is no key to resolve their file from.",
2403
+ // The remedy is the designer's, not the agent's: one instance is enough,
2404
+ // and only while the scan runs — the keys it yields stay valid after.
2405
+ how: "Ask the designer to drag any one component from that library onto the canvas (any page), then call this tool again with refresh:true. The instance can be deleted once the catalog is read \u2014 the keys remain valid. Or pass libraryFileUrl with the library file's figma.com URL.",
2406
+ ignoreIf: "A library that publishes only variables always lands here; its contents are already in variables.libraryCollections."
2407
+ };
2408
+ }
2379
2409
  async function fetchLibraryCatalogs(libraryFileUrl, scan) {
2380
2410
  const token = loadToken();
2381
2411
  if (!token) {
@@ -2396,8 +2426,9 @@ async function fetchLibraryCatalogs(libraryFileUrl, scan) {
2396
2426
  return { note: err.message };
2397
2427
  }
2398
2428
  if (!targets.length) {
2429
+ const remote = (scan.components?.remoteUsed?.items?.length ?? 0) + (scan.styles?.remoteUsed?.items?.length ?? 0);
2399
2430
  return {
2400
- note: "No library file could be resolved from the keys this file holds \u2014 every candidate 404'd (unpublished, or from a library this token cannot read). Pass libraryFileUrl explicitly."
2431
+ note: remote ? "No library file could be resolved from the keys this file holds \u2014 every candidate 404'd (unpublished, or from a library this token cannot read). Pass libraryFileUrl explicitly." : "This file uses no remote components or styles, so there is no key to resolve a library from. Either it draws from none, or it publishes its own \u2014 check components.local. Pass libraryFileUrl to catalog a specific library anyway."
2401
2432
  };
2402
2433
  }
2403
2434
  }
@@ -4444,4 +4475,4 @@ export {
4444
4475
  listToolCatalog,
4445
4476
  registerPrompts
4446
4477
  };
4447
- //# sourceMappingURL=chunk-BEGACSIP.js.map
4478
+ //# sourceMappingURL=chunk-BW7VTSKX.js.map