figma-console-mcp 1.38.2 → 1.39.1
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/README.md +15 -9
- package/dist/cloudflare/core/cloud-websocket-connector.js +12 -1
- package/dist/cloudflare/core/multi-file-tools.js +161 -0
- package/dist/cloudflare/core/tokens-tools.js +1 -1
- package/dist/cloudflare/core/websocket-connector.js +5 -2
- package/dist/cloudflare/core/websocket-server.js +43 -2
- package/dist/cloudflare/core/write-tools.js +9 -3
- package/dist/cloudflare/index.js +7 -7
- package/dist/core/figma-connector.d.ts +1 -1
- package/dist/core/figma-connector.d.ts.map +1 -1
- package/dist/core/multi-file-tools.d.ts +9 -0
- package/dist/core/multi-file-tools.d.ts.map +1 -0
- package/dist/core/multi-file-tools.js +162 -0
- package/dist/core/multi-file-tools.js.map +1 -0
- package/dist/core/tokens-tools.js +1 -1
- package/dist/core/websocket-connector.d.ts +1 -1
- package/dist/core/websocket-connector.d.ts.map +1 -1
- package/dist/core/websocket-connector.js +5 -2
- package/dist/core/websocket-connector.js.map +1 -1
- package/dist/core/websocket-server.d.ts +18 -1
- package/dist/core/websocket-server.d.ts.map +1 -1
- package/dist/core/websocket-server.js +43 -2
- package/dist/core/websocket-server.js.map +1 -1
- package/dist/core/write-tools.d.ts.map +1 -1
- package/dist/core/write-tools.js +9 -3
- package/dist/core/write-tools.js.map +1 -1
- package/dist/local.d.ts.map +1 -1
- package/dist/local.js +6 -0
- package/dist/local.js.map +1 -1
- package/figma-desktop-bridge/code.js +1 -1
- package/figma-desktop-bridge/ui.html +7 -0
- package/package.json +1 -1
- package/dist/apps/design-system-dashboard/scoring/fix-generator.d.ts +0 -15
- package/dist/apps/design-system-dashboard/scoring/fix-generator.d.ts.map +0 -1
- package/dist/apps/design-system-dashboard/scoring/fix-generator.js +0 -270
- package/dist/apps/design-system-dashboard/scoring/fix-generator.js.map +0 -1
- package/dist/apps/design-system-dashboard/scoring/fix-types.d.ts +0 -32
- package/dist/apps/design-system-dashboard/scoring/fix-types.d.ts.map +0 -1
- package/dist/apps/design-system-dashboard/scoring/fix-types.js +0 -8
- package/dist/apps/design-system-dashboard/scoring/fix-types.js.map +0 -1
- package/dist/apps/token-browser.d.ts +0 -30
- package/dist/apps/token-browser.d.ts.map +0 -1
- package/dist/apps/token-browser.js +0 -680
- package/dist/apps/token-browser.js.map +0 -1
- package/dist/browser/base.d.ts +0 -58
- package/dist/browser/base.d.ts.map +0 -1
- package/dist/browser/base.js +0 -6
- package/dist/browser/base.js.map +0 -1
- package/dist/browser/local.d.ts +0 -87
- package/dist/browser/local.d.ts.map +0 -1
- package/dist/browser/local.js +0 -318
- package/dist/browser/local.js.map +0 -1
- package/dist/cloudflare/apps/design-system-dashboard/scoring/fix-generator.js +0 -269
- package/dist/cloudflare/apps/design-system-dashboard/scoring/fix-types.js +0 -7
- package/dist/cloudflare/apps/hello-world/server.js +0 -63
- package/dist/cloudflare/apps/token-browser.js +0 -679
- package/dist/cloudflare/browser/base.js +0 -5
- package/dist/cloudflare/browser/cloudflare.js +0 -156
- package/dist/cloudflare/core/code-to-spec.js +0 -1126
- package/dist/cloudflare/core/figma-desktop-connector.js +0 -1297
- package/dist/cloudflare/core/figma-mcp-client.js +0 -150
- package/dist/cloudflare/test-browser.js +0 -88
- package/dist/core/cdp-pipe-manager.d.ts +0 -96
- package/dist/core/cdp-pipe-manager.d.ts.map +0 -1
- package/dist/core/cdp-pipe-manager.js +0 -429
- package/dist/core/cdp-pipe-manager.js.map +0 -1
- package/dist/core/cloud-websocket-connector.d.ts +0 -58
- package/dist/core/cloud-websocket-connector.d.ts.map +0 -1
- package/dist/core/cloud-websocket-connector.js +0 -247
- package/dist/core/cloud-websocket-connector.js.map +0 -1
- package/dist/core/cloud-websocket-relay.d.ts +0 -51
- package/dist/core/cloud-websocket-relay.d.ts.map +0 -1
- package/dist/core/cloud-websocket-relay.js +0 -171
- package/dist/core/cloud-websocket-relay.js.map +0 -1
- package/dist/core/code-to-spec.d.ts +0 -103
- package/dist/core/code-to-spec.d.ts.map +0 -1
- package/dist/core/code-to-spec.js +0 -1127
- package/dist/core/code-to-spec.js.map +0 -1
- package/dist/core/figma-desktop-connector.d.ts +0 -312
- package/dist/core/figma-desktop-connector.d.ts.map +0 -1
- package/dist/core/figma-desktop-connector.js +0 -1298
- package/dist/core/figma-desktop-connector.js.map +0 -1
- package/dist/core/figma-mcp-client.d.ts +0 -61
- package/dist/core/figma-mcp-client.d.ts.map +0 -1
- package/dist/core/figma-mcp-client.js +0 -151
- package/dist/core/figma-mcp-client.js.map +0 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
> **Your design system as an API.** Model Context Protocol server that bridges design and development—giving AI assistants complete access to Figma for **extraction**, **creation**, **debugging**, and **bidirectional token sync**.
|
|
10
10
|
|
|
11
|
-
>
|
|
11
|
+
> **🗂 Multi-File Execution (v1.39.0, patched v1.39.1):** Work across several Figma files at once. `figma_execute_across_files` runs one script against every (or a chosen subset of) connected file **concurrently** — for auditing a multi-file design system for the same problem, or applying one fix across a known set, instead of switching the active file and repeating yourself. Four files × 2s of work completes in ~3s, not ~8s. `figma_execute` also takes an optional `fileKey` to target a single file without moving the active file or releasing target lock. You must name `fileKeys` or pass `allFiles: true` — there's no fan-out-to-everything default, since this runs code in files you may be actively editing. From community PR [#107](https://github.com/southleft/figma-console-mcp/pull/107) by [@Wolfr](https://github.com/Wolfr). Also fixes a relay bug that silently dropped `resultAnalysis` and `fileContext` from every `figma_execute` response — **re-import `manifest.json`** for those two fields; everything else works without it. **Patched in v1.39.1:** if the plugin kept telling you to re-import no matter how many times you did, that was an older server instance nagging a newer plugin — an unfixable banner, now silenced. [See what's new →](CHANGELOG.md#1391---2026-08-02)
|
|
12
12
|
|
|
13
13
|
## What is this?
|
|
14
14
|
|
|
@@ -56,9 +56,9 @@ Figma Console MCP connects AI assistants (like Claude) to Figma, enabling:
|
|
|
56
56
|
| Real-time monitoring (console, selection) | ✅ | ❌ | ❌ |
|
|
57
57
|
| Desktop Bridge plugin | ✅ | ✅ | ❌ |
|
|
58
58
|
| Requires Node.js | Yes | **No** | No |
|
|
59
|
-
| **Total tools available** | **
|
|
59
|
+
| **Total tools available** | **114** | **101** | **9** |
|
|
60
60
|
|
|
61
|
-
> **Bottom line:** Remote SSE is **read-only** with 9 tools. **Cloud Mode** unlocks write access (101 tools) from web AI clients without Node.js. NPX/Local Git gives the full
|
|
61
|
+
> **Bottom line:** Remote SSE is **read-only** with 9 tools. **Cloud Mode** unlocks write access (101 tools) from web AI clients without Node.js. NPX/Local Git gives the full 114 tools with real-time monitoring.
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
@@ -66,7 +66,7 @@ Figma Console MCP connects AI assistants (like Claude) to Figma, enabling:
|
|
|
66
66
|
|
|
67
67
|
**Best for:** Designers who want full AI-assisted design capabilities.
|
|
68
68
|
|
|
69
|
-
**What you get:** All
|
|
69
|
+
**What you get:** All 114 tools including design creation, variable management, and component instantiation.
|
|
70
70
|
|
|
71
71
|
#### Prerequisites
|
|
72
72
|
|
|
@@ -163,7 +163,7 @@ Create a simple frame with a blue background
|
|
|
163
163
|
|
|
164
164
|
**Best for:** Developers who want to modify source code or contribute to the project.
|
|
165
165
|
|
|
166
|
-
**What you get:** Same
|
|
166
|
+
**What you get:** Same 114 tools as NPX, plus full source code access.
|
|
167
167
|
|
|
168
168
|
#### Quick Setup
|
|
169
169
|
|
|
@@ -309,7 +309,7 @@ AI Client → Cloud MCP Server → Durable Object Relay → Desktop Bridge Plugi
|
|
|
309
309
|
| Feature | NPX (Recommended) | Cloud Mode | Local Git | Remote SSE |
|
|
310
310
|
|---------|-------------------|------------|-----------|------------|
|
|
311
311
|
| **Setup time** | ~10 minutes | ~5 minutes | ~15 minutes | ~2 minutes |
|
|
312
|
-
| **Total tools** | **
|
|
312
|
+
| **Total tools** | **114** | **101** | **114** | **9** (read-only) |
|
|
313
313
|
| **Design creation** | ✅ | ✅ | ✅ | ❌ |
|
|
314
314
|
| **Variable management** | ✅ | ✅ | ✅ | ❌ |
|
|
315
315
|
| **Component instantiation** | ✅ | ✅ | ✅ | ❌ |
|
|
@@ -324,7 +324,7 @@ AI Client → Cloud MCP Server → Durable Object Relay → Desktop Bridge Plugi
|
|
|
324
324
|
| **Automatic updates** | ✅ (`@latest`) | ✅ | Manual (`git pull`) | ✅ |
|
|
325
325
|
| **Source code access** | ❌ | ❌ | ✅ | ❌ |
|
|
326
326
|
|
|
327
|
-
> **Key insight:** Remote SSE is read-only. Cloud Mode adds write access for web AI clients without Node.js. NPX/Local Git give the full
|
|
327
|
+
> **Key insight:** Remote SSE is read-only. Cloud Mode adds write access for web AI clients without Node.js. NPX/Local Git give the full 114 tools.
|
|
328
328
|
|
|
329
329
|
**📖 [Complete Feature Comparison](docs/mode-comparison.md)**
|
|
330
330
|
|
|
@@ -417,6 +417,10 @@ When you first use design system tools:
|
|
|
417
417
|
- Create frames, shapes, text, components
|
|
418
418
|
- Apply auto-layout, styles, effects
|
|
419
419
|
- Build complete UI mockups programmatically
|
|
420
|
+
- Optional `fileKey` targets one specific connected file directly (Local Mode only), without touching the active file or target lock
|
|
421
|
+
- `figma_execute_across_files` - **Local Mode only.** Run the same script in several Desktop Bridge-connected files at once, concurrently, returning a per-file result map — for cross-file consistency checks and fixes across a multi-file design system, replacing "open file, run plugin, repeat per file"
|
|
422
|
+
- Name the files with `fileKeys` (from `figma_list_open_files`), or pass `allFiles: true` to hit every connected file — one of the two is required, so a script never fans out to files you didn't mean to touch
|
|
423
|
+
- Per-file timeouts and error isolation: one slow or failing file doesn't delay or fail the others
|
|
420
424
|
- `figma_create_component_set` - **Create a component set with variants in one declarative call**
|
|
421
425
|
- Generate every variant combination from an axes matrix (e.g. `{ State: ["default", "hover", "disabled"], Size: ["sm", "lg"] }` → 6 variants) off a base component, or combine existing components
|
|
422
426
|
- `Prop=Value` variant naming, `combineAsVariants` under the hood, optional auto-arranged labeled grid
|
|
@@ -682,7 +686,7 @@ The **Figma Desktop Bridge** plugin is the recommended way to connect Figma to t
|
|
|
682
686
|
- The MCP server communicates via **WebSocket** through the Desktop Bridge plugin
|
|
683
687
|
- The server tries port 9223 first, then automatically falls back through ports 9224–9232 if needed
|
|
684
688
|
- The plugin scans all ports in the range and connects to every active server it finds
|
|
685
|
-
- All
|
|
689
|
+
- All 114 tools work through the WebSocket transport
|
|
686
690
|
|
|
687
691
|
**Multiple files:** The WebSocket server supports multiple simultaneous plugin connections — one per open Figma file. Each connection is tracked by file key with independent state (selection, document changes, console logs).
|
|
688
692
|
|
|
@@ -823,9 +827,11 @@ The architecture supports adding new apps with minimal boilerplate — each app
|
|
|
823
827
|
|
|
824
828
|
## 🛤️ Roadmap
|
|
825
829
|
|
|
826
|
-
**Current Status:** v1.
|
|
830
|
+
**Current Status:** v1.39.1 (Stable) - Production-ready. Latest: a fix for a plugin-update banner that could never be cleared — an older server instance nagging a newer plugin to re-import, which only ever installs the same or a newer plugin. On top of v1.39.0's multi-file execution — `figma_execute_across_files` runs one script against several Desktop Bridge-connected files concurrently (four files x 2s of work in ~3s, not ~8s), and `figma_execute` takes an optional `fileKey` to target a single file without moving the active file or releasing target lock; targeting must be explicit (`fileKeys` or `allFiles: true`), so nothing fans out to files you did not name. From community PR #107 by @Wolfr. Ships with a relay fix: `handleResult()` in the plugin's ui.html rebuilt each response field by field and silently dropped `resultAnalysis` and `fileContext`, so the `resultAnalysis.warning` check that `figma_execute`'s own description tells callers to perform has never been possible (re-import `manifest.json` for those two fields; everything else works without it). On top of v1.38.2's connection-stability fix — the server's own orphan reaper was terminating healthy MCP servers because its liveness probe used an IPv4 literal while the server binds the IPv6 loopback, which turned every kill-safety gate into a rubber stamp; this was the cause of recurring "Server disconnected" errors across all MCP clients. Alongside v1.38.1's fix for the shared-library variable tools, which had silently reported zero collections since v1.29.0 and reported failed imports as successes. On top of v1.38.0's ongoing component changelogs in generated docs — `figma_generate_component_doc` takes an opt-in `history` parameter that pulls per-component **design history** from Figma version history (each version diffed and scoped to that component, so renames, added properties, and token bindings show up as rows) alongside **code history** from `git log` on the component's source files, rendered as a `## History` section with design, code, and release-note tables. Prefers labeled versions, falls back to auto-saves when a file has none, and is off by default so existing calls are unchanged (server-only, no plugin re-import). On top of v1.37.x's design-system health audit for every client — `figma_audit_design_system_report` runs the dashboard's deterministic six-category scoring engine and returns the report as data with per-finding remediation, live-first fileKey-verified data (source disclosed), chunked per-category drill-down, and a 5-minute cache (server-only, no plugin re-import). On top of v1.36.0's target lock for multi-file parallel work — — `figma_navigate` takes a `lock: true` flag that pins the active file so an AI agent can work in one file while you work in another without commands routing to the wrong file. On top of v1.35.0's Figma Slots write support — create, inspect, populate, and reset Slots (GA at Config 2026) via 5 new tools (`figma_create_slot`, `figma_get_slots`, `figma_append_to_slot`, `figma_reset_slot`, `figma_add_slot_property`), live-validated against the GA Plugin API and based on community PR #77. On top of v1.34.0's Bidirectional Token Sync v2 + DTCG 2025.10 — `figma_import_tokens` applies the complete diff plan (creates missing collections/variables, applies renames, writes real `VARIABLE_ALIAS` references, and deletes only under explicit `replace`), `figma_export_tokens` speaks the DTCG 2025.10 dialect on request (legacy default byte-identical), variable scopes/codeSyntax round-trip via `$extensions`, `figma_setup_design_tokens` accepts alias values via DTCG brace references, and `figma_create_component_set` builds a full variant set from an axes matrix in one call. On top of the v1.33.x line: version-handshake fix (re-import banner only fires when plugin files actually changed), security dependency sweep, and the v1.33.0 connection UX overhaul (honest status pill derived from live connection state, `/health` auto-discovery with self-healing reconnect) + a 33-fix full-codebase audit (lossless DTCG multi-mode round-trips, cross-collection alias resolution, branch-URL correctness across REST tools, cache-poisoning and CSWSH fixes, bridge-first screenshots). Built on WCAG-accurate accessibility auditing (line height below 1.5× is no longer mis-flagged as a failure; readability hints decoupled from conformance checks and scoped to multi-line text; code-side WCAG 1.4.12 check), a self-healing Desktop Bridge connection (zombie-process reaper + auto-reconnect watchdog — fixes the recurring "not connected until restart" bug), native variable binding on fills/strokes + typography control in the write tools, shared-library inspection (key-based component resolution + library variable read/import without Enterprise plan), 10-format token export pipeline (DTCG, CSS, Tailwind v4, Tailwind v3, SCSS, TS module, JSON flat/nested, Style Dictionary v3, Tokens Studio), bidirectional Figma↔code token sync, version history & time-series awareness, FigJam + Slides support, Cloud Write Relay, Design System Kit, WebSocket-only connectivity, smart multi-file tracking, **114 tools** (Local) / **101 tools** (Cloud) / **9 tools** (Remote read-only), Comments API, cross-MCP identity disambiguation, and MCP Apps.
|
|
827
831
|
|
|
828
832
|
**Recent Releases:**
|
|
833
|
+
- [x] **v1.39.1** - Plugin update banner could never be cleared. `computePluginUpdateAvailable()` was a bare inequality with no direction check, so a server whose bundled plugin copy was OLDER than the connected plugin still told the user to re-import — which only ever installs the same or a newer plugin. Not an edge case: the 9223–9232 port range keeps several server instances alive, `BUNDLED_PLUGIN_VERSION` is parsed once at module load, and every server left running from before an upgrade nags a correctly-updated plugin. Reproduced live with four leftover v1.38.2 servers against a freshly re-imported 1.39.0 plugin. Now flags only when the bundled copy is genuinely newer. Server-only, no plugin re-import. 1452 tests.
|
|
834
|
+
- [x] **v1.39.0** - Multi-file execution. New `figma_execute_across_files` runs one script against several Desktop Bridge-connected files concurrently, with per-file error isolation and independent timeouts (verified live: four files × 2s of work in ~3.0s, all dispatches within 5ms — versus ~8s serialized). `figma_execute` gained an optional `fileKey` to target a single non-active file without moving the active file or releasing target lock. Targeting is deliberately explicit — `fileKeys` or `allFiles: true`, no fan-out-to-everything default — because this runs arbitrary code in files you may be actively editing, including one pinned by target lock. The transport was already concurrent (`sendCommand` has always taken a target file key, and every hop is request-id keyed); only the tool layer was missing. Community PR #107 by @Wolfr. Also fixes a Desktop Bridge relay bug that silently dropped `resultAnalysis` and `fileContext` from every `figma_execute` response since they were introduced — making the `resultAnalysis.warning` check the tool's own description tells callers to perform impossible — guarded now by a test that reads the real plugin files. **Re-import `manifest.json`** for those two fields; the rest works without it, and mixed plugin versions degrade cleanly. 52 suites / 1443 tests.
|
|
829
835
|
- [x] **v1.38.2** - Connection stability: the orphan reaper was terminating healthy MCP servers, the cause of recurring "Server disconnected" errors across every MCP client (reproduced in both Claude Code and Claude Desktop; unrelated to the Desktop Bridge plugin). The reaper probes a sibling's `/health` before deciding it is dead, but requested `127.0.0.1` while the WebSocket server binds `localhost` — resolved to the IPv6 loopback on dual-stack macOS, with nothing on IPv4 — so the probe reported "nothing responding" for healthy servers and every kill-safety gate built on it became a rubber stamp, including the one written to spare siblings after the machine sleeps. Three supporting defects: port files written non-atomically (a reader landing mid-rewrite got a parse error that both cleanup paths treated as "corrupt, delete it", stranding a healthy server), an orphan path that terminated fileless port-holders without probing at all, and a heartbeat that gave up permanently once its own file went missing. Fixes: probe `localhost`, atomic temp+rename writes, never delete on a parse failure, health-probe before the orphan kill in both paths, and self-healing re-advertisement guarded by in-process port ownership. **Fully restart MCP clients after upgrading** — older running builds keep the broken probe and still terminate healthy siblings. Server-only, no plugin re-import. 1422 tests (7 new regressions, each verified to fail pre-fix).
|
|
830
836
|
- [x] **v1.38.1** - Shared-library variable tools fixed. `figma_get_library_variables` returned `totalCollections: 0` for every file, on every plan, since it shipped in v1.29.0, and `figma_import_library_variable` reported failed imports as successes with `id: undefined`. Both read the Desktop Bridge's `{ success, result }` envelope as if it were the injected script's bare return value, so `Array.isArray()` was always false, the `__error` guard was dead code, and `.id` was always undefined. The failure presented as a *success* with a plausible hint attached ("subscribe a library via the Assets panel"), which is why it survived two months unreported. Both tools now unwrap through a shared helper that also maps a bridge-level `success: false` onto the error path, so a plugin timeout surfaces as a real error instead of being swallowed as "0 collections"; an import yielding no `id` is now an explicit error. All 26 `executeCodeViaUI` call sites audited — only these two were affected. Test mocks had encoded a wire contract that does not exist, which is why CI stayed green; they now reproduce the real envelope, plus six regression tests verified to fail against the pre-fix source. Reported by Isabella Minzly. Server-only — no plugin re-import needed.
|
|
831
837
|
- [x] **v1.38.0** - Ongoing component changelogs in generated docs. `figma_generate_component_doc` gained an opt-in `history` parameter that produces a real changelog instead of only echoing hand-written `codeInfo.changelog` rows: `history.figma` walks Figma version history and diffs each consecutive pair scoped to the component (reusing the same engine as `figma_diff_versions`, so a rename, a newly added component property, or a token binding each become a row), while `history.git` runs `git log` over the component's source files auto-derived from `codeInfo.filePath` / `sourceFiles[]`. Labeled versions are preferred but auto-saves are used automatically when a file has none — verified against a mature system with 72 auto-saves and 0 labeled versions, where a labeled-only walk yields nothing. Detailed-mode bindings group by property (binding one token across a 24-variant set otherwise produced 44 near-identical bullets in a single table cell). Both sources default off, so existing callers get byte-identical output. No new tools; server-only, no plugin re-import.
|
|
@@ -56,7 +56,18 @@ export class CloudWebSocketConnector {
|
|
|
56
56
|
`;
|
|
57
57
|
return this.sendCommand('EXECUTE_CODE', { code, timeout: 30000 }, 32000);
|
|
58
58
|
}
|
|
59
|
-
async executeCodeViaUI(code, timeoutMs = 5000) {
|
|
59
|
+
async executeCodeViaUI(code, timeoutMs = 5000, fileKey) {
|
|
60
|
+
// fileKey exists for IFigmaConnector parity but cannot be honored here —
|
|
61
|
+
// the cloud relay pairs with exactly one plugin instance, so there is no
|
|
62
|
+
// multi-file target to route between (matches getVariables* above).
|
|
63
|
+
// Reject rather than silently running against the paired file: a caller
|
|
64
|
+
// that asked for file B and got a successful write to file A has no way
|
|
65
|
+
// to tell from the response that it was misrouted.
|
|
66
|
+
if (fileKey) {
|
|
67
|
+
throw new Error('Per-file targeting (fileKey) is Local Mode only. Cloud Mode pairs with a single ' +
|
|
68
|
+
'plugin instance, so there is no second file to route to. Omit fileKey to run ' +
|
|
69
|
+
'against the paired file, or use Local Mode (NPX/Git) for multi-file work.');
|
|
70
|
+
}
|
|
60
71
|
return this.sendCommand('EXECUTE_CODE', { code, timeout: timeoutMs }, timeoutMs + 2000);
|
|
61
72
|
}
|
|
62
73
|
// ============================================================================
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Register tools that operate across every Figma file connected via the
|
|
4
|
+
* Desktop Bridge plugin at once, rather than only the single active file.
|
|
5
|
+
* Local mode only — cloud/relay mode pairs with exactly one plugin instance.
|
|
6
|
+
*/
|
|
7
|
+
export function registerMultiFileTools(server, getWsServer, getDesktopConnector) {
|
|
8
|
+
server.tool("figma_execute_across_files", "Run the same JavaScript against multiple Figma files connected via the Desktop Bridge plugin, IN PARALLEL, without touching the active file or target lock. Built for cross-file consistency work — e.g. running the same structural check or fix against every file in a multi-file design system and diffing the results — instead of switching the active file and running figma_execute once per file in sequence. Each file's code runs in that file's own plugin context (same 'figma' global as figma_execute). You must say which files to target: pass fileKeys (read them from figma_list_open_files first — strongly preferred for anything that writes), or pass allFiles: true to hit every connected file. Requires Desktop Bridge plugin open in each target file. Local Mode only.", {
|
|
9
|
+
code: z
|
|
10
|
+
.string()
|
|
11
|
+
.describe("JavaScript code to execute in each targeted file. Has access to the 'figma' global object, same as figma_execute. Example: 'return { pageCount: figma.root.children.length };'"),
|
|
12
|
+
fileKeys: z
|
|
13
|
+
.array(z.string())
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("Which connected files to target, by fileKey. Get fileKeys from figma_list_open_files. Required unless allFiles is true."),
|
|
16
|
+
allFiles: z
|
|
17
|
+
.boolean()
|
|
18
|
+
.optional()
|
|
19
|
+
.default(false)
|
|
20
|
+
.describe("Run against EVERY currently connected file. Opt-in on purpose: this executes the code in files the user may be actively working in, including any file pinned by target lock. Prefer naming fileKeys explicitly for anything that writes."),
|
|
21
|
+
timeout: z
|
|
22
|
+
.number()
|
|
23
|
+
.optional()
|
|
24
|
+
.default(10000)
|
|
25
|
+
.describe("Per-file execution timeout in milliseconds (default: 10000, max: 30000). Applies independently to each file — one slow/unresponsive file does not delay the others."),
|
|
26
|
+
}, async ({ code, fileKeys, allFiles, timeout }) => {
|
|
27
|
+
try {
|
|
28
|
+
const wsServer = getWsServer();
|
|
29
|
+
if (!wsServer?.isClientConnected()) {
|
|
30
|
+
return {
|
|
31
|
+
content: [{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: JSON.stringify({
|
|
34
|
+
error: "No files connected. Open the Desktop Bridge plugin in Figma to connect files.",
|
|
35
|
+
results: {},
|
|
36
|
+
}),
|
|
37
|
+
}],
|
|
38
|
+
isError: true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const connectedFiles = wsServer.getConnectedFiles();
|
|
42
|
+
const cappedTimeout = Math.min(timeout, 30000);
|
|
43
|
+
// Fanning out to every connected file has to be asked for. This
|
|
44
|
+
// runs arbitrary code in files the user may be actively editing,
|
|
45
|
+
// including one pinned by target lock — the exact misrouting that
|
|
46
|
+
// target lock exists to prevent. "All" is a decision, not a default.
|
|
47
|
+
const hasExplicitTargets = Boolean(fileKeys && fileKeys.length > 0);
|
|
48
|
+
if (!hasExplicitTargets && !allFiles) {
|
|
49
|
+
return {
|
|
50
|
+
content: [{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: JSON.stringify({
|
|
53
|
+
error: "No target files specified. Pass fileKeys to name the files to run against, or allFiles: true to run against every connected file.",
|
|
54
|
+
hint: "Call figma_list_open_files to see connected fileKeys. Naming files explicitly is strongly preferred for code that writes.",
|
|
55
|
+
connectedFiles: connectedFiles.map((f) => ({
|
|
56
|
+
fileKey: f.fileKey,
|
|
57
|
+
fileName: f.fileName,
|
|
58
|
+
isActive: f.isActive,
|
|
59
|
+
})),
|
|
60
|
+
}),
|
|
61
|
+
}],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// A client is only ever registered under a real fileKey (see
|
|
66
|
+
// handleFileInfo), so this filter is belt-and-braces — but an
|
|
67
|
+
// entry without one must never fall through to sendCommand's
|
|
68
|
+
// active-file default, which would silently run the code against
|
|
69
|
+
// the active file instead and report it as a success.
|
|
70
|
+
const targetable = connectedFiles.filter((f) => Boolean(f.fileKey));
|
|
71
|
+
const unidentifiedFiles = connectedFiles
|
|
72
|
+
.filter((f) => !f.fileKey)
|
|
73
|
+
.map((f) => f.fileName);
|
|
74
|
+
let targets = targetable;
|
|
75
|
+
let missingFileKeys = [];
|
|
76
|
+
if (hasExplicitTargets) {
|
|
77
|
+
const connectedKeySet = new Set(targetable.map((f) => f.fileKey));
|
|
78
|
+
missingFileKeys = fileKeys.filter((k) => !connectedKeySet.has(k));
|
|
79
|
+
targets = targetable.filter((f) => fileKeys.includes(f.fileKey));
|
|
80
|
+
}
|
|
81
|
+
if (targets.length === 0) {
|
|
82
|
+
return {
|
|
83
|
+
content: [{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: JSON.stringify({
|
|
86
|
+
error: "No matching connected files to target.",
|
|
87
|
+
requestedFileKeys: fileKeys,
|
|
88
|
+
connectedFileKeys: connectedFiles.map((f) => f.fileKey),
|
|
89
|
+
}),
|
|
90
|
+
}],
|
|
91
|
+
isError: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const connector = await getDesktopConnector();
|
|
95
|
+
const outcomes = await Promise.allSettled(targets.map((file) => connector.executeCodeViaUI(code, cappedTimeout, file.fileKey)));
|
|
96
|
+
const results = {};
|
|
97
|
+
let succeeded = 0;
|
|
98
|
+
let failed = 0;
|
|
99
|
+
outcomes.forEach((outcome, i) => {
|
|
100
|
+
const file = targets[i];
|
|
101
|
+
const key = file.fileKey;
|
|
102
|
+
if (outcome.status === "fulfilled") {
|
|
103
|
+
const result = outcome.value;
|
|
104
|
+
const ok = result?.success !== false;
|
|
105
|
+
if (ok)
|
|
106
|
+
succeeded++;
|
|
107
|
+
else
|
|
108
|
+
failed++;
|
|
109
|
+
results[key] = {
|
|
110
|
+
fileName: file.fileName,
|
|
111
|
+
success: result?.success,
|
|
112
|
+
result: result?.result,
|
|
113
|
+
error: result?.error,
|
|
114
|
+
// Reported by the plugin itself, so the caller can confirm
|
|
115
|
+
// each result came from the file it was addressed to.
|
|
116
|
+
fileContext: result?.fileContext,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
failed++;
|
|
121
|
+
results[key] = {
|
|
122
|
+
fileName: file.fileName,
|
|
123
|
+
success: false,
|
|
124
|
+
error: outcome.reason instanceof Error
|
|
125
|
+
? outcome.reason.message
|
|
126
|
+
: String(outcome.reason),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return {
|
|
131
|
+
content: [{
|
|
132
|
+
type: "text",
|
|
133
|
+
text: JSON.stringify({
|
|
134
|
+
results,
|
|
135
|
+
totalTargeted: targets.length,
|
|
136
|
+
totalSucceeded: succeeded,
|
|
137
|
+
totalFailed: failed,
|
|
138
|
+
missingFileKeys: missingFileKeys.length > 0 ? missingFileKeys : undefined,
|
|
139
|
+
// Connected but unaddressable (no fileKey reported) — skipped
|
|
140
|
+
// rather than silently redirected to the active file.
|
|
141
|
+
skippedUnidentifiedFiles: unidentifiedFiles.length > 0 ? unidentifiedFiles : undefined,
|
|
142
|
+
timestamp: Date.now(),
|
|
143
|
+
}),
|
|
144
|
+
}],
|
|
145
|
+
isError: failed > 0 && succeeded === 0,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return {
|
|
150
|
+
content: [{
|
|
151
|
+
type: "text",
|
|
152
|
+
text: JSON.stringify({
|
|
153
|
+
error: error instanceof Error ? error.message : String(error),
|
|
154
|
+
message: "Failed to execute across files",
|
|
155
|
+
}),
|
|
156
|
+
}],
|
|
157
|
+
isError: true,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
@@ -35,7 +35,7 @@ const logger = createChildLogger({ component: "tokens-tools" });
|
|
|
35
35
|
* on every exported token document. Kept in sync with package.json by
|
|
36
36
|
* scripts/release.sh — see step 3 of the release flow.
|
|
37
37
|
*/
|
|
38
|
-
const MCP_VERSION = "1.
|
|
38
|
+
const MCP_VERSION = "1.39.1";
|
|
39
39
|
const EXPORT_TOOL_DESCRIPTION = `Export Figma variables to design token files in your codebase. Bidirectional with figma_import_tokens — together they replace Style Dictionary and Tokens Studio's export pipeline for the popular styling methods.
|
|
40
40
|
|
|
41
41
|
FULLY-IMPLEMENTED OUTPUT FORMATS:
|
|
@@ -96,8 +96,11 @@ export class WebSocketConnector {
|
|
|
96
96
|
`;
|
|
97
97
|
return this.wsServer.sendCommand('EXECUTE_CODE', { code, timeout: 30000 }, 32000, fileKey);
|
|
98
98
|
}
|
|
99
|
-
async executeCodeViaUI(code, timeoutMs = 5000) {
|
|
100
|
-
|
|
99
|
+
async executeCodeViaUI(code, timeoutMs = 5000, fileKey) {
|
|
100
|
+
// fileKey is optional — when passed, routes to that specific connected
|
|
101
|
+
// client instead of the active file (see sendCommand's targetFileKey),
|
|
102
|
+
// so code can run against a non-active file without switching to it.
|
|
103
|
+
return this.wsServer.sendCommand('EXECUTE_CODE', { code, timeout: timeoutMs }, timeoutMs + 2000, fileKey);
|
|
101
104
|
}
|
|
102
105
|
// ============================================================================
|
|
103
106
|
// Variable operations
|
|
@@ -55,13 +55,54 @@ catch {
|
|
|
55
55
|
export function getBundledPluginVersion() {
|
|
56
56
|
return BUNDLED_PLUGIN_VERSION;
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Compare two `major.minor.patch` strings. Returns <0 when a precedes b, 0 when
|
|
60
|
+
* equal, >0 when a follows b, and null when either side isn't parseable.
|
|
61
|
+
*/
|
|
62
|
+
export function compareSemver(a, b) {
|
|
63
|
+
const parse = (v) => {
|
|
64
|
+
const parts = v.trim().split('.');
|
|
65
|
+
if (parts.length !== 3)
|
|
66
|
+
return null;
|
|
67
|
+
const nums = parts.map((p) => Number(p));
|
|
68
|
+
return nums.every((n) => Number.isInteger(n) && n >= 0) ? nums : null;
|
|
69
|
+
};
|
|
70
|
+
const pa = parse(a);
|
|
71
|
+
const pb = parse(b);
|
|
72
|
+
if (!pa || !pb)
|
|
73
|
+
return null;
|
|
74
|
+
for (let i = 0; i < 3; i++) {
|
|
75
|
+
if (pa[i] !== pb[i])
|
|
76
|
+
return pa[i] - pb[i];
|
|
77
|
+
}
|
|
78
|
+
return 0;
|
|
79
|
+
}
|
|
58
80
|
/**
|
|
59
81
|
* A plugin needs re-importing when it reports no version (predates version
|
|
60
|
-
* reporting) or
|
|
82
|
+
* reporting) or an OLDER version than the plugin files this server ships.
|
|
61
83
|
* The server's own package version is irrelevant here.
|
|
84
|
+
*
|
|
85
|
+
* The direction matters. This used to be a bare `!==`, which also fired when
|
|
86
|
+
* the connected plugin was NEWER than the server's bundled copy — telling the
|
|
87
|
+
* user to re-import, which can only ever install the same or a newer plugin,
|
|
88
|
+
* so the banner could never be cleared. That is not a rare state: the port
|
|
89
|
+
* range means several server instances run at once, and during an upgrade the
|
|
90
|
+
* older ones keep an outdated BUNDLED_PLUGIN_VERSION in memory (it is parsed
|
|
91
|
+
* once at module load) while the freshly re-imported plugin is already current.
|
|
92
|
+
* Every stale server then nags a correctly-updated plugin. Observed live on
|
|
93
|
+
* v1.39.0 with four leftover v1.38.2 servers.
|
|
94
|
+
*
|
|
95
|
+
* An older server has nothing to offer a newer plugin, so it stays quiet.
|
|
62
96
|
*/
|
|
63
97
|
export function computePluginUpdateAvailable(pluginVersion, bundledPluginVersion) {
|
|
64
|
-
|
|
98
|
+
if (!pluginVersion)
|
|
99
|
+
return true;
|
|
100
|
+
const cmp = compareSemver(pluginVersion, bundledPluginVersion);
|
|
101
|
+
// Unparseable on either side — fall back to the conservative inequality so a
|
|
102
|
+
// genuinely odd plugin build still prompts rather than passing silently.
|
|
103
|
+
if (cmp === null)
|
|
104
|
+
return pluginVersion !== bundledPluginVersion;
|
|
105
|
+
return cmp < 0;
|
|
65
106
|
}
|
|
66
107
|
const logger = createChildLogger({ component: 'websocket-server' });
|
|
67
108
|
export class FigmaWebSocketServer extends EventEmitter {
|
|
@@ -25,7 +25,9 @@ When creating: place inside a named Section, positioned BELOW or AWAY from exist
|
|
|
25
25
|
After creating: screenshot to verify clean placement and no overlaps.
|
|
26
26
|
On failure/retry: DELETE any partial artifacts (empty frames, orphaned layers, blank pages) before retrying. Use node.remove() to clean up.
|
|
27
27
|
Pages: NEVER create a new page if one with that name already exists — use the existing one. If you created a blank page during a failed attempt, delete it.
|
|
28
|
-
Layers: If your code creates helper frames, placeholder nodes, or intermediate layers that aren't part of the final result, remove them
|
|
28
|
+
Layers: If your code creates helper frames, placeholder nodes, or intermediate layers that aren't part of the final result, remove them.
|
|
29
|
+
|
|
30
|
+
**MULTI-FILE (Local Mode only):** Pass fileKey to run this in a specific connected file without switching the active file/target lock (see figma_list_open_files). To run the same code across several connected files at once, use figma_execute_across_files instead. Cloud Mode pairs with a single plugin instance and rejects fileKey.`, {
|
|
29
31
|
code: z
|
|
30
32
|
.string()
|
|
31
33
|
.describe("JavaScript code to execute. Has access to the 'figma' global object. " +
|
|
@@ -35,10 +37,14 @@ Layers: If your code creates helper frames, placeholder nodes, or intermediate l
|
|
|
35
37
|
.optional()
|
|
36
38
|
.default(5000)
|
|
37
39
|
.describe("Execution timeout in milliseconds (default: 5000, max: 30000)"),
|
|
38
|
-
|
|
40
|
+
fileKey: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Local Mode only. Run against this specific connected file instead of the active file. Does not change the active file or target lock. Get connected fileKeys from figma_list_open_files. Rejected in Cloud Mode, which pairs with a single plugin instance."),
|
|
44
|
+
}, async ({ code, timeout, fileKey }) => {
|
|
39
45
|
try {
|
|
40
46
|
const connector = await getDesktopConnector();
|
|
41
|
-
const result = await connector.executeCodeViaUI(code, Math.min(timeout, 30000));
|
|
47
|
+
const result = await connector.executeCodeViaUI(code, Math.min(timeout, 30000), fileKey);
|
|
42
48
|
return {
|
|
43
49
|
content: [
|
|
44
50
|
{
|
package/dist/cloudflare/index.js
CHANGED
|
@@ -75,7 +75,7 @@ export class FigmaConsoleMCPv3 extends McpAgent {
|
|
|
75
75
|
this.server = (() => {
|
|
76
76
|
const s = new McpServer({
|
|
77
77
|
name: "Figma Console MCP",
|
|
78
|
-
version: "1.
|
|
78
|
+
version: "1.39.1",
|
|
79
79
|
});
|
|
80
80
|
// Identity wrap — every tool's response and thrown error gets stamped
|
|
81
81
|
// with our MCP name so cross-MCP attribution is unambiguous.
|
|
@@ -1085,7 +1085,7 @@ export default {
|
|
|
1085
1085
|
});
|
|
1086
1086
|
const statelessServer = new McpServer({
|
|
1087
1087
|
name: "Figma Console MCP",
|
|
1088
|
-
version: "1.
|
|
1088
|
+
version: "1.39.1",
|
|
1089
1089
|
});
|
|
1090
1090
|
wrapServerForIdentity(statelessServer);
|
|
1091
1091
|
// ================================================================
|
|
@@ -1723,7 +1723,7 @@ export default {
|
|
|
1723
1723
|
return new Response(JSON.stringify({
|
|
1724
1724
|
status: "healthy",
|
|
1725
1725
|
service: "Figma Console MCP",
|
|
1726
|
-
version: "1.
|
|
1726
|
+
version: "1.39.1",
|
|
1727
1727
|
endpoints: {
|
|
1728
1728
|
mcp: ["/sse", "/mcp"],
|
|
1729
1729
|
oauth_mcp_spec: ["/.well-known/oauth-authorization-server", "/authorize", "/token", "/oauth/register"],
|
|
@@ -1762,13 +1762,13 @@ export default {
|
|
|
1762
1762
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1763
1763
|
<title>Figma Console MCP - The Most Comprehensive MCP Server for Figma</title>
|
|
1764
1764
|
<link rel="icon" type="image/svg+xml" href="https://docs.figma-console-mcp.southleft.com/favicon.svg">
|
|
1765
|
-
<meta name="description" content="Turn your Figma design system into a living API.
|
|
1765
|
+
<meta name="description" content="Turn your Figma design system into a living API. 114+ tools give AI assistants deep access to design tokens, component specs, variables, and programmatic design creation.">
|
|
1766
1766
|
|
|
1767
1767
|
<!-- Open Graph -->
|
|
1768
1768
|
<meta property="og:type" content="website">
|
|
1769
1769
|
<meta property="og:url" content="https://figma-console-mcp.southleft.com">
|
|
1770
1770
|
<meta property="og:title" content="Figma Console MCP - Turn Your Design System Into a Living API">
|
|
1771
|
-
<meta property="og:description" content="The most comprehensive MCP server for Figma.
|
|
1771
|
+
<meta property="og:description" content="The most comprehensive MCP server for Figma. 114+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
|
|
1772
1772
|
<meta property="og:image" content="https://docs.figma-console-mcp.southleft.com/images/og-image.jpg">
|
|
1773
1773
|
<meta property="og:image:width" content="1200">
|
|
1774
1774
|
<meta property="og:image:height" content="630">
|
|
@@ -1776,7 +1776,7 @@ export default {
|
|
|
1776
1776
|
<!-- Twitter -->
|
|
1777
1777
|
<meta name="twitter:card" content="summary_large_image">
|
|
1778
1778
|
<meta name="twitter:title" content="Figma Console MCP - Turn Your Design System Into a Living API">
|
|
1779
|
-
<meta name="twitter:description" content="The most comprehensive MCP server for Figma.
|
|
1779
|
+
<meta name="twitter:description" content="The most comprehensive MCP server for Figma. 114+ tools give AI assistants deep access to design tokens, components, variables, and programmatic design creation.">
|
|
1780
1780
|
<meta name="twitter:image" content="https://docs.figma-console-mcp.southleft.com/images/og-image.jpg">
|
|
1781
1781
|
|
|
1782
1782
|
<meta name="theme-color" content="#0D9488">
|
|
@@ -2663,7 +2663,7 @@ export default {
|
|
|
2663
2663
|
<div class="grid-cell showcase-cell rule-left">
|
|
2664
2664
|
<div class="showcase-label">What AI Can Access</div>
|
|
2665
2665
|
<div class="showcase-stat">
|
|
2666
|
-
<span class="number">
|
|
2666
|
+
<span class="number">114+</span>
|
|
2667
2667
|
<span class="label">MCP tools for Figma</span>
|
|
2668
2668
|
</div>
|
|
2669
2669
|
<div class="capability-list">
|
|
@@ -10,7 +10,7 @@ export interface IFigmaConnector {
|
|
|
10
10
|
executeInPluginContext<T = any>(code: string): Promise<T>;
|
|
11
11
|
getVariablesFromPluginUI(fileKey?: string): Promise<any>;
|
|
12
12
|
getVariables(fileKey?: string): Promise<any>;
|
|
13
|
-
executeCodeViaUI(code: string, timeoutMs?: number): Promise<any>;
|
|
13
|
+
executeCodeViaUI(code: string, timeoutMs?: number, fileKey?: string): Promise<any>;
|
|
14
14
|
updateVariable(variableId: string, modeId: string, value: any): Promise<any>;
|
|
15
15
|
createVariable(name: string, collectionId: string, resolvedType: string, options?: any): Promise<any>;
|
|
16
16
|
deleteVariable(variableId: string): Promise<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figma-connector.d.ts","sourceRoot":"","sources":["../../src/core/figma-connector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAE9B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,gBAAgB,IAAI,WAAW,CAAC;IAGhC,sBAAsB,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1D,wBAAwB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACzD,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"figma-connector.d.ts","sourceRoot":"","sources":["../../src/core/figma-connector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { FigmaWebSocketServer } from "./websocket-server.js";
|
|
3
|
+
/**
|
|
4
|
+
* Register tools that operate across every Figma file connected via the
|
|
5
|
+
* Desktop Bridge plugin at once, rather than only the single active file.
|
|
6
|
+
* Local mode only — cloud/relay mode pairs with exactly one plugin instance.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerMultiFileTools(server: McpServer, getWsServer: () => FigmaWebSocketServer | null, getDesktopConnector: () => Promise<any>): void;
|
|
9
|
+
//# sourceMappingURL=multi-file-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-file-tools.d.ts","sourceRoot":"","sources":["../../src/core/multi-file-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE;;;;GAIG;AACH,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,oBAAoB,GAAG,IAAI,EAC9C,mBAAmB,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,QAsLvC"}
|