faux-studio 0.4.4 → 0.4.7
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/index.js +194 -40
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -10447,6 +10447,7 @@ function error(message) {
|
|
|
10447
10447
|
|
|
10448
10448
|
// src/credential-store.ts
|
|
10449
10449
|
import { readFile, writeFile, mkdir, unlink } from "fs/promises";
|
|
10450
|
+
import { execFile } from "child_process";
|
|
10450
10451
|
import { join } from "path";
|
|
10451
10452
|
import { homedir } from "os";
|
|
10452
10453
|
var FAUX_DIR = join(homedir(), ".faux");
|
|
@@ -10480,43 +10481,99 @@ var FileCredentialStore = class {
|
|
|
10480
10481
|
}
|
|
10481
10482
|
}
|
|
10482
10483
|
};
|
|
10483
|
-
|
|
10484
|
+
function securityExec(...args) {
|
|
10485
|
+
return new Promise((resolve, reject) => {
|
|
10486
|
+
execFile("/usr/bin/security", args, { timeout: 1e4 }, (err, stdout, stderr) => {
|
|
10487
|
+
if (err) return reject(err);
|
|
10488
|
+
resolve({ stdout, stderr });
|
|
10489
|
+
});
|
|
10490
|
+
});
|
|
10491
|
+
}
|
|
10492
|
+
var SecurityCliKeychainStore = class {
|
|
10484
10493
|
name = "keychain";
|
|
10485
|
-
|
|
10486
|
-
constructor(entry) {
|
|
10487
|
-
this.entry = entry;
|
|
10488
|
-
}
|
|
10494
|
+
cached = void 0;
|
|
10489
10495
|
async load() {
|
|
10496
|
+
if (this.cached !== void 0) return this.cached;
|
|
10490
10497
|
try {
|
|
10491
|
-
const
|
|
10492
|
-
|
|
10498
|
+
const { stdout } = await securityExec(
|
|
10499
|
+
"find-generic-password",
|
|
10500
|
+
"-s",
|
|
10501
|
+
KEYCHAIN_SERVICE,
|
|
10502
|
+
"-a",
|
|
10503
|
+
KEYCHAIN_ACCOUNT,
|
|
10504
|
+
"-w"
|
|
10505
|
+
);
|
|
10506
|
+
const raw = stdout.trim();
|
|
10507
|
+
if (!raw) {
|
|
10508
|
+
this.cached = null;
|
|
10509
|
+
return null;
|
|
10510
|
+
}
|
|
10493
10511
|
const creds = JSON.parse(raw);
|
|
10494
|
-
if (!creds.jwt || !creds.refreshToken || !creds.user)
|
|
10512
|
+
if (!creds.jwt || !creds.refreshToken || !creds.user) {
|
|
10513
|
+
this.cached = null;
|
|
10514
|
+
return null;
|
|
10515
|
+
}
|
|
10516
|
+
this.cached = creds;
|
|
10495
10517
|
return creds;
|
|
10496
10518
|
} catch {
|
|
10519
|
+
this.cached = null;
|
|
10497
10520
|
return null;
|
|
10498
10521
|
}
|
|
10499
10522
|
}
|
|
10500
10523
|
async save(creds) {
|
|
10524
|
+
const value = JSON.stringify(creds);
|
|
10525
|
+
try {
|
|
10526
|
+
await securityExec(
|
|
10527
|
+
"delete-generic-password",
|
|
10528
|
+
"-s",
|
|
10529
|
+
KEYCHAIN_SERVICE,
|
|
10530
|
+
"-a",
|
|
10531
|
+
KEYCHAIN_ACCOUNT
|
|
10532
|
+
);
|
|
10533
|
+
} catch {
|
|
10534
|
+
}
|
|
10501
10535
|
try {
|
|
10502
|
-
await
|
|
10536
|
+
await securityExec(
|
|
10537
|
+
"add-generic-password",
|
|
10538
|
+
"-s",
|
|
10539
|
+
KEYCHAIN_SERVICE,
|
|
10540
|
+
"-a",
|
|
10541
|
+
KEYCHAIN_ACCOUNT,
|
|
10542
|
+
"-w",
|
|
10543
|
+
value,
|
|
10544
|
+
"-A",
|
|
10545
|
+
"-U"
|
|
10546
|
+
);
|
|
10547
|
+
this.cached = creds;
|
|
10503
10548
|
} catch (err) {
|
|
10504
10549
|
warn(`Could not save to keychain: ${err instanceof Error ? err.message : err}`);
|
|
10505
10550
|
}
|
|
10506
10551
|
}
|
|
10507
10552
|
async clear() {
|
|
10508
10553
|
try {
|
|
10509
|
-
await
|
|
10554
|
+
await securityExec(
|
|
10555
|
+
"delete-generic-password",
|
|
10556
|
+
"-s",
|
|
10557
|
+
KEYCHAIN_SERVICE,
|
|
10558
|
+
"-a",
|
|
10559
|
+
KEYCHAIN_ACCOUNT
|
|
10560
|
+
);
|
|
10561
|
+
this.cached = null;
|
|
10510
10562
|
} catch {
|
|
10511
10563
|
}
|
|
10512
10564
|
}
|
|
10513
10565
|
};
|
|
10514
10566
|
async function tryCreateKeychainStore() {
|
|
10567
|
+
if (process.platform !== "darwin") {
|
|
10568
|
+
log("[keychain] not macOS \u2014 skipping keychain");
|
|
10569
|
+
return null;
|
|
10570
|
+
}
|
|
10515
10571
|
try {
|
|
10516
|
-
|
|
10517
|
-
const
|
|
10518
|
-
await
|
|
10519
|
-
|
|
10572
|
+
log("[keychain] probing macOS security CLI...");
|
|
10573
|
+
const t0 = Date.now();
|
|
10574
|
+
await securityExec("help");
|
|
10575
|
+
log(`[keychain] security CLI available (${Date.now() - t0}ms)`);
|
|
10576
|
+
return new SecurityCliKeychainStore();
|
|
10520
10577
|
} catch (err) {
|
|
10521
10578
|
warn(
|
|
10522
10579
|
`OS keychain not available, using file-based credential storage: ${err instanceof Error ? err.message : err}`
|
|
@@ -10532,9 +10589,12 @@ function createCredentialStore() {
|
|
|
10532
10589
|
return initPromise;
|
|
10533
10590
|
}
|
|
10534
10591
|
async function initStore() {
|
|
10592
|
+
log("[credential-store] initializing...");
|
|
10593
|
+
const t0 = Date.now();
|
|
10535
10594
|
const fileStore = new FileCredentialStore();
|
|
10536
10595
|
const keychainStore = await tryCreateKeychainStore();
|
|
10537
10596
|
if (!keychainStore) {
|
|
10597
|
+
log(`[credential-store] using file store (${Date.now() - t0}ms)`);
|
|
10538
10598
|
return fileStore;
|
|
10539
10599
|
}
|
|
10540
10600
|
const keychainCreds = await keychainStore.load();
|
|
@@ -10542,6 +10602,7 @@ async function initStore() {
|
|
|
10542
10602
|
const fileCreds = await fileStore.load();
|
|
10543
10603
|
if (fileCreds) {
|
|
10544
10604
|
await keychainStore.save(fileCreds);
|
|
10605
|
+
keychainStore["cached"] = void 0;
|
|
10545
10606
|
const verified = await keychainStore.load();
|
|
10546
10607
|
if (verified) {
|
|
10547
10608
|
await fileStore.clear();
|
|
@@ -10552,6 +10613,7 @@ async function initStore() {
|
|
|
10552
10613
|
}
|
|
10553
10614
|
}
|
|
10554
10615
|
}
|
|
10616
|
+
log(`[credential-store] using keychain store (${Date.now() - t0}ms)`);
|
|
10555
10617
|
return keychainStore;
|
|
10556
10618
|
}
|
|
10557
10619
|
|
|
@@ -10648,6 +10710,8 @@ async function authenticate() {
|
|
|
10648
10710
|
);
|
|
10649
10711
|
}
|
|
10650
10712
|
async function ensureAuth() {
|
|
10713
|
+
log("[auth] ensureAuth() started");
|
|
10714
|
+
const t0 = Date.now();
|
|
10651
10715
|
const apiKey = process.env.FAUX_API_KEY;
|
|
10652
10716
|
if (apiKey) {
|
|
10653
10717
|
log("Using FAUX_API_KEY from environment");
|
|
@@ -10658,7 +10722,9 @@ async function ensureAuth() {
|
|
|
10658
10722
|
source: "api-key"
|
|
10659
10723
|
};
|
|
10660
10724
|
}
|
|
10725
|
+
log("[auth] creating credential store...");
|
|
10661
10726
|
const credStore = await createCredentialStore();
|
|
10727
|
+
log(`[auth] credential store ready (${credStore.name}) in ${Date.now() - t0}ms`);
|
|
10662
10728
|
const saved = await credStore.load();
|
|
10663
10729
|
if (saved) {
|
|
10664
10730
|
if (!isExpiringSoon(saved)) {
|
|
@@ -11215,6 +11281,31 @@ async function probeCdpPorts() {
|
|
|
11215
11281
|
}
|
|
11216
11282
|
return null;
|
|
11217
11283
|
}
|
|
11284
|
+
async function launchFigmaWithCdp() {
|
|
11285
|
+
const figmaPath = findFigmaPath();
|
|
11286
|
+
if (!figmaPath) {
|
|
11287
|
+
throw new Error(
|
|
11288
|
+
"Figma Desktop is not installed. Download from https://figma.com/downloads"
|
|
11289
|
+
);
|
|
11290
|
+
}
|
|
11291
|
+
const port = await findAvailablePort();
|
|
11292
|
+
log(`Launching Figma Desktop (port ${port})...`);
|
|
11293
|
+
launchFigmaProcess(figmaPath, port);
|
|
11294
|
+
const startTime = Date.now();
|
|
11295
|
+
while (Date.now() - startTime < CDP_WAIT_TIMEOUT_MS) {
|
|
11296
|
+
await new Promise((r) => setTimeout(r, CDP_POLL_INTERVAL_MS));
|
|
11297
|
+
const { alive, isFigma } = await isCdpAlive(port);
|
|
11298
|
+
if (alive && isFigma) {
|
|
11299
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
11300
|
+
const targets = await listTargets(port);
|
|
11301
|
+
log("Figma Desktop started");
|
|
11302
|
+
return { port, targets };
|
|
11303
|
+
}
|
|
11304
|
+
}
|
|
11305
|
+
throw new Error(
|
|
11306
|
+
`Figma did not respond on port ${port} within ${CDP_WAIT_TIMEOUT_MS / 1e3}s. Try again.`
|
|
11307
|
+
);
|
|
11308
|
+
}
|
|
11218
11309
|
function launchFigmaProcess(figmaPath, port) {
|
|
11219
11310
|
if (process.platform === "darwin") {
|
|
11220
11311
|
const binary = `${figmaPath}/Contents/MacOS/Figma`;
|
|
@@ -25896,8 +25987,11 @@ var RESOURCES = [
|
|
|
25896
25987
|
];
|
|
25897
25988
|
var INSTRUCTIONS = `You are connected to Figma Desktop via faux-studio. You can create, modify, and inspect designs using the tools below.
|
|
25898
25989
|
|
|
25990
|
+
## Transport
|
|
25991
|
+
faux-studio connects to Figma Desktop via **CDP (Chrome DevTools Protocol)** by default \u2014 no plugin needed. It launches Figma with a debug port and communicates directly. If the Figma plugin is installed and running, it can also connect via plugin WebSocket as a fallback. CDP is the preferred zero-setup transport.
|
|
25992
|
+
|
|
25899
25993
|
## Workflow
|
|
25900
|
-
1. Call \`setup_figma\` first to ensure Figma is running and connected.
|
|
25994
|
+
1. Call \`setup_figma\` first to ensure Figma is running and connected (via CDP or plugin).
|
|
25901
25995
|
2. Call \`get_page_structure\` or \`get_screenshot\` to understand what's on the canvas.
|
|
25902
25996
|
3. Use \`create_from_schema\` for all creation \u2014 it accepts declarative JSON schemas.
|
|
25903
25997
|
4. Use \`modify_via_schema\` to change existing nodes.
|
|
@@ -25937,7 +26031,7 @@ Resources provide quick read-only access to Figma state without tool calls:
|
|
|
25937
26031
|
- Create components for reusable UI patterns.`;
|
|
25938
26032
|
function createMcpServer(deps) {
|
|
25939
26033
|
const server2 = new Server(
|
|
25940
|
-
{ name: "faux-studio", version: "0.4.
|
|
26034
|
+
{ name: "faux-studio", version: "0.4.7" },
|
|
25941
26035
|
{
|
|
25942
26036
|
capabilities: { tools: { listChanged: true }, resources: {}, logging: {} },
|
|
25943
26037
|
instructions: INSTRUCTIONS
|
|
@@ -25952,7 +26046,7 @@ function createMcpServer(deps) {
|
|
|
25952
26046
|
},
|
|
25953
26047
|
{
|
|
25954
26048
|
name: "setup_figma",
|
|
25955
|
-
description: "Ensure Figma Desktop is running and connected. Call this before any design work. Launches Figma if needed, detects open files and the active tab
|
|
26049
|
+
description: "Ensure Figma Desktop is running and connected via CDP (preferred) or plugin WebSocket. Call this before any design work. Launches Figma with CDP debug port if needed, detects open files and the active tab. Returns connection status, transport mode, active file, and list of all open design files. Idempotent \u2014 safe to call multiple times.",
|
|
25956
26050
|
inputSchema: {
|
|
25957
26051
|
type: "object",
|
|
25958
26052
|
properties: {},
|
|
@@ -26166,13 +26260,19 @@ function lazyInit() {
|
|
|
26166
26260
|
return initPromise2;
|
|
26167
26261
|
}
|
|
26168
26262
|
async function doInit() {
|
|
26263
|
+
log("[init] lazyInit triggered \u2014 starting auth + tool fetch");
|
|
26264
|
+
const t0 = Date.now();
|
|
26169
26265
|
auth = await ensureAuth();
|
|
26266
|
+
log(`[init] auth complete in ${Date.now() - t0}ms`);
|
|
26170
26267
|
try {
|
|
26268
|
+
const t1 = Date.now();
|
|
26171
26269
|
tools = await getTools(auth.jwt);
|
|
26270
|
+
log(`[init] tools fetched (${tools.length}) in ${Date.now() - t1}ms`);
|
|
26172
26271
|
} catch (err) {
|
|
26173
26272
|
error(err instanceof Error ? err.message : String(err));
|
|
26174
26273
|
process.exit(1);
|
|
26175
26274
|
}
|
|
26275
|
+
log(`[init] full initialization complete in ${Date.now() - t0}ms`);
|
|
26176
26276
|
}
|
|
26177
26277
|
async function tryConnectCdp() {
|
|
26178
26278
|
try {
|
|
@@ -26196,10 +26296,6 @@ async function tryConnectCdp() {
|
|
|
26196
26296
|
}
|
|
26197
26297
|
}
|
|
26198
26298
|
async function executeScript(script, intents, opts) {
|
|
26199
|
-
if (forceTransport !== "cdp" && pluginServer.hasConnections) {
|
|
26200
|
-
log(`Executing via plugin (file: ${pluginServer.activeFileId || "active"})`);
|
|
26201
|
-
return pluginServer.executeScript(script, void 0, intents);
|
|
26202
|
-
}
|
|
26203
26299
|
if (forceTransport !== "plugin") {
|
|
26204
26300
|
const client = await tryConnectCdp();
|
|
26205
26301
|
if (client) {
|
|
@@ -26236,6 +26332,10 @@ async function executeScript(script, intents, opts) {
|
|
|
26236
26332
|
}
|
|
26237
26333
|
}
|
|
26238
26334
|
}
|
|
26335
|
+
if (forceTransport !== "cdp" && pluginServer.hasConnections) {
|
|
26336
|
+
log(`Executing via plugin (file: ${pluginServer.activeFileId || "active"})`);
|
|
26337
|
+
return pluginServer.executeScript(script, void 0, intents);
|
|
26338
|
+
}
|
|
26239
26339
|
log("No transport available, waiting for plugin...");
|
|
26240
26340
|
return pluginServer.executeScript(script, void 0, intents);
|
|
26241
26341
|
}
|
|
@@ -26308,9 +26408,6 @@ function pluginReadyResult() {
|
|
|
26308
26408
|
};
|
|
26309
26409
|
}
|
|
26310
26410
|
async function setupFigma(params) {
|
|
26311
|
-
if (pluginServer.hasConnections) {
|
|
26312
|
-
return pluginReadyResult();
|
|
26313
|
-
}
|
|
26314
26411
|
if (forceTransport !== "plugin" && cdpClient?.connected && cdpClient.hasContext) {
|
|
26315
26412
|
if (fileTracker) {
|
|
26316
26413
|
const detection = await fileTracker.detectActiveFile();
|
|
@@ -26328,6 +26425,9 @@ async function setupFigma(params) {
|
|
|
26328
26425
|
message: "Connected via CDP. Ready to design."
|
|
26329
26426
|
};
|
|
26330
26427
|
}
|
|
26428
|
+
if (forceTransport !== "cdp" && pluginServer.hasConnections) {
|
|
26429
|
+
return pluginReadyResult();
|
|
26430
|
+
}
|
|
26331
26431
|
if (forceTransport !== "plugin") {
|
|
26332
26432
|
const existing = await probeCdpPorts();
|
|
26333
26433
|
if (existing) {
|
|
@@ -26363,25 +26463,77 @@ async function setupFigma(params) {
|
|
|
26363
26463
|
return {
|
|
26364
26464
|
status: "not_installed",
|
|
26365
26465
|
transport: "none",
|
|
26366
|
-
message:
|
|
26367
|
-
|
|
26368
|
-
1. Download Figma: https://figma.com/downloads
|
|
26369
|
-
2. Install and open it
|
|
26370
|
-
3. Install the faux-studio plugin: ${PLUGIN_URL}
|
|
26371
|
-
4. Call setup_figma again`
|
|
26466
|
+
message: "Figma Desktop is not installed.\n\n1. Download Figma: https://figma.com/downloads\n2. Install and open it\n3. Call setup_figma again"
|
|
26372
26467
|
};
|
|
26373
26468
|
}
|
|
26374
26469
|
if (!isFigmaRunning()) {
|
|
26375
|
-
|
|
26376
|
-
|
|
26377
|
-
|
|
26378
|
-
|
|
26379
|
-
|
|
26380
|
-
|
|
26381
|
-
|
|
26382
|
-
|
|
26470
|
+
if (forceTransport === "plugin") {
|
|
26471
|
+
try {
|
|
26472
|
+
launchFigma();
|
|
26473
|
+
} catch (err) {
|
|
26474
|
+
return {
|
|
26475
|
+
status: "not_installed",
|
|
26476
|
+
transport: "none",
|
|
26477
|
+
message: err instanceof Error ? err.message : "Failed to launch Figma."
|
|
26478
|
+
};
|
|
26479
|
+
}
|
|
26480
|
+
} else {
|
|
26481
|
+
try {
|
|
26482
|
+
const connection = await launchFigmaWithCdp();
|
|
26483
|
+
const target = findFigmaDesignTarget(connection.targets);
|
|
26484
|
+
if (target) {
|
|
26485
|
+
const client = new CdpClient();
|
|
26486
|
+
await client.connect(target.webSocketDebuggerUrl);
|
|
26487
|
+
await client.discoverFigmaContext();
|
|
26488
|
+
cdpClient = client;
|
|
26489
|
+
log(`CDP connected after launch: ${target.title}`);
|
|
26490
|
+
if (!fileTracker) {
|
|
26491
|
+
fileTracker = new CdpFileTracker(connection.port);
|
|
26492
|
+
}
|
|
26493
|
+
const detection = await fileTracker.detectActiveFile();
|
|
26494
|
+
fileTracker.acknowledgeActiveFile();
|
|
26495
|
+
return {
|
|
26496
|
+
status: "launched",
|
|
26497
|
+
transport: "cdp",
|
|
26498
|
+
message: `Launched Figma and connected via CDP. Active file: "${detection.activeFile?.fileName ?? target.title}". ${detection.allFiles.length} file(s) open. Ready to design.`,
|
|
26499
|
+
activeFile: detection.activeFile?.fileName ?? target.title,
|
|
26500
|
+
openFiles: detection.allFiles.map((f) => ({ fileKey: f.fileKey, fileName: f.fileName })),
|
|
26501
|
+
port: connection.port
|
|
26502
|
+
};
|
|
26503
|
+
}
|
|
26504
|
+
return {
|
|
26505
|
+
status: "launched",
|
|
26506
|
+
transport: "cdp",
|
|
26507
|
+
message: "Launched Figma with CDP enabled but no design file is open.\n\nOpen or create a design file in Figma, then call setup_figma again.",
|
|
26508
|
+
port: connection.port
|
|
26509
|
+
};
|
|
26510
|
+
} catch (err) {
|
|
26511
|
+
return {
|
|
26512
|
+
status: "not_installed",
|
|
26513
|
+
transport: "none",
|
|
26514
|
+
message: err instanceof Error ? err.message : "Failed to launch Figma."
|
|
26515
|
+
};
|
|
26516
|
+
}
|
|
26383
26517
|
}
|
|
26384
26518
|
}
|
|
26519
|
+
if (forceTransport !== "plugin") {
|
|
26520
|
+
return {
|
|
26521
|
+
status: "waiting_for_plugin",
|
|
26522
|
+
transport: "none",
|
|
26523
|
+
message: `Figma is running but the CDP debug port is not enabled.
|
|
26524
|
+
|
|
26525
|
+
To fix this:
|
|
26526
|
+
1. Quit Figma completely (Cmd+Q / Alt+F4)
|
|
26527
|
+
2. Call setup_figma again \u2014 it will relaunch Figma with CDP enabled
|
|
26528
|
+
|
|
26529
|
+
Alternatively, install the faux-studio plugin:
|
|
26530
|
+
1. Download: ${PLUGIN_URL}
|
|
26531
|
+
2. In Figma: Plugins \u2192 Development \u2192 Import plugin from manifest
|
|
26532
|
+
3. Run: Plugins \u2192 Development \u2192 faux-studio
|
|
26533
|
+
4. Call setup_figma again once the plugin shows "Ready".`,
|
|
26534
|
+
port: pluginServer.port
|
|
26535
|
+
};
|
|
26536
|
+
}
|
|
26385
26537
|
log("Waiting for plugin connection...");
|
|
26386
26538
|
const connected = await waitForPlugin();
|
|
26387
26539
|
if (connected) {
|
|
@@ -26408,7 +26560,8 @@ Call setup_figma again once the plugin shows "Ready".`,
|
|
|
26408
26560
|
};
|
|
26409
26561
|
}
|
|
26410
26562
|
async function main() {
|
|
26411
|
-
|
|
26563
|
+
const startupT0 = Date.now();
|
|
26564
|
+
log(`faux-studio v${"0.4.7"} \u2014 process started (PID ${process.pid}, PPID ${process.ppid})`);
|
|
26412
26565
|
try {
|
|
26413
26566
|
const port = await pluginServer.start();
|
|
26414
26567
|
if (forceTransport === "plugin") {
|
|
@@ -26416,7 +26569,7 @@ async function main() {
|
|
|
26416
26569
|
} else if (forceTransport === "cdp") {
|
|
26417
26570
|
log(`Transport: CDP-only mode (FAUX_TRANSPORT=cdp) \u2014 plugin WS on port ${port} (standby)`);
|
|
26418
26571
|
} else {
|
|
26419
|
-
log(`Transport: auto \u2014 plugin WS on port ${port}
|
|
26572
|
+
log(`Transport: auto \u2014 CDP preferred, plugin WS on port ${port} (fallback)`);
|
|
26420
26573
|
}
|
|
26421
26574
|
} catch (err) {
|
|
26422
26575
|
warn(`Plugin WS server failed to start: ${err instanceof Error ? err.message : err}`);
|
|
@@ -26460,6 +26613,7 @@ async function main() {
|
|
|
26460
26613
|
});
|
|
26461
26614
|
await startServer(server2);
|
|
26462
26615
|
setServer(server2);
|
|
26616
|
+
log(`[startup] MCP server ready in ${Date.now() - startupT0}ms \u2014 handshake complete`);
|
|
26463
26617
|
if (forceTransport !== "plugin") {
|
|
26464
26618
|
try {
|
|
26465
26619
|
await tryConnectCdp();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "faux-studio",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "AI-powered Figma design via MCP — connect any AI client to Figma Desktop",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -44,7 +44,9 @@
|
|
|
44
44
|
"url": "https://github.com/uxfreak/faux-studio.git"
|
|
45
45
|
},
|
|
46
46
|
"homepage": "https://faux.design",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
47
|
+
"os": [
|
|
48
|
+
"darwin",
|
|
49
|
+
"linux",
|
|
50
|
+
"win32"
|
|
51
|
+
]
|
|
50
52
|
}
|