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.
- package/figma-plugin/code.js +1 -1
- package/figma-plugin/manifest.json +2 -2
- package/package.json +1 -1
- package/src/bridge.js +52 -36
- package/src/server.js +3 -5
package/figma-plugin/code.js
CHANGED
|
@@ -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": ["
|
|
12
|
-
"reasoning": "
|
|
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.
|
|
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(
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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(
|
|
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: ()
|
|
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
|
-
|
|
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 } },
|