@dannote/figma-use 0.1.0 → 0.1.2

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 CHANGED
@@ -4,6 +4,39 @@ Control Figma from the command line. Like [browser-use](https://github.com/brows
4
4
 
5
5
  Built for AI agents to create and manipulate Figma designs programmatically.
6
6
 
7
+ ## Why not the official Figma MCP?
8
+
9
+ The [official Figma MCP server](https://developers.figma.com/docs/figma-mcp-server/) is **read-only** — it can extract design context and take screenshots, but cannot create or modify anything.
10
+
11
+ | Feature | Official MCP | figma-use |
12
+ |---------|-------------|-----------|
13
+ | Read node properties | ✓ | ✓ |
14
+ | Take screenshots | ✓ | ✓ |
15
+ | Extract variables/styles | ✓ | ✓ |
16
+ | **Create shapes** | ✗ | ✓ |
17
+ | **Create text** | ✗ | ✓ |
18
+ | **Create frames & components** | ✗ | ✓ |
19
+ | **Modify properties** | ✗ | ✓ |
20
+ | **Set fills, strokes, effects** | ✗ | ✓ |
21
+ | **Auto-layout** | ✗ | ✓ |
22
+ | **Execute arbitrary code** | ✗ | ✓ |
23
+
24
+ figma-use gives AI agents full control over Figma — not just reading, but **creating and editing** designs.
25
+
26
+ ## How it works
27
+
28
+ ```
29
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
30
+ │ │ │ │ │ │
31
+ │ AI Agent / │────▶│ figma-use │────▶│ Figma │
32
+ │ CLI │ HTTP│ proxy │ WS │ Plugin │
33
+ │ │◀────│ :38451 │◀────│ │
34
+ │ │ │ │ │ │
35
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
36
+ ```
37
+
38
+ The CLI sends commands to a local proxy server, which forwards them via WebSocket to a Figma plugin. The plugin executes commands using the Figma API and returns results.
39
+
7
40
  ## Installation
8
41
 
9
42
  ```bash
@@ -18,39 +51,44 @@ bun install -g @dannote/figma-use
18
51
  figma-use proxy
19
52
  ```
20
53
 
21
- ### 2. Load the Figma plugin
54
+ ### 2. Install the Figma plugin
22
55
 
23
- Open Figma, go to **Plugins → Development → Import plugin from manifest**, and select:
56
+ ```bash
57
+ # Quit Figma first, then:
58
+ figma-use plugin
24
59
 
25
- ```
26
- ~/.bun/install/global/node_modules/@dannote/figma-use/packages/plugin/dist/manifest.json
27
- ```
60
+ # Or force install while Figma is running (restart required):
61
+ figma-use plugin --force
28
62
 
29
- Or find it with:
63
+ # Show plugin path only:
64
+ figma-use plugin --path
30
65
 
31
- ```bash
32
- figma-use plugin
66
+ # Uninstall:
67
+ figma-use plugin --uninstall
33
68
  ```
34
69
 
70
+ Start Figma and find the plugin in **Plugins → Development → Figma Use**.
71
+
35
72
  ### 3. Run commands
36
73
 
37
74
  ```bash
38
- # Create shapes
39
- figma-use create-rectangle --x 0 --y 0 --width 200 --height 100 --fill "#3B82F6" --radius 8
40
-
41
- # Create text
42
- figma-use create-text --x 50 --y 40 --text "Hello Figma" --fontSize 24 --fill "#FFFFFF"
75
+ # Create a styled button in one command (fill + stroke + radius + layout)
76
+ figma-use create-frame --x 0 --y 0 --width 200 --height 48 \
77
+ --fill "#3B82F6" --stroke "#1D4ED8" --radius 8 \
78
+ --layoutMode HORIZONTAL --itemSpacing 8 --padding "12,24,12,24" \
79
+ --name "Button"
43
80
 
44
- # Get node info
45
- figma-use get-node --id "1:2"
81
+ # Add text with font styling
82
+ figma-use create-text --x 0 --y 0 --text "Click me" \
83
+ --fontSize 16 --fontFamily "Inter" --fontStyle "Medium" --fill "#FFFFFF" \
84
+ --parentId "1:23"
46
85
 
47
86
  # Export to PNG
48
- figma-use export-node --id "1:2" --format PNG --scale 2 --output design.png
49
-
50
- # Take screenshot
51
- figma-use screenshot --output viewport.png
87
+ figma-use export-node --id "1:23" --format PNG --scale 2 --output button.png
52
88
  ```
53
89
 
90
+ All create commands support inline styling — no need for separate `set-*` calls.
91
+
54
92
  ## Output Format
55
93
 
56
94
  Human-readable by default:
@@ -171,6 +209,30 @@ $ figma-use get-node --id "1:2" --json
171
209
  | `zoom-to-fit` | Zoom to fit nodes |
172
210
  | `set-viewport` | Set viewport position and zoom |
173
211
 
212
+ ### Advanced
213
+
214
+ | Command | Description |
215
+ |---------|-------------|
216
+ | `eval` | Execute arbitrary JavaScript in Figma |
217
+
218
+ #### eval
219
+
220
+ Run any JavaScript code in the Figma plugin context:
221
+
222
+ ```bash
223
+ # Simple expression
224
+ figma-use eval "return 2 + 2"
225
+
226
+ # Access Figma API
227
+ figma-use eval "return figma.currentPage.name"
228
+
229
+ # Create nodes
230
+ figma-use eval "const r = figma.createRectangle(); r.resize(100, 100); return r.id"
231
+
232
+ # Async code (top-level await supported)
233
+ figma-use eval "const node = await figma.getNodeByIdAsync('1:2'); return node.name"
234
+ ```
235
+
174
236
  ## Environment Variables
175
237
 
176
238
  | Variable | Default | Description |
@@ -180,39 +242,26 @@ $ figma-use get-node --id "1:2" --json
180
242
 
181
243
  ## For AI Agents
182
244
 
183
- figma-use is designed for AI agents. Example with Claude:
184
-
185
- ```python
186
- import anthropic
187
- import subprocess
188
-
189
- def figma(cmd):
190
- result = subprocess.run(
191
- f"figma-use {cmd} --json",
192
- shell=True, capture_output=True, text=True
193
- )
194
- return result.stdout
195
-
196
- client = anthropic.Anthropic()
197
-
198
- response = client.messages.create(
199
- model="claude-sonnet-4-20250514",
200
- messages=[{
201
- "role": "user",
202
- "content": "Create a blue button with white text 'Click me'"
203
- }],
204
- tools=[{
205
- "name": "figma",
206
- "description": "Run figma-use CLI command",
207
- "input_schema": {
208
- "type": "object",
209
- "properties": {
210
- "command": {"type": "string"}
211
- }
212
- }
213
- }]
214
- )
245
+ figma-use is designed to work with AI coding agents like [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Cursor](https://cursor.sh), or any agent that can execute shell commands.
246
+
247
+ ### Using with Claude Code
248
+
249
+ Add the [web-to-figma skill](https://github.com/anthropics/claude-code/tree/main/skills) to your agent:
250
+
251
+ ```bash
252
+ # The skill teaches the agent how to:
253
+ # - Extract styles from web pages
254
+ # - Recreate UI components in Figma
255
+ # - Match colors, fonts, spacing, and layout
256
+ ```
257
+
258
+ Then just ask:
259
+
215
260
  ```
261
+ Recreate this login form in Figma: https://example.com/login
262
+ ```
263
+
264
+ The agent will use `figma-use` commands to build the design.
216
265
 
217
266
  ## License
218
267
 
package/bin/figma-use.js CHANGED
@@ -4,18 +4,7 @@ import { fileURLToPath } from 'url'
4
4
  import { dirname, join } from 'path'
5
5
 
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url))
7
- const args = process.argv.slice(2)
7
+ const cliPath = join(__dirname, '..', 'dist', 'cli', 'index.js')
8
8
 
9
- // If first arg is 'proxy' or 'plugin', handle specially
10
- if (args[0] === 'proxy') {
11
- const proxyPath = join(__dirname, '..', 'dist', 'proxy', 'index.js')
12
- spawn('bun', ['run', proxyPath], { stdio: 'inherit' })
13
- } else if (args[0] === 'plugin') {
14
- const pluginPath = join(__dirname, '..', 'packages', 'plugin', 'dist')
15
- console.log(`Plugin files at: ${pluginPath}`)
16
- console.log('Import manifest.json into Figma via Plugins > Development > Import plugin from manifest')
17
- } else {
18
- // CLI command
19
- const cliPath = join(__dirname, '..', 'dist', 'cli', 'index.js')
20
- spawn('bun', ['run', cliPath, ...args], { stdio: 'inherit' })
21
- }
9
+ const child = spawn('bun', ['run', cliPath, ...process.argv.slice(2)], { stdio: 'inherit' })
10
+ child.on('exit', (code) => process.exit(code || 0))
package/dist/cli/index.js CHANGED
@@ -27,6 +27,7 @@ var __export = (target, all) => {
27
27
  });
28
28
  };
