feat(core,cli): figma REST client, asset import command, binding index (M0+M1) (#1870)

M0: renderNode/imageFills/variables/styles/nodeTree/fileVersion over
api.figma.com with injectable fetch and typed capability errors
(NO_TOKEN/BAD_TOKEN/REQUIRES_ENTERPRISE/RATE_LIMITED/RENDER_FAILED/
NODE_NOT_FOUND/HTTP_ERROR) per design spec 4.4.

M1: svg sanitizer (scripts/foreignObject/handlers/external hrefs) +
hyperframes figma asset: render -> sanitize -> freeze under .media/ ->
manifest provenance -> snippet. Idempotent on
fileKey:nodeId:format:scale:version; re-imports when the version moves.

Plus the 7.1 binding index store (.media/figma-bindings.jsonl): exact-ID
lookup incl. alias chains, per-project library-file answers, shared
jsonl reader with the asset manifest.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-07-03 18:11:33 -07:00
committed by GitHub
co-authored by Claude Fable 5
parent 23f67da5e2
commit fb13797d2f
13 changed files with 1114 additions and 14 deletions
+47
View File
@@ -0,0 +1,47 @@
/**
* `hyperframes figma` — import figma assets, tokens, and components over
* the REST API (design spec: phases 13 run on REST; motion/shaders are
* MCP-only and live in the /figma skill, not this command).
*
* Requires FIGMA_TOKEN (personal access token from figma.com/settings).
*/
import { defineCommand } from "citty";
import type { Example } from "./_examples.js";
import { c } from "../ui/colors.js";
export const examples: Example[] = [
[
"Import a frame as a frozen SVG asset",
"hyperframes figma asset 'https://www.figma.com/design/KEY/T?node-id=1-2'",
],
["Import as PNG at 2x", "hyperframes figma asset KEY:1-2 --format png --scale 2"],
["Pull brand tokens into the composition", "hyperframes figma tokens KEY"],
["Import a frame as an editable HTML component", "hyperframes figma component KEY:10-20"],
];
const HELP = `
${c.bold("hyperframes figma")} ${c.dim("<subcommand> [args]")}
Import figma content over the REST API. Requires ${c.accent("FIGMA_TOKEN")}.
${c.bold("SUBCOMMANDS:")}
${c.accent("asset")} ${c.dim("Render a node (png/svg/jpg/pdf), freeze under .media/, print a snippet.")}
${c.accent("tokens")} ${c.dim("Import variables/styles as composition brand variables.")}
${c.bold("ENV VARS:")}
${c.accent("FIGMA_TOKEN")} Personal access token (figma.com/settings → security).
${c.dim("Motion and shader import are agent-only (figma exposes no REST endpoint for")}
${c.dim("either) — use the /figma skill in a Claude session for those.")}
`;
export default defineCommand({
meta: { name: "figma", description: "Import figma assets, tokens, and components (REST)" },
subCommands: {
asset: () => import("./figma/asset.js").then((m) => m.default),
},
async run({ args }) {
if (!args._?.[0]) console.log(HELP);
},
});