figma-relai 0.7.2 → 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.
- package/dist/{chunk-EU6JIYHS.js → chunk-BW7VTSKX.js} +48 -19
- package/dist/{chunk-EU6JIYHS.js.map → chunk-BW7VTSKX.js.map} +1 -1
- package/dist/index.js +10 -7
- package/dist/index.js.map +1 -1
- package/dist/{manifest-M5YNF3DV.js → manifest-XNMB2VXD.js} +2 -2
- package/package.json +1 -1
- /package/dist/{manifest-M5YNF3DV.js.map → manifest-XNMB2VXD.js.map} +0 -0
|
@@ -16,7 +16,7 @@ function createServer() {
|
|
|
16
16
|
return new McpServer(
|
|
17
17
|
{
|
|
18
18
|
name: "Relai",
|
|
19
|
-
version: "0.7.
|
|
19
|
+
version: "0.7.4"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
instructions: `
|
|
@@ -889,11 +889,7 @@ async function resolveFileIdentity(sendCommand) {
|
|
|
889
889
|
statuses.push(res.status);
|
|
890
890
|
const meta = res.json.meta ?? {};
|
|
891
891
|
if (res.ok && typeof meta.file_key === "string") {
|
|
892
|
-
main = {
|
|
893
|
-
fileKey: meta.file_key,
|
|
894
|
-
fileName: meta.file_name ?? rootName,
|
|
895
|
-
via: c.key
|
|
896
|
-
};
|
|
892
|
+
main = { fileKey: meta.file_key, via: c.key };
|
|
897
893
|
break;
|
|
898
894
|
}
|
|
899
895
|
}
|
|
@@ -905,16 +901,18 @@ async function resolveFileIdentity(sendCommand) {
|
|
|
905
901
|
denied ? "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`." : "None of this file's published component keys resolved."
|
|
906
902
|
);
|
|
907
903
|
}
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
904
|
+
const file = await figmaApi(token, `/files/${main.fileKey}?branch_data=true&depth=1`);
|
|
905
|
+
const identity = {
|
|
906
|
+
fileKey: main.fileKey,
|
|
907
|
+
fileName: typeof file.json.name === "string" ? file.json.name : rootName
|
|
908
|
+
};
|
|
909
|
+
if (rootName && rootName !== identity.fileName) {
|
|
910
|
+
const branches = file.json.branches ?? [];
|
|
912
911
|
const hit = branches.find((b) => b.name === rootName);
|
|
913
912
|
if (hit?.key) {
|
|
914
913
|
identity.branchKey = hit.key;
|
|
915
914
|
identity.branchName = hit.name;
|
|
916
915
|
}
|
|
917
|
-
if (typeof res.json.name === "string") identity.fileName = res.json.name;
|
|
918
916
|
}
|
|
919
917
|
try {
|
|
920
918
|
await sendCommand("set_file_identity", { identity, componentKey: main.via });
|
|
@@ -1887,7 +1885,7 @@ import { z as z12 } from "zod";
|
|
|
1887
1885
|
function register11(server, sendCommand) {
|
|
1888
1886
|
server.tool(
|
|
1889
1887
|
"import_from_library",
|
|
1890
|
-
"Import a component, style, or variable from an enabled team library by its key.
|
|
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.",
|
|
1891
1889
|
{
|
|
1892
1890
|
kind: z12.enum(["component", "style", "variable"]),
|
|
1893
1891
|
key: z12.string().describe("Library key")
|
|
@@ -2197,13 +2195,15 @@ function register15(server, sendCommand) {
|
|
|
2197
2195
|
var design_system_exports = {};
|
|
2198
2196
|
__export(design_system_exports, {
|
|
2199
2197
|
discoverLibraryFiles: () => discoverLibraryFiles,
|
|
2198
|
+
librariesNotCatalogued: () => librariesNotCatalogued,
|
|
2199
|
+
probeFailureNote: () => probeFailureNote,
|
|
2200
2200
|
register: () => register16
|
|
2201
2201
|
});
|
|
2202
2202
|
import { z as z17 } from "zod";
|
|
2203
2203
|
function register16(server, sendCommand) {
|
|
2204
2204
|
server.tool(
|
|
2205
2205
|
"get_design_system",
|
|
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. 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.",
|
|
2207
2207
|
{
|
|
2208
2208
|
refresh: z17.boolean().optional().describe("Rescan instead of using the session cache"),
|
|
2209
2209
|
libraryFileUrl: z17.string().optional().describe(
|
|
@@ -2219,6 +2219,10 @@ function register16(server, sendCommand) {
|
|
|
2219
2219
|
12e4
|
|
2220
2220
|
);
|
|
2221
2221
|
data.libraryCatalog = await fetchLibraryCatalogs(libraryFileUrl, data);
|
|
2222
|
+
if (!libraryFileUrl) {
|
|
2223
|
+
const missed = librariesNotCatalogued(data);
|
|
2224
|
+
if (missed.length) data.librariesNotCatalogued = missedNote(missed);
|
|
2225
|
+
}
|
|
2222
2226
|
const truncNotes = [];
|
|
2223
2227
|
const components = data.components;
|
|
2224
2228
|
for (const [group, entry] of Object.entries(components ?? {})) {
|
|
@@ -2310,9 +2314,10 @@ function apiFor(token) {
|
|
|
2310
2314
|
return { ok: res.ok, status: res.status, json };
|
|
2311
2315
|
};
|
|
2312
2316
|
}
|
|
2313
|
-
function
|
|
2314
|
-
|
|
2315
|
-
|
|
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.`;
|
|
2316
2321
|
}
|
|
2317
2322
|
var metaOf = (r) => r.json.meta ?? {};
|
|
2318
2323
|
async function discoverLibraryFiles(api, scan) {
|
|
@@ -2336,7 +2341,7 @@ async function discoverLibraryFiles(api, scan) {
|
|
|
2336
2341
|
}
|
|
2337
2342
|
}
|
|
2338
2343
|
if (found.size === 0) {
|
|
2339
|
-
const denied =
|
|
2344
|
+
const denied = probeFailureNote(statuses);
|
|
2340
2345
|
if (denied) throw new Error(denied);
|
|
2341
2346
|
}
|
|
2342
2347
|
return [...found].map(([fileKey, via]) => ({ fileKey, via }));
|
|
@@ -2378,6 +2383,29 @@ async function catalogOne(api, fileKey) {
|
|
|
2378
2383
|
}))
|
|
2379
2384
|
};
|
|
2380
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
|
+
}
|
|
2381
2409
|
async function fetchLibraryCatalogs(libraryFileUrl, scan) {
|
|
2382
2410
|
const token = loadToken();
|
|
2383
2411
|
if (!token) {
|
|
@@ -2398,8 +2426,9 @@ async function fetchLibraryCatalogs(libraryFileUrl, scan) {
|
|
|
2398
2426
|
return { note: err.message };
|
|
2399
2427
|
}
|
|
2400
2428
|
if (!targets.length) {
|
|
2429
|
+
const remote = (scan.components?.remoteUsed?.items?.length ?? 0) + (scan.styles?.remoteUsed?.items?.length ?? 0);
|
|
2401
2430
|
return {
|
|
2402
|
-
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."
|
|
2403
2432
|
};
|
|
2404
2433
|
}
|
|
2405
2434
|
}
|
|
@@ -4446,4 +4475,4 @@ export {
|
|
|
4446
4475
|
listToolCatalog,
|
|
4447
4476
|
registerPrompts
|
|
4448
4477
|
};
|
|
4449
|
-
//# sourceMappingURL=chunk-
|
|
4478
|
+
//# sourceMappingURL=chunk-BW7VTSKX.js.map
|