29
29
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
30
+ var __require = import.meta.require;
30
31
 
31
32
  // node_modules/.bun/consola@3.4.2/node_modules/consola/dist/chunks/prompt.mjs
32
33
  var exports_prompt = {};
@@ -2450,6 +2451,8 @@ __export(exports_commands, {
2450
2451
  screenshot: () => screenshot_default,
2451
2452
  "resize-node": () => resize_node_default,
2452
2453
  "rename-node": () => rename_node_default,
2454
+ proxy: () => proxy_default,
2455
+ plugin: () => plugin_default,
2453
2456
  "move-node": () => move_node_default,
2454
2457
  "intersect-nodes": () => intersect_nodes_default,
2455
2458
  "import-svg": () => import_svg_default,
@@ -2466,6 +2469,7 @@ __export(exports_commands, {
2466
2469
  "export-selection": () => export_selection_default,
2467
2470
  "export-node": () => export_node_default,
2468
2471
  "exclude-nodes": () => exclude_nodes_default,
2472
+ eval: () => eval_default,
2469
2473
  "edit-component-property": () => edit_component_property_default,
2470
2474
  "delete-node": () => delete_node_default,
2471
2475
  "delete-component-property": () => delete_component_property_default,
@@ -2489,6 +2493,249 @@ __export(exports_commands, {
2489
2493
  "add-component-property": () => add_component_property_default
2490
2494
  });
2491
2495
 
2496
+ // packages/cli/src/commands/proxy.ts
2497
+ import { spawn } from "child_process";
2498
+ import { resolve, dirname } from "path";
2499
+ function getPackageRoot() {
2500
+ const currentFile = import.meta.path || import.meta.url.replace("file://", "");
2501
+ let dir = dirname(currentFile);
2502
+ for (let i2 = 0;i2 < 10; i2++) {
2503
+ try {
2504
+ const pkg = __require(resolve(dir, "package.json"));
2505
+ if (pkg.name === "@dannote/figma-use") {
2506
+ return dir;
2507
+ }
2508
+ } catch {}
2509
+ dir = dirname(dir);
2510
+ }
2511
+ return dirname(dirname(dirname(currentFile)));
2512
+ }
2513
+ var proxy_default = defineCommand({
2514
+ meta: { description: "Start the WebSocket proxy server" },
2515
+ args: {
2516
+ port: { type: "string", description: "Port to listen on", default: "38451" }
2517
+ },
2518
+ run({ args }) {
2519
+ process.env.PORT = args.port;
2520
+ const root = getPackageRoot();
2521
+ const proxyPath = resolve(root, "dist", "proxy", "index.js");
2522
+ const child = spawn("bun", ["run", proxyPath], { stdio: "inherit" });
2523
+ child.on("exit", (code) => process.exit(code || 0));
2524
+ }
2525
+ });
2526
+ // packages/cli/src/commands/plugin.ts
2527
+ import { resolve as resolve2, dirname as dirname2, join } from "path";
2528
+ import { readFileSync, writeFileSync, existsSync } from "fs";
2529
+ import { execSync } from "child_process";
2530
+ function getPackageRoot2() {
2531
+ const currentFile = import.meta.path || import.meta.url.replace("file://", "");
2532
+ let dir = dirname2(currentFile);
2533
+ for (let i2 = 0;i2 < 10; i2++) {
2534
+ try {
2535
+ const pkg = __require(resolve2(dir, "package.json"));
2536
+ if (pkg.name === "@dannote/figma-use") {
2537
+ return dir;
2538
+ }
2539
+ } catch {}
2540
+ dir = dirname2(dir);
2541
+ }
2542
+ return dirname2(dirname2(dirname2(currentFile)));
2543
+ }
2544
+ function getFigmaSettingsPath() {
2545
+ const home = process.env.HOME || process.env.USERPROFILE || "";
2546
+ if (process.platform === "darwin") {
2547
+ return join(home, "Library", "Application Support", "Figma", "settings.json");
2548
+ } else if (process.platform === "win32") {
2549
+ const appData = process.env.APPDATA || join(home, "AppData", "Roaming");
2550
+ return join(appData, "Figma", "settings.json");
2551
+ } else {
2552
+ return join(home, ".config", "Figma", "settings.json");
2553
+ }
2554
+ }
2555
+ function isFigmaRunning() {
2556
+ try {
2557
+ if (process.platform === "darwin") {
2558
+ execSync("pgrep -x Figma", { stdio: "pipe" });
2559
+ return true;
2560
+ } else if (process.platform === "win32") {
2561
+ execSync('tasklist /FI "IMAGENAME eq Figma.exe" | find "Figma.exe"', { stdio: "pipe" });
2562
+ return true;
2563
+ } else {
2564
+ execSync("pgrep -x figma", { stdio: "pipe" });
2565
+ return true;
2566
+ }
2567
+ } catch {
2568
+ return false;
2569
+ }
2570
+ }
2571
+ function getNextId(extensions) {
2572
+ if (!extensions || extensions.length === 0)
2573
+ return 1;
2574
+ return Math.max(...extensions.map((e2) => e2.id)) + 1;
2575
+ }
2576
+ function installPlugin(manifestPath) {
2577
+ const settingsPath = getFigmaSettingsPath();
2578
+ if (!settingsPath || !existsSync(settingsPath)) {
2579
+ return {
2580
+ success: false,
2581
+ message: "Figma settings not found. Please install Figma Desktop first."
2582
+ };
2583
+ }
2584
+ if (isFigmaRunning()) {
2585
+ return {
2586
+ success: false,
2587
+ message: "Figma is running. Please quit Figma first, then run this command again."
2588
+ };
2589
+ }
2590
+ try {
2591
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
2592
+ const extensions = settings.localFileExtensions || [];
2593
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
2594
+ const pluginId = manifest.id || "figma-use-plugin";
2595
+ const existing = extensions.find((e2) => e2.lastKnownPluginId === pluginId && e2.fileMetadata?.type === "manifest");
2596
+ if (existing) {
2597
+ if (existing.manifestPath !== manifestPath) {
2598
+ existing.manifestPath = manifestPath;
2599
+ const pluginDir2 = dirname2(manifestPath);
2600
+ for (const ext of extensions) {
2601
+ if (ext.fileMetadata?.manifestFileId === existing.id) {
2602
+ if (ext.fileMetadata.type === "code") {
2603
+ ext.manifestPath = join(pluginDir2, manifest.main || "main.js");
2604
+ } else if (ext.fileMetadata.type === "ui") {
2605
+ ext.manifestPath = join(pluginDir2, manifest.ui || "ui.html");
2606
+ }
2607
+ }
2608
+ }
2609
+ settings.localFileExtensions = extensions;
2610
+ writeFileSync(settingsPath, JSON.stringify(settings));
2611
+ return { success: true, message: "Plugin path updated" };
2612
+ }
2613
+ return { success: true, message: "Plugin already installed" };
2614
+ }
2615
+ const pluginDir = dirname2(manifestPath);
2616
+ const manifestId = getNextId(extensions);
2617
+ const codeId = manifestId + 1;
2618
+ const uiId = manifestId + 2;
2619
+ extensions.push({
2620
+ id: manifestId,
2621
+ manifestPath,
2622
+ lastKnownName: manifest.name || "Figma Use",
2623
+ lastKnownPluginId: pluginId,
2624
+ fileMetadata: {
2625
+ type: "manifest",
2626
+ codeFileId: codeId,
2627
+ uiFileIds: [uiId]
2628
+ },
2629
+ cachedContainsWidget: false
2630
+ });
2631
+ extensions.push({
2632
+ id: codeId,
2633
+ manifestPath: join(pluginDir, manifest.main || "main.js"),
2634
+ fileMetadata: {
2635
+ type: "code",
2636
+ manifestFileId: manifestId
2637
+ }
2638
+ });
2639
+ extensions.push({
2640
+ id: uiId,
2641
+ manifestPath: join(pluginDir, manifest.ui || "ui.html"),
2642
+ fileMetadata: {
2643
+ type: "ui",
2644
+ manifestFileId: manifestId
2645
+ }
2646
+ });
2647
+ settings.localFileExtensions = extensions;
2648
+ writeFileSync(settingsPath, JSON.stringify(settings));
2649
+ return { success: true, message: "Plugin installed successfully" };
2650
+ } catch (error) {
2651
+ return {
2652
+ success: false,
2653
+ message: `Failed to install: ${error instanceof Error ? error.message : error}`
2654
+ };
2655
+ }
2656
+ }
2657
+ function uninstallPlugin(manifestPath) {
2658
+ const settingsPath = getFigmaSettingsPath();
2659
+ if (!settingsPath || !existsSync(settingsPath)) {
2660
+ return { success: false, message: "Figma settings not found" };
2661
+ }
2662
+ if (isFigmaRunning()) {
2663
+ return {
2664
+ success: false,
2665
+ message: "Figma is running. Please quit Figma first."
2666
+ };
2667
+ }
2668
+ try {
2669
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
2670
+ const extensions = settings.localFileExtensions || [];
2671
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
2672
+ const pluginId = manifest.id || "figma-use-plugin";
2673
+ const manifestEntry = extensions.find((e2) => e2.lastKnownPluginId === pluginId && e2.fileMetadata?.type === "manifest");
2674
+ if (!manifestEntry) {
2675
+ return { success: true, message: "Plugin not installed" };
2676
+ }
2677
+ const manifestId = manifestEntry.id;
2678
+ settings.localFileExtensions = extensions.filter((e2) => e2.id !== manifestId && e2.fileMetadata?.manifestFileId !== manifestId);
2679
+ writeFileSync(settingsPath, JSON.stringify(settings));
2680
+ return { success: true, message: "Plugin uninstalled successfully" };
2681
+ } catch (error) {
2682
+ return {
2683
+ success: false,
2684
+ message: `Failed to uninstall: ${error instanceof Error ? error.message : error}`
2685
+ };
2686
+ }
2687
+ }
2688
+ var plugin_default = defineCommand({
2689
+ meta: { description: "Install/uninstall Figma plugin" },
2690
+ args: {
2691
+ uninstall: { type: "boolean", description: "Uninstall the plugin" },
2692
+ path: { type: "boolean", description: "Show plugin path only" },
2693
+ force: { type: "boolean", description: "Force install even if Figma is running (not recommended)" }
2694
+ },
2695
+ async run({ args }) {
2696
+ const root = getPackageRoot2();
2697
+ const pluginPath = resolve2(root, "packages", "plugin", "dist", "manifest.json");
2698
+ if (args.path) {
2699
+ console.log(pluginPath);
2700
+ return;
2701
+ }
2702
+ if (args.uninstall) {
2703
+ const result2 = uninstallPlugin(pluginPath);
2704
+ if (result2.success) {
2705
+ consola.success(result2.message);
2706
+ } else {
2707
+ consola.error(result2.message);
2708
+ }
2709
+ return;
2710
+ }
2711
+ if (!args.force && isFigmaRunning()) {
2712
+ consola.error("Figma is running");
2713
+ consola.info("Please quit Figma, then run: figma-use plugin");
2714
+ consola.info("Or use --force to install anyway (changes will apply on restart)");
2715
+ return;
2716
+ }
2717
+ const result = installPlugin(pluginPath);
2718
+ if (result.success) {
2719
+ consola.success(result.message);
2720
+ if (result.message !== "Plugin already installed") {
2721
+ consola.box(`Next steps:
2722
+
2723
+ 1. Start Figma
2724
+ 2. Open any Figma file
2725
+ 3. Run: figma-use proxy
2726
+ 4. In Figma: Plugins \u2192 Development \u2192 Figma Use`);
2727
+ }
2728
+ } else {
2729
+ consola.error(result.message);
2730
+ consola.box({
2731
+ title: "Manual Installation",
2732
+ message: `1. Open Figma Desktop
2733
+ 2. Go to: Plugins \u2192 Development \u2192 Import plugin from manifest
2734
+ 3. Select: ${pluginPath}`
2735
+ });
2736
+ }
2737
+ }
2738
+ });
2492
2739
  // packages/cli/src/client.ts
2493
2740
  init_output();
2494
2741
  var PROXY_URL = process.env.FIGMA_PROXY_URL || "http://localhost:38451";
@@ -2514,6 +2761,19 @@ function handleError(error) {
2514
2761
  process.exit(1);
2515
2762
  }
2516
2763
 
2764
+ // packages/cli/src/commands/eval.ts
2765
+ init_output();
2766
+ var eval_default = defineCommand({
2767
+ meta: { description: "Execute arbitrary code in Figma plugin context" },
2768
+ args: {
2769
+ code: { type: "positional", description: "JavaScript code to execute", required: true },
2770
+ json: { type: "boolean", description: "Output raw JSON" }
2771
+ },
2772
+ async run({ args }) {
2773
+ const result = await sendCommand("eval", { code: args.code });
2774
+ printResult(result, args.json);
2775
+ }
2776
+ });
2517
2777
  // packages/cli/src/commands/status.ts
2518
2778
  var status_default = defineCommand({
2519
2779
  meta: { description: "Check if plugin is connected" },
@@ -3627,7 +3887,7 @@ var zoom_to_fit_default = defineCommand({
3627
3887
  }
3628
3888
  });
3629
3889
  // packages/cli/src/commands/export-node.ts
3630
- import { writeFileSync } from "fs";
3890
+ import { writeFileSync as writeFileSync2 } from "fs";
3631
3891
  var export_node_default = defineCommand({
3632
3892
  meta: { description: "Export node as image" },
3633
3893
  args: {
@@ -3646,7 +3906,7 @@ var export_node_default = defineCommand({
3646
3906
  });
3647
3907
  if (args.output) {
3648
3908
  const buffer = Buffer.from(result.data, "base64");
3649
- writeFileSync(args.output, buffer);
3909
+ writeFileSync2(args.output, buffer);
3650
3910
  console.log(`Exported to ${args.output}`);
3651
3911
  } else {
3652
3912
  console.log(JSON.stringify(result, null, 2));
@@ -3673,7 +3933,7 @@ var delete_node_default = defineCommand({
3673
3933
  }
3674
3934
  });
3675
3935
  // packages/cli/src/commands/screenshot.ts
3676
- import { writeFileSync as writeFileSync2 } from "fs";
3936
+ import { writeFileSync as writeFileSync3 } from "fs";
3677
3937
  var screenshot_default = defineCommand({
3678
3938
  meta: { description: "Take a screenshot of current viewport" },
3679
3939
  args: {
@@ -3687,7 +3947,7 @@ var screenshot_default = defineCommand({
3687
3947
  scale: Number(args.scale)
3688
3948
  });
3689
3949
  const buffer = Buffer.from(result.data, "base64");
3690
- writeFileSync2(args.output, buffer);
3950
+ writeFileSync3(args.output, buffer);
3691
3951
  console.log(args.output);
3692
3952
  } catch (e2) {
3693
3953
  handleError(e2);
@@ -3695,7 +3955,7 @@ var screenshot_default = defineCommand({
3695
3955
  }
3696
3956
  });
3697
3957
  // packages/cli/src/commands/export-selection.ts
3698
- import { writeFileSync as writeFileSync3 } from "fs";
3958
+ import { writeFileSync as writeFileSync4 } from "fs";
3699
3959
  var export_selection_default = defineCommand({
3700
3960
  meta: { description: "Export current selection as image" },
3701
3961
  args: {
@@ -3713,7 +3973,7 @@ var export_selection_default = defineCommand({
3713
3973
  padding: Number(args.padding)
3714
3974
  });
3715
3975
  const buffer = Buffer.from(result.data, "base64");
3716
- writeFileSync3(args.output, buffer);
3976
+ writeFileSync4(args.output, buffer);
3717
3977
  console.log(args.output);
3718
3978
  } catch (e2) {
3719
3979
  handleError(e2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dannote/figma-use",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Control Figma from the command line. Like browser-use, but for Figma.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -46,14 +46,8 @@
46
46
  "elysia": "^1.2.25"
47
47
  },
48
48
  "devDependencies": {
49
- "@anthropic-ai/sdk": "^0.52.0",
50
- "@anthropic-ai/tokenizer": "^0.0.4",
51
49
  "@types/bun": "^1.3.6",
52
50
  "esbuild": "^0.25.4",
53
51
  "typescript": "^5.8.3"
54
- },
55
- "engines": {
56
- "node": ">=18",
57
- "bun": ">=1.0"
58
52
  }
59
53
  }
@@ -877,6 +877,17 @@
877
877
  node.remove();
878
878
  return { deleted: true };
879
879
  }
880
+ // ==================== EVAL ====================
881
+ case "eval": {
882
+ const { code } = args;
883
+ const AsyncFunction = Object.getPrototypeOf(function() {
884
+ return __async(this, null, function* () {
885
+ });
886
+ }).constructor;
887
+ const wrappedCode = code.trim().startsWith("return") ? code : `return (async () => { ${code} })()`;
888
+ const fn = new AsyncFunction("figma", wrappedCode);
889
+ return yield fn(figma);
890
+ }
880
891
  default:
881
892
  throw new Error(`Unknown command: ${command}`);
882
893
  }