conductor-figma 3.0.0 → 3.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.
@@ -62,7 +62,7 @@ function resolveRef(ref) {
62
62
 
63
63
  async function loadFont(family, style) {
64
64
  try { await figma.loadFontAsync({ family: family || 'Inter', style: style || 'Regular' }) }
65
- catch { await figma.loadFontAsync({ family: 'Inter', style: 'Regular' }) }
65
+ catch (e) { await figma.loadFontAsync({ family: 'Inter', style: 'Regular' }) }
66
66
  }
67
67
 
68
68
  function serializeNode(node, depth) {
@@ -8,7 +8,7 @@
8
8
  "enableProposedApi": false,
9
9
  "editorType": ["figma"],
10
10
  "networkAccess": {
11
- "allowedDomains": ["none"],
12
- "reasoning": "Conductor connects to a local WebSocket server only"
11
+ "allowedDomains": ["*"],
12
+ "reasoning": "Connects to local MCP WebSocket server"
13
13
  }
14
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conductor-figma",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "Design-intelligent MCP server for Figma. 201 design-intelligent tools for Figma. Every tool knows typography, spacing, color, accessibility. Not a shape proxy — a design engine.",
5
5
  "author": "0xDragoon",
6
6
  "license": "MIT",
package/src/bridge.js CHANGED
@@ -4,57 +4,73 @@
4
4
 
5
5
  import { WebSocketServer } from 'ws'
6
6
 
7
- function log(...args) { process.stderr.write('[bridge] ' + args.join(' ') + '\n') }
7
+ function log() { process.stderr.write('[bridge] ' + Array.prototype.join.call(arguments, ' ') + '\n') }
8
8
 
9
9
  export function createBridge(port) {
10
10
  port = port || parseInt(process.env.CONDUCTOR_PORT) || 3055
11
- let wss = null
12
- let client = null
13
- let pending = new Map()
14
- let msgId = 0
11
+ var wss = null
12
+ var client = null
13
+ var pending = new Map()
14
+ var msgId = 0
15
+ var isOwner = false
15
16
 
16
17
  function start() {
17
- return new Promise((resolve) => {
18
- wss = new WebSocketServer({ port })
19
- wss.on('listening', () => { log(`WebSocket server on port ${port}`); resolve() })
20
- wss.on('connection', (ws) => {
21
- client = ws
22
- log('Figma plugin connected')
23
- ws.on('message', (data) => {
24
- try {
25
- const msg = JSON.parse(data.toString())
26
- if (msg.id && pending.has(msg.id)) {
27
- const { resolve, reject, timer } = pending.get(msg.id)
28
- clearTimeout(timer)
29
- pending.delete(msg.id)
30
- if (msg.error) reject(new Error(msg.error))
31
- else resolve(msg.result)
32
- }
33
- } catch (e) { log('Parse error:', e.message) }
18
+ return new Promise(function(resolve) {
19
+ try {
20
+ wss = new WebSocketServer({ port: port })
21
+ wss.on('listening', function() { isOwner = true; log('WebSocket server on port ' + port); resolve() })
22
+ wss.on('connection', function(ws) {
23
+ client = ws
24
+ log('Figma plugin connected')
25
+ ws.on('message', function(data) {
26
+ try {
27
+ var msg = JSON.parse(data.toString())
28
+ if (msg.id && pending.has(msg.id)) {
29
+ var p = pending.get(msg.id)
30
+ clearTimeout(p.timer)
31
+ pending.delete(msg.id)
32
+ if (msg.error) p.reject(new Error(msg.error))
33
+ else p.resolve(msg.result)
34
+ }
35
+ } catch (e) { log('Parse error:', e.message) }
36
+ })
37
+ ws.on('close', function() { client = null; log('Figma plugin disconnected') })
38
+ ws.on('error', function(e) { log('WS error:', e.message) })
34
39
  })
35
- ws.on('close', () => { client = null; log('Figma plugin disconnected') })
36
- ws.on('error', (e) => log('WS error:', e.message))
37
- })
38
- wss.on('error', (e) => { log('Server error:', e.message); resolve() })
40
+ wss.on('error', function(e) {
41
+ if (e.code === 'EADDRINUSE') {
42
+ log('Port ' + port + ' in use — another Conductor instance is running. This instance will handle MCP only.')
43
+ wss = null
44
+ resolve()
45
+ } else {
46
+ log('Server error:', e.message)
47
+ resolve()
48
+ }
49
+ })
50
+ } catch (e) {
51
+ log('Bridge start error:', e.message)
52
+ resolve()
53
+ }
39
54
  })
40
55
  }
41
56
 
42
- function stop() { if (wss) { wss.close(); wss = null } }
57
+ function stop() { if (wss && isOwner) { wss.close(); wss = null } }
43
58
 
44
59
  function isConnected() { return client !== null && client.readyState === 1 }
45
60
 
46
- function send(command, data, timeout = 15000) {
47
- return new Promise((resolve, reject) => {
48
- if (!isConnected()) return reject(new Error('Figma plugin not connected. Open Figma → Plugins → Development → Conductor'))
49
- const id = ++msgId
50
- const timer = setTimeout(() => {
61
+ function send(command, data, timeout) {
62
+ timeout = timeout || 15000
63
+ return new Promise(function(resolve, reject) {
64
+ if (!isConnected()) return reject(new Error('Figma plugin not connected. Run the Conductor plugin in Figma, and make sure the WebSocket server is running on port ' + port))
65
+ var id = ++msgId
66
+ var timer = setTimeout(function() {
51
67
  pending.delete(id)
52
- reject(new Error(`Timeout waiting for Figma response (${timeout}ms)`))
68
+ reject(new Error('Timeout waiting for Figma response (' + timeout + 'ms)'))
53
69
  }, timeout)
54
- pending.set(id, { resolve, reject, timer })
55
- client.send(JSON.stringify({ id, command, data }))
70
+ pending.set(id, { resolve: resolve, reject: reject, timer: timer })
71
+ client.send(JSON.stringify({ id: id, command: command, data: data }))
56
72
  })
57
73
  }
58
74
 
59
- return { start, stop, isConnected, send, getPort: () => port }
75
+ return { start: start, stop: stop, isConnected: isConnected, send: send, getPort: function() { return port } }
60
76
  }
package/src/server.js CHANGED
@@ -7,9 +7,11 @@ import { handleTool } from './tools/handlers.js'
7
7
  import { createBridge } from './bridge.js'
8
8
 
9
9
  const VERSION = '3.0.0'
10
- let bridge = null
10
+ const bridge = createBridge()
11
+ bridge.start()
11
12
 
12
13
  function log(...args) { process.stderr.write('[conductor] ' + args.join(' ') + '\n') }
14
+ log(`Conductor v${VERSION} starting — WebSocket on port ${bridge.getPort()}`)
13
15
 
14
16
  // ─── JSON-RPC over stdio ───
15
17
  let buffer = ''
@@ -49,10 +51,6 @@ async function handleMessage(msg) {
49
51
 
50
52
  switch (method) {
51
53
  case 'initialize':
52
- if (!bridge) {
53
- bridge = createBridge()
54
- await bridge.start()
55
- }
56
54
  return respond(id, {
57
55
  protocolVersion: '2024-11-05',
58
56
  capabilities: { tools: { listChanged: false } },