@atezer/figma-mcp-bridge 1.1.1 → 1.2.0
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 +164 -119
- package/dist/cloudflare/core/figma-desktop-connector.js +28 -16
- package/dist/cloudflare/core/figma-tools.js +290 -254
- package/dist/cloudflare/core/plugin-bridge-connector.js +38 -4
- package/dist/cloudflare/core/plugin-bridge-server.js +106 -29
- package/dist/core/figma-desktop-connector.d.ts +6 -2
- package/dist/core/figma-desktop-connector.d.ts.map +1 -1
- package/dist/core/figma-desktop-connector.js +28 -16
- package/dist/core/figma-desktop-connector.js.map +1 -1
- package/dist/core/figma-tools.d.ts.map +1 -1
- package/dist/core/figma-tools.js +290 -254
- package/dist/core/figma-tools.js.map +1 -1
- package/dist/core/plugin-bridge-connector.d.ts +18 -2
- package/dist/core/plugin-bridge-connector.d.ts.map +1 -1
- package/dist/core/plugin-bridge-connector.js +38 -4
- package/dist/core/plugin-bridge-connector.js.map +1 -1
- package/dist/core/plugin-bridge-server.d.ts +7 -2
- package/dist/core/plugin-bridge-server.d.ts.map +1 -1
- package/dist/core/plugin-bridge-server.js +106 -29
- package/dist/core/plugin-bridge-server.js.map +1 -1
- package/dist/local-plugin-only.d.ts.map +1 -1
- package/dist/local-plugin-only.js +289 -95
- package/dist/local-plugin-only.js.map +1 -1
- package/dist/local.js +323 -183
- package/dist/local.js.map +1 -1
- package/f-mcp-plugin/code.js +341 -53
- package/f-mcp-plugin/manifest.json +22 -3
- package/f-mcp-plugin/ui.html +226 -43
- package/package.json +3 -2
package/f-mcp-plugin/ui.html
CHANGED
|
@@ -9,12 +9,27 @@
|
|
|
9
9
|
padding: 0;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
html, body {
|
|
13
|
+
overflow: hidden !important;
|
|
14
|
+
overflow-x: hidden !important;
|
|
15
|
+
overflow-y: hidden !important;
|
|
16
|
+
/* Scrollbar'ları gizle; içerik ne ise öyle görünsün (taşma yok) */
|
|
17
|
+
-ms-overflow-style: none;
|
|
18
|
+
scrollbar-width: none;
|
|
19
|
+
}
|
|
20
|
+
html::-webkit-scrollbar, body::-webkit-scrollbar {
|
|
21
|
+
display: none;
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
body {
|
|
13
25
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
14
26
|
font-size: 11px;
|
|
15
27
|
background: var(--figma-color-bg, #2c2c2c);
|
|
16
28
|
color: var(--figma-color-text, rgba(255, 255, 255, 0.9));
|
|
17
|
-
|
|
29
|
+
width: fit-content;
|
|
30
|
+
min-width: 0;
|
|
31
|
+
height: auto;
|
|
32
|
+
min-height: 0;
|
|
18
33
|
display: flex;
|
|
19
34
|
align-items: center;
|
|
20
35
|
justify-content: center;
|
|
@@ -83,17 +98,29 @@
|
|
|
83
98
|
display: flex;
|
|
84
99
|
flex-direction: column;
|
|
85
100
|
gap: 6px;
|
|
86
|
-
width:
|
|
101
|
+
width: fit-content;
|
|
102
|
+
min-width: 0;
|
|
103
|
+
max-width: 100%;
|
|
104
|
+
overflow: hidden;
|
|
87
105
|
}
|
|
88
|
-
.bridge-port {
|
|
106
|
+
.bridge-host, .bridge-port {
|
|
89
107
|
display: flex;
|
|
90
108
|
align-items: center;
|
|
91
109
|
gap: 6px;
|
|
92
110
|
font-size: 10px;
|
|
93
111
|
}
|
|
94
|
-
.bridge-port label {
|
|
112
|
+
.bridge-host label, .bridge-port label {
|
|
95
113
|
color: var(--figma-color-text-secondary, rgba(255, 255, 255, 0.7));
|
|
96
114
|
}
|
|
115
|
+
.bridge-host input {
|
|
116
|
+
width: 90px;
|
|
117
|
+
padding: 2px 4px;
|
|
118
|
+
background: var(--figma-color-bg-tertiary, #1e1e1e);
|
|
119
|
+
border: 1px solid var(--figma-color-border, #4a4a4a);
|
|
120
|
+
border-radius: 3px;
|
|
121
|
+
color: inherit;
|
|
122
|
+
font-size: 11px;
|
|
123
|
+
}
|
|
97
124
|
.bridge-port input {
|
|
98
125
|
width: 56px;
|
|
99
126
|
padding: 2px 4px;
|
|
@@ -125,16 +152,20 @@
|
|
|
125
152
|
</head>
|
|
126
153
|
<body>
|
|
127
154
|
<div class="bridge-row">
|
|
128
|
-
<div class="bridge-status" id="status-container" title="
|
|
155
|
+
<div class="bridge-status" id="status-container" title="'no server': MCP bridge çalıştığından emin olun. Browser Figma'da da çalışır (aynı makinede localhost, uzakta IP girin).">
|
|
129
156
|
<div class="status-indicator loading" id="status-dot"></div>
|
|
130
157
|
<div class="status-text">
|
|
131
158
|
<span class="label">MCP</span>
|
|
132
159
|
<span class="state" id="status-state">connecting</span>
|
|
133
160
|
</div>
|
|
134
161
|
</div>
|
|
135
|
-
<div class="bridge-
|
|
162
|
+
<div class="bridge-host" title="Host: localhost (aynı makine) veya IP adresi (uzak makine). Browser Figma'da da çalışır.">
|
|
163
|
+
<label for="mcp-host">Host</label>
|
|
164
|
+
<input type="text" id="mcp-host" value="localhost" placeholder="localhost" aria-label="MCP bridge host (localhost veya IP)" />
|
|
165
|
+
</div>
|
|
166
|
+
<div class="bridge-port" title="Port: Claude açıkken 5454'te bağlanır. Çoklu kullanıcıda her kullanıcı farklı port (5455–5470) seçer.">
|
|
136
167
|
<label for="mcp-port">Port</label>
|
|
137
|
-
<input type="number" id="mcp-port" min="5454" max="5470" value="5454" />
|
|
168
|
+
<input type="number" id="mcp-port" min="5454" max="5470" value="5454" aria-label="MCP bridge port (5454 varsayılan, Claude açıkken bağlanır)" />
|
|
138
169
|
</div>
|
|
139
170
|
</div>
|
|
140
171
|
|
|
@@ -257,8 +288,11 @@
|
|
|
257
288
|
// COMPONENT OPERATIONS
|
|
258
289
|
// ============================================================================
|
|
259
290
|
|
|
260
|
-
window.getLocalComponents = () => {
|
|
261
|
-
|
|
291
|
+
window.getLocalComponents = (currentPageOnly, limit) => {
|
|
292
|
+
var params = {};
|
|
293
|
+
params.currentPageOnly = currentPageOnly !== false;
|
|
294
|
+
if (limit != null && limit > 0) params.limit = limit;
|
|
295
|
+
return window.sendPluginCommand('GET_LOCAL_COMPONENTS', params, 120000)
|
|
262
296
|
.catch(function(err) { return { success: false, error: err.message || String(err) }; });
|
|
263
297
|
};
|
|
264
298
|
|
|
@@ -470,7 +504,11 @@
|
|
|
470
504
|
case 'VARIABLES_DATA':
|
|
471
505
|
window.__figmaVariablesData = msg.data;
|
|
472
506
|
window.__figmaVariablesReady = true;
|
|
473
|
-
|
|
507
|
+
if (mcpConnectedPort) {
|
|
508
|
+
updateStatus('ready (:' + mcpConnectedPort + ')', true, false);
|
|
509
|
+
} else {
|
|
510
|
+
updateStatus('ready', true, false);
|
|
511
|
+
}
|
|
474
512
|
console.log('[F-MCP ATezer Bridge] Active - ' + (msg.data.variables?.length || 0) + ' vars');
|
|
475
513
|
break;
|
|
476
514
|
|
|
@@ -588,6 +626,9 @@
|
|
|
588
626
|
case 'GET_DOCUMENT_STRUCTURE_RESULT':
|
|
589
627
|
handleResult('GET_DOCUMENT_STRUCTURE', null);
|
|
590
628
|
break;
|
|
629
|
+
case 'GET_NODE_CONTEXT_RESULT':
|
|
630
|
+
handleResult('GET_NODE_CONTEXT', null);
|
|
631
|
+
break;
|
|
591
632
|
case 'GET_LOCAL_STYLES_RESULT':
|
|
592
633
|
handleResult('GET_LOCAL_STYLES', null);
|
|
593
634
|
break;
|
|
@@ -612,8 +653,26 @@
|
|
|
612
653
|
}
|
|
613
654
|
};
|
|
614
655
|
|
|
615
|
-
window.getDocumentStructure = (depth, verbosity) => {
|
|
616
|
-
|
|
656
|
+
window.getDocumentStructure = (depth, verbosity, includeLayout, includeVisual, includeTypography, includeCodeReady, outputHint) => {
|
|
657
|
+
var payload = { depth: depth || 1, verbosity: verbosity || 'summary' };
|
|
658
|
+
if (includeLayout !== undefined) payload.includeLayout = !!includeLayout;
|
|
659
|
+
if (includeVisual !== undefined) payload.includeVisual = !!includeVisual;
|
|
660
|
+
if (includeTypography !== undefined) payload.includeTypography = !!includeTypography;
|
|
661
|
+
if (includeCodeReady !== undefined) payload.includeCodeReady = !!includeCodeReady;
|
|
662
|
+
if (outputHint !== undefined && outputHint != null) payload.outputHint = outputHint;
|
|
663
|
+
return window.sendPluginCommand('GET_DOCUMENT_STRUCTURE', payload, 90000).then(function(r) {
|
|
664
|
+
if (r && r.success === false) return r;
|
|
665
|
+
return r && r.data !== undefined ? r.data : r;
|
|
666
|
+
});
|
|
667
|
+
};
|
|
668
|
+
window.getNodeContext = (nodeId, depth, verbosity, includeLayout, includeVisual, includeTypography, includeCodeReady, outputHint) => {
|
|
669
|
+
var payload = { nodeId: nodeId, depth: depth || 2, verbosity: verbosity || 'standard' };
|
|
670
|
+
if (includeLayout !== undefined) payload.includeLayout = !!includeLayout;
|
|
671
|
+
if (includeVisual !== undefined) payload.includeVisual = !!includeVisual;
|
|
672
|
+
if (includeTypography !== undefined) payload.includeTypography = !!includeTypography;
|
|
673
|
+
if (includeCodeReady !== undefined) payload.includeCodeReady = !!includeCodeReady;
|
|
674
|
+
if (outputHint !== undefined && outputHint != null) payload.outputHint = outputHint;
|
|
675
|
+
return window.sendPluginCommand('GET_NODE_CONTEXT', payload, 90000).then(function(r) {
|
|
617
676
|
if (r && r.success === false) return r;
|
|
618
677
|
return r && r.data !== undefined ? r.data : r;
|
|
619
678
|
});
|
|
@@ -649,11 +708,24 @@
|
|
|
649
708
|
|
|
650
709
|
// ============================================================================
|
|
651
710
|
// MCP PLUGIN BRIDGE - WebSocket client (no Figma debug port needed)
|
|
652
|
-
// Port configurable
|
|
711
|
+
// Host + Port configurable: browser Figma ve uzak makine destegi
|
|
653
712
|
// ============================================================================
|
|
654
|
-
var
|
|
713
|
+
var MCP_BRIDGE_PORT_KEY = 'f-mcp-bridge-port';
|
|
714
|
+
var MCP_BRIDGE_HOST_KEY = 'f-mcp-bridge-host';
|
|
655
715
|
var mcpBridgeWs = null;
|
|
656
716
|
var mcpBridgeReconnectTimer = null;
|
|
717
|
+
var mcpReconnectDelay = 1000;
|
|
718
|
+
var MCP_RECONNECT_MIN = 1000;
|
|
719
|
+
var MCP_RECONNECT_MAX = 30000;
|
|
720
|
+
var mcpConnecting = false;
|
|
721
|
+
var mcpConnectedPort = null;
|
|
722
|
+
|
|
723
|
+
function getMcpBridgeHost() {
|
|
724
|
+
var el = document.getElementById('mcp-host');
|
|
725
|
+
if (!el) return 'localhost';
|
|
726
|
+
var v = (el.value || '').trim();
|
|
727
|
+
return v || 'localhost';
|
|
728
|
+
}
|
|
657
729
|
|
|
658
730
|
function getMcpBridgePort() {
|
|
659
731
|
var el = document.getElementById('mcp-port');
|
|
@@ -663,9 +735,42 @@
|
|
|
663
735
|
return n;
|
|
664
736
|
}
|
|
665
737
|
|
|
738
|
+
function forceDisconnectAndReconnect() {
|
|
739
|
+
if (mcpBridgeReconnectTimer) { clearTimeout(mcpBridgeReconnectTimer); mcpBridgeReconnectTimer = null; }
|
|
740
|
+
mcpReconnectDelay = MCP_RECONNECT_MIN;
|
|
741
|
+
mcpConnecting = false;
|
|
742
|
+
if (mcpBridgeWs) {
|
|
743
|
+
var old = mcpBridgeWs;
|
|
744
|
+
mcpBridgeWs = null;
|
|
745
|
+
old.onclose = null;
|
|
746
|
+
old.onerror = null;
|
|
747
|
+
old.onmessage = null;
|
|
748
|
+
try { old.close(); } catch (_) {}
|
|
749
|
+
}
|
|
750
|
+
connectMcpBridge();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function initMcpHostInput() {
|
|
754
|
+
try {
|
|
755
|
+
var stored = localStorage.getItem(MCP_BRIDGE_HOST_KEY);
|
|
756
|
+
if (stored) {
|
|
757
|
+
var el = document.getElementById('mcp-host');
|
|
758
|
+
if (el) { el.value = stored; }
|
|
759
|
+
}
|
|
760
|
+
} catch (e) {}
|
|
761
|
+
var el = document.getElementById('mcp-host');
|
|
762
|
+
if (el) {
|
|
763
|
+
el.addEventListener('change', function() {
|
|
764
|
+
var host = getMcpBridgeHost();
|
|
765
|
+
try { localStorage.setItem(MCP_BRIDGE_HOST_KEY, host); } catch (e) {}
|
|
766
|
+
forceDisconnectAndReconnect();
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
666
771
|
function initMcpPortInput() {
|
|
667
772
|
try {
|
|
668
|
-
var stored = localStorage.getItem(
|
|
773
|
+
var stored = localStorage.getItem(MCP_BRIDGE_PORT_KEY);
|
|
669
774
|
if (stored) {
|
|
670
775
|
var n = parseInt(stored, 10);
|
|
671
776
|
if (n >= 5454 && n <= 5470) {
|
|
@@ -678,39 +783,96 @@
|
|
|
678
783
|
if (el) {
|
|
679
784
|
el.addEventListener('change', function() {
|
|
680
785
|
var port = getMcpBridgePort();
|
|
681
|
-
try { localStorage.setItem(
|
|
682
|
-
|
|
683
|
-
mcpBridgeWs.close();
|
|
684
|
-
mcpBridgeWs = null;
|
|
685
|
-
}
|
|
686
|
-
connectMcpBridge();
|
|
786
|
+
try { localStorage.setItem(MCP_BRIDGE_PORT_KEY, String(port)); } catch (e) {}
|
|
787
|
+
forceDisconnectAndReconnect();
|
|
687
788
|
});
|
|
688
789
|
}
|
|
689
790
|
}
|
|
690
791
|
|
|
792
|
+
var mcpHandshakeTimer = null;
|
|
793
|
+
var mcpHandshakeDone = false;
|
|
794
|
+
var mcpKeepAliveTimer = null;
|
|
795
|
+
|
|
796
|
+
function scheduleReconnect() {
|
|
797
|
+
if (mcpBridgeReconnectTimer) clearTimeout(mcpBridgeReconnectTimer);
|
|
798
|
+
mcpBridgeReconnectTimer = setTimeout(function() {
|
|
799
|
+
mcpBridgeReconnectTimer = null;
|
|
800
|
+
connectMcpBridge();
|
|
801
|
+
}, mcpReconnectDelay);
|
|
802
|
+
mcpReconnectDelay = Math.min(mcpReconnectDelay * 2, MCP_RECONNECT_MAX);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
function startKeepAlive(ws) {
|
|
806
|
+
if (mcpKeepAliveTimer) { clearInterval(mcpKeepAliveTimer); mcpKeepAliveTimer = null; }
|
|
807
|
+
mcpKeepAliveTimer = setInterval(function() {
|
|
808
|
+
if (ws && ws.readyState === 1) {
|
|
809
|
+
try { ws.send(JSON.stringify({ type: 'keepalive' })); } catch (_) {}
|
|
810
|
+
} else {
|
|
811
|
+
clearInterval(mcpKeepAliveTimer);
|
|
812
|
+
mcpKeepAliveTimer = null;
|
|
813
|
+
}
|
|
814
|
+
}, 2000);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function stopKeepAlive() {
|
|
818
|
+
if (mcpKeepAliveTimer) { clearInterval(mcpKeepAliveTimer); mcpKeepAliveTimer = null; }
|
|
819
|
+
}
|
|
820
|
+
|
|
691
821
|
function connectMcpBridge() {
|
|
692
|
-
if (
|
|
822
|
+
if (mcpConnecting) return;
|
|
823
|
+
if (mcpBridgeWs && (mcpBridgeWs.readyState === 0 || mcpBridgeWs.readyState === 1)) return;
|
|
824
|
+
mcpConnecting = true;
|
|
825
|
+
var host = getMcpBridgeHost();
|
|
693
826
|
var port = getMcpBridgePort();
|
|
694
|
-
var url = 'ws://
|
|
827
|
+
var url = 'ws://' + host + ':' + port;
|
|
828
|
+
mcpHandshakeDone = false;
|
|
695
829
|
try {
|
|
696
830
|
mcpBridgeWs = new WebSocket(url);
|
|
831
|
+
var currentWs = mcpBridgeWs;
|
|
697
832
|
mcpBridgeWs.onopen = function() {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
833
|
+
mcpConnecting = false;
|
|
834
|
+
mcpReconnectDelay = MCP_RECONNECT_MIN;
|
|
835
|
+
console.log('[F-MCP ATezer Bridge] WebSocket opened to ' + url + ', waiting for handshake...');
|
|
836
|
+
updateStatus('connecting...', false, false);
|
|
837
|
+
currentWs.send(JSON.stringify({ type: 'ready' }));
|
|
838
|
+
startKeepAlive(currentWs);
|
|
839
|
+
if (mcpHandshakeTimer) clearTimeout(mcpHandshakeTimer);
|
|
840
|
+
mcpHandshakeTimer = setTimeout(function() {
|
|
841
|
+
if (!mcpHandshakeDone && mcpBridgeWs === currentWs) {
|
|
842
|
+
console.warn('[F-MCP ATezer Bridge] No welcome from server — wrong server or outdated bridge');
|
|
843
|
+
updateStatus('wrong server', false, true);
|
|
844
|
+
}
|
|
845
|
+
}, 5000);
|
|
701
846
|
};
|
|
702
847
|
mcpBridgeWs.onmessage = function(event) {
|
|
703
848
|
try {
|
|
704
849
|
var msg = JSON.parse(event.data);
|
|
850
|
+
if (msg.type === 'welcome') {
|
|
851
|
+
mcpHandshakeDone = true;
|
|
852
|
+
if (mcpHandshakeTimer) { clearTimeout(mcpHandshakeTimer); mcpHandshakeTimer = null; }
|
|
853
|
+
mcpConnectedPort = msg.port || port;
|
|
854
|
+
console.log('[F-MCP ATezer Bridge] Handshake OK — bridge v' + (msg.bridgeVersion || '?') + ' on port ' + mcpConnectedPort);
|
|
855
|
+
updateStatus('ready (:' + mcpConnectedPort + ')', true, false);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
if (msg.type === 'ping') {
|
|
859
|
+
if (mcpBridgeWs && mcpBridgeWs.readyState === 1) {
|
|
860
|
+
mcpBridgeWs.send(JSON.stringify({ type: 'pong' }));
|
|
861
|
+
}
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
705
864
|
if (!msg.id || !msg.method) return;
|
|
706
865
|
var id = msg.id;
|
|
707
866
|
var method = msg.method;
|
|
708
867
|
var params = msg.params || {};
|
|
709
868
|
var run = function() {
|
|
710
869
|
if (method === 'getVariablesFromPluginUI') {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
870
|
+
// Always refresh first (async API) so variables work in dynamic-page context
|
|
871
|
+
return window.refreshVariables().then(function(r) {
|
|
872
|
+
if (r && r.success === false) return { success: false, error: r.error || 'Variables refresh failed' };
|
|
873
|
+
if (!window.__figmaVariablesData) return { success: false, error: 'Variables not loaded' };
|
|
874
|
+
return { success: true, variables: window.__figmaVariablesData.variables, variableCollections: window.__figmaVariablesData.variableCollections };
|
|
875
|
+
});
|
|
714
876
|
}
|
|
715
877
|
if (method === 'getComponentFromPluginUI') {
|
|
716
878
|
return window.requestComponentData(params.nodeId).then(function(data) {
|
|
@@ -758,7 +920,7 @@
|
|
|
758
920
|
return window.refreshVariables();
|
|
759
921
|
}
|
|
760
922
|
if (method === 'getLocalComponents') {
|
|
761
|
-
return window.getLocalComponents();
|
|
923
|
+
return window.getLocalComponents(params.currentPageOnly, params.limit);
|
|
762
924
|
}
|
|
763
925
|
if (method === 'instantiateComponent') {
|
|
764
926
|
return window.instantiateComponent(params.componentKey, params.options);
|
|
@@ -815,7 +977,10 @@
|
|
|
815
977
|
return window.setInstanceProperties(params.nodeId, params.properties);
|
|
816
978
|
}
|
|
817
979
|
if (method === 'getDocumentStructure') {
|
|
818
|
-
return window.getDocumentStructure(params.depth, params.verbosity);
|
|
980
|
+
return window.getDocumentStructure(params.depth, params.verbosity, params.includeLayout, params.includeVisual, params.includeTypography, params.includeCodeReady, params.outputHint);
|
|
981
|
+
}
|
|
982
|
+
if (method === 'getNodeContext') {
|
|
983
|
+
return window.getNodeContext(params.nodeId, params.depth, params.verbosity, params.includeLayout, params.includeVisual, params.includeTypography, params.includeCodeReady, params.outputHint);
|
|
819
984
|
}
|
|
820
985
|
if (method === 'getLocalStyles') {
|
|
821
986
|
return window.getLocalStyles(params.verbosity);
|
|
@@ -840,35 +1005,53 @@
|
|
|
840
1005
|
}
|
|
841
1006
|
return { success: false, error: 'Unknown method: ' + method };
|
|
842
1007
|
};
|
|
1008
|
+
var wsRef = mcpBridgeWs;
|
|
843
1009
|
Promise.resolve(run()).then(function(result) {
|
|
844
|
-
|
|
1010
|
+
if (wsRef && wsRef.readyState === 1) {
|
|
1011
|
+
try { wsRef.send(JSON.stringify({ id: id, result: result })); } catch (_) {}
|
|
1012
|
+
}
|
|
845
1013
|
}).catch(function(err) {
|
|
846
|
-
|
|
1014
|
+
if (wsRef && wsRef.readyState === 1) {
|
|
1015
|
+
try { wsRef.send(JSON.stringify({ id: id, error: err.message || String(err) })); } catch (_) {}
|
|
1016
|
+
}
|
|
847
1017
|
});
|
|
848
1018
|
} catch (e) {
|
|
849
|
-
if (mcpBridgeWs && mcpBridgeWs.readyState === 1 && msg && msg.id)
|
|
850
|
-
mcpBridgeWs.send(JSON.stringify({ id: msg.id, error: e.message || String(e) }));
|
|
1019
|
+
if (mcpBridgeWs && mcpBridgeWs.readyState === 1 && msg && msg.id) {
|
|
1020
|
+
try { mcpBridgeWs.send(JSON.stringify({ id: msg.id, error: e.message || String(e) })); } catch (_) {}
|
|
1021
|
+
}
|
|
851
1022
|
}
|
|
852
1023
|
};
|
|
853
1024
|
mcpBridgeWs.onclose = function() {
|
|
1025
|
+
stopKeepAlive();
|
|
1026
|
+
if (mcpBridgeWs !== currentWs) return;
|
|
854
1027
|
mcpBridgeWs = null;
|
|
1028
|
+
mcpConnecting = false;
|
|
1029
|
+
mcpConnectedPort = null;
|
|
1030
|
+
if (mcpHandshakeTimer) { clearTimeout(mcpHandshakeTimer); mcpHandshakeTimer = null; }
|
|
855
1031
|
updateStatus('no server', false, true);
|
|
856
|
-
|
|
857
|
-
mcpBridgeReconnectTimer = setTimeout(connectMcpBridge, 2000);
|
|
1032
|
+
scheduleReconnect();
|
|
858
1033
|
};
|
|
859
1034
|
mcpBridgeWs.onerror = function() {
|
|
860
|
-
|
|
861
|
-
updateStatus('no server', false, true);
|
|
862
|
-
if (mcpBridgeReconnectTimer) clearTimeout(mcpBridgeReconnectTimer);
|
|
863
|
-
mcpBridgeReconnectTimer = setTimeout(connectMcpBridge, 2000);
|
|
1035
|
+
mcpConnecting = false;
|
|
864
1036
|
};
|
|
865
1037
|
} catch (e) {
|
|
1038
|
+
mcpConnecting = false;
|
|
866
1039
|
updateStatus('no server', false, true);
|
|
867
|
-
|
|
868
|
-
mcpBridgeReconnectTimer = setTimeout(connectMcpBridge, 2000);
|
|
1040
|
+
scheduleReconnect();
|
|
869
1041
|
}
|
|
870
1042
|
}
|
|
1043
|
+
|
|
1044
|
+
if (typeof document !== 'undefined' && document.addEventListener) {
|
|
1045
|
+
document.addEventListener('visibilitychange', function() {
|
|
1046
|
+
if (!document.hidden && (!mcpBridgeWs || mcpBridgeWs.readyState > 1)) {
|
|
1047
|
+
mcpReconnectDelay = MCP_RECONNECT_MIN;
|
|
1048
|
+
connectMcpBridge();
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
|
|
871
1053
|
if (typeof WebSocket !== 'undefined') {
|
|
1054
|
+
initMcpHostInput();
|
|
872
1055
|
initMcpPortInput();
|
|
873
1056
|
connectMcpBridge();
|
|
874
1057
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atezer/figma-mcp-bridge",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "F-MCP ATezer: MCP server and Figma plugin bridge for Claude/Cursor. No REST token required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/local.js",
|
|
7
7
|
"types": "dist/local.d.ts",
|
|
8
8
|
"bin": {
|
|
9
|
-
"figma-mcp-bridge": "./dist/local.js"
|
|
9
|
+
"figma-mcp-bridge": "./dist/local.js",
|
|
10
|
+
"figma-mcp-bridge-plugin": "./dist/local-plugin-only.js"
|
|
10
11
|
},
|
|
11
12
|
"files": [
|
|
12
13
|
"dist",
|