figma-rust-mcp 8.0.1 → 8.0.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.
@@ -253,6 +253,13 @@ async function findOrDownloadBinary() {
253
253
  * - Windows: Task Scheduler XML via schtasks
254
254
  */
255
255
  async function installService(binPath) {
256
+ // An outdated CLI (e.g. an old global install run via plain `npx figma-rust-mcp`) must not replace a newer service.
257
+ const running = await serverVersion(Number(process.env.FIGMA_RUST_MCP_PORT) || 41730);
258
+ if (running && isNewer(running, pkgVersion)) {
259
+ console.log(` ${yellow('!')} Service runs v${running}, newer than this CLI (v${pkgVersion}); left it unchanged.`);
260
+ note('Use the latest CLI: npx -y figma-rust-mcp@latest --init');
261
+ return false;
262
+ }
256
263
  removeLegacyService();
257
264
  await stopRunningServer();
258
265
  const platform = process.platform;
@@ -340,26 +347,51 @@ WantedBy=default.target
340
347
  console.error(`\x1b[31mUnsupported platform: ${platform}\x1b[0m`);
341
348
  process.exit(1);
342
349
  }
350
+ pruneOldBinaries(binPath);
351
+ }
352
+
353
+ /**
354
+ * Delete cached binaries of versions older than the one the service now runs. A process still
355
+ * running an old binary keeps working on macOS/Linux; on Windows a locked file is skipped.
356
+ */
357
+ function pruneOldBinaries(binPath) {
358
+ const root = path.dirname(getCacheDir(pkgVersion));
359
+ const current = path.basename(path.dirname(binPath)).match(/^v(\d+\.\d+\.\d+)$/)?.[1] || pkgVersion;
360
+ let entries;
361
+ try { entries = fs.readdirSync(root); } catch (_) { return; }
362
+ let freed = 0, removed = 0;
363
+ for (const name of entries) {
364
+ const version = name.match(/^v(\d+\.\d+\.\d+)$/)?.[1];
365
+ if (!version || !isNewer(current, version)) continue;
366
+ const dir = path.join(root, name);
367
+ try {
368
+ const size = fs.readdirSync(dir).reduce((sum, file) => sum + fs.statSync(path.join(dir, file)).size, 0);
369
+ fs.rmSync(dir, { recursive: true });
370
+ freed += size; removed++;
371
+ } catch (_) {}
372
+ }
373
+ if (removed) note(`Removed ${removed} old binar${removed === 1 ? 'y' : 'ies'} (${(freed / 1048576).toFixed(0)} MB freed)`);
343
374
  }
344
375
 
345
376
  async function serviceInstalled(where) {
346
377
  const port = Number(process.env.FIGMA_RUST_MCP_PORT) || 41730;
347
378
  const deadline = Date.now() + 10000;
348
- while (!(await isOldServerUp(port)) && Date.now() < deadline) await new Promise(resolve => setTimeout(resolve, 300));
349
- if (await isOldServerUp(port)) ok('Background service running', `http://127.0.0.1:${port}`);
379
+ while (!(await serverVersion(port)) && Date.now() < deadline) await new Promise(resolve => setTimeout(resolve, 300));
380
+ if (await serverVersion(port)) ok('Background service running', `http://127.0.0.1:${port}`);
350
381
  else console.log(` ${yellow('!')} Service installed but not answering on port ${port} yet`);
351
382
  note(`Starts on login · ${where}`);
352
383
  }
353
384
 
354
- function isOldServerUp(port) {
385
+ /** Version of the figma-rust-mcp answering on `port`, or null. */
386
+ function serverVersion(port) {
355
387
  return new Promise(resolve => {
356
388
  const req = http.get({ host: '127.0.0.1', port, path: '/plugin/version', timeout: 500 }, res => {
357
389
  let body = '';
358
390
  res.on('data', chunk => { body += chunk; });
359
- res.on('end', () => { try { resolve(JSON.parse(body).name === 'figma-rust-mcp'); } catch (_) { resolve(false); } });
391
+ res.on('end', () => { try { const v = JSON.parse(body); resolve(v.name === 'figma-rust-mcp' ? v.version || '0.0.0' : null); } catch (_) { resolve(null); } });
360
392
  });
361
- req.on('error', () => resolve(false));
362
- req.on('timeout', () => { req.destroy(); resolve(false); });
393
+ req.on('error', () => resolve(null));
394
+ req.on('timeout', () => { req.destroy(); resolve(null); });
363
395
  });
364
396
  }
365
397
 
@@ -382,7 +414,7 @@ async function stopRunningServer() {
382
414
  }
383
415
  const port = Number(process.env.FIGMA_RUST_MCP_PORT) || 41730;
384
416
  const deadline = Date.now() + 10000;
385
- while (await isOldServerUp(port)) {
417
+ while (await serverVersion(port)) {
386
418
  if (Date.now() > deadline) {
387
419
  console.log(` ${yellow('!')} An old figma-rust-mcp still answers on port ${port}; stop it, then rerun setup.`);
388
420
  return;
@@ -559,19 +591,17 @@ function checkForUpdatesAsync() {
559
591
  }
560
592
 
561
593
  async function upgrade() {
562
- console.log('\x1b[36m[figma-rust-mcp]\x1b[0m Checking for updates and upgrading figma-rust-mcp...');
594
+ const major = pkgVersion.split('.')[0];
595
+ console.log(`${tag(36)} Upgrading figma-rust-mcp v${major}.x…`);
563
596
  try {
564
- const major = pkgVersion ? pkgVersion.split('.')[0] : 'latest';
565
597
  execSync(`npm install -g figma-rust-mcp@${major}`, { stdio: 'inherit' });
566
- ok(`Upgraded figma-rust-mcp (${major === 'latest' ? 'latest' : `v${major}.x`})`);
567
- setupPlugin();
568
- if (isServiceInstalled()) {
569
- console.log('\x1b[36mUpdating background service binary...\x1b[0m');
570
- const binPath = await findOrDownloadBinary();
571
- await installService(binPath);
572
- }
598
+ // This process still runs the old code and version; let the new package refresh the plugin and service.
599
+ const args = ['-y', `figma-rust-mcp@${major}`, isServiceInstalled() ? '--install-service' : '--setup-plugin'];
600
+ execFileSync(process.platform === 'win32' ? 'npx.cmd' : 'npx', args, { stdio: 'inherit', shell: process.platform === 'win32' });
601
+ ok(`Upgraded figma-rust-mcp (v${major}.x)`);
573
602
  } catch (err) {
574
- console.log('\x1b[33mTip: Run directly with latest version:\x1b[0m\n npx -y figma-rust-mcp@latest\n');
603
+ console.log(` ${yellow('!')} Upgrade failed: ${err.message}`);
604
+ note('Run the latest version directly: npx -y figma-rust-mcp@latest --init');
575
605
  }
576
606
  }
577
607
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "figma-rust-mcp",
3
- "version": "8.0.1",
3
+ "version": "8.0.2",
4
4
  "description": "Claude Code to Figma — Bidirectional MCP bridge. AI draws UI on Figma canvas, reads designs back. Works with Claude, Cursor, VS Code, Windsurf, Antigravity. No API key needed.",
5
5
  "mcpName": "io.github.BuiHung1612/figma-rust-mcp",
6
6
  "type": "module",