@atezer/figma-mcp-bridge 1.4.1 → 1.4.3
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/CHANGELOG.md +14 -1
- package/README.md +1 -1
- package/dist/browser/base.d.ts +50 -0
- package/dist/browser/base.d.ts.map +1 -0
- package/dist/browser/base.js +6 -0
- package/dist/browser/base.js.map +1 -0
- package/dist/browser/local.d.ts +81 -0
- package/dist/browser/local.d.ts.map +1 -0
- package/dist/browser/local.js +283 -0
- package/dist/browser/local.js.map +1 -0
- package/dist/core/plugin-bridge-server.js +1 -1
- package/dist/local-plugin-only.js +1 -1
- package/dist/local.js +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,7 +12,20 @@ Bu dosya [Keep a Changelog](https://keepachangelog.com/tr/1.1.0/) bicimine uygun
|
|
|
12
12
|
|
|
13
13
|
Bu changelog'a ekleme oncesi surumlerin tam ayrintilari icin `git log` kullanilabilir.
|
|
14
14
|
|
|
15
|
-
## [1.4.
|
|
15
|
+
## [1.4.3] - 2026-04-02
|
|
16
|
+
|
|
17
|
+
### Versiyon tutarliligi
|
|
18
|
+
|
|
19
|
+
- Tum kaynak kod, dokuman ve config dosyalarindaki versiyon referanslari 1.4.2→1.4.3 senkronize edildi.
|
|
20
|
+
- McpServer version, bridgeVersion, plugin.json, README, FUTURE hepsi guncel.
|
|
21
|
+
|
|
22
|
+
## [1.4.2] - 2026-04-02
|
|
23
|
+
|
|
24
|
+
### Kritik duzeltme
|
|
25
|
+
|
|
26
|
+
- **dist/browser pakete geri eklendi:** v1.4.1'de tam mod (local.js) `dist/browser/local.js`'i import ediyordu ama dosya paketten cikarilmisti → MODULE_NOT_FOUND hatasi. `dist/cloudflare/` haric tutuldu (bu kullanilmiyor).
|
|
27
|
+
|
|
28
|
+
## [1.4.1] - 2026-04-02 [YANLIS — tam mod kirik, 1.4.2 kullanin]
|
|
16
29
|
|
|
17
30
|
### npm paket optimizasyonu
|
|
18
31
|
|
package/README.md
CHANGED
|
@@ -91,7 +91,7 @@ Varsayılan NPM `main` ve `figma-mcp-bridge` komutu **tam mod**dur; plugin ile y
|
|
|
91
91
|
|
|
92
92
|
| Ne | Nerede |
|
|
93
93
|
| --- | --- |
|
|
94
|
-
| **Sürüm numarası** | [`package.json`](package.json) içindeki `version` (ör. **1.4.
|
|
94
|
+
| **Sürüm numarası** | [`package.json`](package.json) içindeki `version` (ör. **1.4.2**) |
|
|
95
95
|
| **Değişiklik özeti** | [CHANGELOG.md](CHANGELOG.md) |
|
|
96
96
|
| **Yayın bildirimi** | GitHub’da [Releases](https://github.com/atezer/FMCP/releases) — *Watch* → *Custom* → *Releases* ile e-posta bildirimi |
|
|
97
97
|
| **npm paketi** | [@atezer/figma-mcp-bridge](https://www.npmjs.com/package/@atezer/figma-mcp-bridge) — sürüm geçmişi npm sayfasında |
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Manager Interface
|
|
3
|
+
* Abstract interface for browser automation across different runtimes
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Browser Manager Interface
|
|
7
|
+
* Provides unified API for browser automation regardless of runtime (Cloudflare/Local)
|
|
8
|
+
*
|
|
9
|
+
* Note: Uses 'any' for Page type to support both puppeteer-core and @cloudflare/puppeteer
|
|
10
|
+
* implementations which have incompatible type definitions but compatible runtime behavior
|
|
11
|
+
*/
|
|
12
|
+
export interface IBrowserManager {
|
|
13
|
+
/**
|
|
14
|
+
* Launch or connect to browser instance
|
|
15
|
+
*/
|
|
16
|
+
launch(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Get active page instance
|
|
19
|
+
*/
|
|
20
|
+
getPage(): Promise<any>;
|
|
21
|
+
/**
|
|
22
|
+
* Navigate to Figma URL
|
|
23
|
+
*/
|
|
24
|
+
navigateToFigma(url?: string): Promise<any>;
|
|
25
|
+
/**
|
|
26
|
+
* Reload current page
|
|
27
|
+
*/
|
|
28
|
+
reload(hardReload?: boolean): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Evaluate JavaScript in page context
|
|
31
|
+
*/
|
|
32
|
+
evaluate<T>(fn: () => T): Promise<T>;
|
|
33
|
+
/**
|
|
34
|
+
* Check if browser is running
|
|
35
|
+
*/
|
|
36
|
+
isRunning(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Close browser instance
|
|
39
|
+
*/
|
|
40
|
+
close(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Get current URL
|
|
43
|
+
*/
|
|
44
|
+
getCurrentUrl(): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Wait for navigation to complete
|
|
47
|
+
*/
|
|
48
|
+
waitForNavigation(timeout?: number): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/browser/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC/B;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAExB;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IAExB;;OAEG;IACH,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAE5C;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C;;OAEG;IACH,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAKrC;;OAEG;IACH,SAAS,IAAI,OAAO,CAAC;IAErB;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI,CAAC;IAE/B;;OAEG;IACH,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/browser/base.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Browser Manager
|
|
3
|
+
* Connects to Figma Desktop via Chrome Remote Debugging Protocol
|
|
4
|
+
*/
|
|
5
|
+
import { type Page } from 'puppeteer-core';
|
|
6
|
+
import type { IBrowserManager } from './base.js';
|
|
7
|
+
/**
|
|
8
|
+
* Local browser configuration
|
|
9
|
+
*/
|
|
10
|
+
export interface LocalBrowserConfig {
|
|
11
|
+
debugPort: number;
|
|
12
|
+
debugHost: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Local Browser Manager
|
|
16
|
+
* Connects to existing Figma Desktop instance via remote debugging port
|
|
17
|
+
*/
|
|
18
|
+
export declare class LocalBrowserManager implements IBrowserManager {
|
|
19
|
+
private browser;
|
|
20
|
+
private page;
|
|
21
|
+
private config;
|
|
22
|
+
constructor(config: LocalBrowserConfig);
|
|
23
|
+
/**
|
|
24
|
+
* Connect to Figma Desktop via remote debugging port
|
|
25
|
+
*/
|
|
26
|
+
launch(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Find the best page for plugin debugging
|
|
29
|
+
* Actively searches for pages with workers across ALL tabs
|
|
30
|
+
*/
|
|
31
|
+
private findBestPage;
|
|
32
|
+
/**
|
|
33
|
+
* Get active Figma page or create new one
|
|
34
|
+
* Prefers pages with active plugin workers for plugin debugging
|
|
35
|
+
*/
|
|
36
|
+
getPage(): Promise<Page>;
|
|
37
|
+
/**
|
|
38
|
+
* Navigate to Figma URL
|
|
39
|
+
*/
|
|
40
|
+
navigateToFigma(figmaUrl?: string): Promise<Page>;
|
|
41
|
+
/**
|
|
42
|
+
* Reload current page
|
|
43
|
+
*/
|
|
44
|
+
reload(hardReload?: boolean): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Execute JavaScript in page context
|
|
47
|
+
*/
|
|
48
|
+
evaluate<T>(fn: () => T): Promise<T>;
|
|
49
|
+
/**
|
|
50
|
+
* Check if browser is connected
|
|
51
|
+
*/
|
|
52
|
+
isRunning(): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Disconnect from browser (doesn't close Figma Desktop)
|
|
55
|
+
*/
|
|
56
|
+
close(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Get current page URL
|
|
59
|
+
*/
|
|
60
|
+
getCurrentUrl(): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Check if the browser connection is still alive
|
|
63
|
+
* Returns false if connection is stale (e.g., after computer sleep)
|
|
64
|
+
*/
|
|
65
|
+
isConnectionAlive(): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Reconnect to Figma Desktop if connection was lost
|
|
68
|
+
* Call this before any operation that requires a live connection
|
|
69
|
+
*/
|
|
70
|
+
ensureConnection(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Force a complete reconnection to Figma Desktop
|
|
73
|
+
* Use this when frames become detached or stale even though the browser appears connected
|
|
74
|
+
*/
|
|
75
|
+
forceReconnect(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Wait for navigation
|
|
78
|
+
*/
|
|
79
|
+
waitForNavigation(timeout?: number): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/browser/local.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAkB,EAAgB,KAAK,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAIjD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IAC1D,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,MAAM,CAAqB;gBAEvB,MAAM,EAAE,kBAAkB;IAItC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IA2C7B;;;OAGG;YACW,YAAY;IA4C1B;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC9B;;OAEG;IACG,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBvD;;OAEG;IACG,MAAM,CAAC,UAAU,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB/C;;OAEG;IACG,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAQ1C;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB5B;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;IAQ9B;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAe3C;;;OAGG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBvC;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBrC;;OAEG;IACG,iBAAiB,CAAC,OAAO,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAUvD"}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Browser Manager
|
|
3
|
+
* Connects to Figma Desktop via Chrome Remote Debugging Protocol
|
|
4
|
+
*/
|
|
5
|
+
import puppeteer from 'puppeteer-core';
|
|
6
|
+
import { createChildLogger } from '../core/logger.js';
|
|
7
|
+
const logger = createChildLogger({ component: 'local-browser' });
|
|
8
|
+
/**
|
|
9
|
+
* Local Browser Manager
|
|
10
|
+
* Connects to existing Figma Desktop instance via remote debugging port
|
|
11
|
+
*/
|
|
12
|
+
export class LocalBrowserManager {
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.browser = null;
|
|
15
|
+
this.page = null;
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Connect to Figma Desktop via remote debugging port
|
|
20
|
+
*/
|
|
21
|
+
async launch() {
|
|
22
|
+
if (this.browser) {
|
|
23
|
+
logger.info('Browser already connected, reusing instance');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const { debugHost, debugPort } = this.config;
|
|
27
|
+
const browserURL = `http://${debugHost}:${debugPort}`;
|
|
28
|
+
logger.info({ browserURL }, 'Connecting to Figma Desktop');
|
|
29
|
+
try {
|
|
30
|
+
// Connect to existing browser (Figma Desktop)
|
|
31
|
+
this.browser = await puppeteer.connect({
|
|
32
|
+
browserURL,
|
|
33
|
+
defaultViewport: null, // Use Figma's viewport
|
|
34
|
+
});
|
|
35
|
+
logger.info('Connected to Figma Desktop successfully');
|
|
36
|
+
// Handle disconnection
|
|
37
|
+
this.browser.on('disconnected', () => {
|
|
38
|
+
logger.warn('Disconnected from Figma Desktop');
|
|
39
|
+
this.browser = null;
|
|
40
|
+
this.page = null;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
logger.error({ error, browserURL }, 'Failed to connect to Figma Desktop');
|
|
45
|
+
throw new Error(`Failed to connect to Figma Desktop at ${browserURL}.\n\n` +
|
|
46
|
+
`Make sure:\n` +
|
|
47
|
+
`1. Figma Desktop is running\n` +
|
|
48
|
+
`2. Figma was launched with: --remote-debugging-port=${debugPort}\n` +
|
|
49
|
+
`3. "Use Developer VM" is enabled in: Plugins → Development → Use Developer VM\n\n` +
|
|
50
|
+
`macOS launch command:\n` +
|
|
51
|
+
` open -a "Figma" --args --remote-debugging-port=${debugPort}\n\n` +
|
|
52
|
+
`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Find the best page for plugin debugging
|
|
57
|
+
* Actively searches for pages with workers across ALL tabs
|
|
58
|
+
*/
|
|
59
|
+
async findBestPage() {
|
|
60
|
+
if (!this.browser) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const pages = await this.browser.pages();
|
|
64
|
+
// Find Figma pages with workers
|
|
65
|
+
const figmaPages = pages.filter(p => {
|
|
66
|
+
const url = p.url();
|
|
67
|
+
return url.includes('figma.com') && !url.includes('devtools');
|
|
68
|
+
});
|
|
69
|
+
if (figmaPages.length === 0) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
// Check each page for workers
|
|
73
|
+
const pagesWithWorkers = figmaPages
|
|
74
|
+
.map(p => ({
|
|
75
|
+
page: p,
|
|
76
|
+
workerCount: p.workers().length,
|
|
77
|
+
url: p.url()
|
|
78
|
+
}))
|
|
79
|
+
.filter(p => p.workerCount > 0)
|
|
80
|
+
.sort((a, b) => b.workerCount - a.workerCount); // Most workers first
|
|
81
|
+
if (pagesWithWorkers.length > 0) {
|
|
82
|
+
logger.info({
|
|
83
|
+
url: pagesWithWorkers[0].url,
|
|
84
|
+
workerCount: pagesWithWorkers[0].workerCount,
|
|
85
|
+
totalPagesWithWorkers: pagesWithWorkers.length
|
|
86
|
+
}, 'Found page with active plugin workers');
|
|
87
|
+
return pagesWithWorkers[0].page;
|
|
88
|
+
}
|
|
89
|
+
// No workers found - prefer design/file pages
|
|
90
|
+
const designPage = figmaPages.find(p => p.url().includes('/design/') || p.url().includes('/file/'));
|
|
91
|
+
return designPage || figmaPages[0];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get active Figma page or create new one
|
|
95
|
+
* Prefers pages with active plugin workers for plugin debugging
|
|
96
|
+
*/
|
|
97
|
+
async getPage() {
|
|
98
|
+
// Ensure connection is alive before proceeding
|
|
99
|
+
await this.ensureConnection();
|
|
100
|
+
if (!this.browser) {
|
|
101
|
+
await this.launch();
|
|
102
|
+
}
|
|
103
|
+
// ALWAYS re-check for best page (don't cache if we might have missed workers)
|
|
104
|
+
const bestPage = await this.findBestPage();
|
|
105
|
+
if (bestPage) {
|
|
106
|
+
const workerCount = bestPage.workers().length;
|
|
107
|
+
logger.info({
|
|
108
|
+
url: bestPage.url(),
|
|
109
|
+
workerCount,
|
|
110
|
+
cached: this.page === bestPage
|
|
111
|
+
}, 'Selected page for monitoring');
|
|
112
|
+
this.page = bestPage;
|
|
113
|
+
return this.page;
|
|
114
|
+
}
|
|
115
|
+
// Fallback: Get any existing page or create new one
|
|
116
|
+
const pages = await this.browser.pages();
|
|
117
|
+
if (pages.length > 0 && pages[0].url() !== 'about:blank') {
|
|
118
|
+
logger.warn({ url: pages[0].url() }, 'No Figma pages found, using first available page');
|
|
119
|
+
this.page = pages[0];
|
|
120
|
+
return this.page;
|
|
121
|
+
}
|
|
122
|
+
// Last resort: Create new page
|
|
123
|
+
logger.warn('No suitable pages found, creating new page in Figma Desktop');
|
|
124
|
+
this.page = await this.browser.newPage();
|
|
125
|
+
return this.page;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Navigate to Figma URL
|
|
129
|
+
*/
|
|
130
|
+
async navigateToFigma(figmaUrl) {
|
|
131
|
+
// Ensure connection is alive before navigation
|
|
132
|
+
await this.ensureConnection();
|
|
133
|
+
const page = await this.getPage();
|
|
134
|
+
// Default to Figma homepage if no URL provided
|
|
135
|
+
const url = figmaUrl || 'https://www.figma.com';
|
|
136
|
+
logger.info({ url }, 'Navigating to Figma');
|
|
137
|
+
try {
|
|
138
|
+
await page.goto(url, {
|
|
139
|
+
waitUntil: 'networkidle2',
|
|
140
|
+
timeout: 30000,
|
|
141
|
+
});
|
|
142
|
+
logger.info({ url }, 'Navigation successful');
|
|
143
|
+
return page;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
logger.error({ error, url }, 'Navigation failed');
|
|
147
|
+
throw new Error(`Failed to navigate to ${url}: ${error}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Reload current page
|
|
152
|
+
*/
|
|
153
|
+
async reload(hardReload = false) {
|
|
154
|
+
if (!this.page || this.page.isClosed()) {
|
|
155
|
+
throw new Error('No active page to reload');
|
|
156
|
+
}
|
|
157
|
+
logger.info({ hardReload }, 'Reloading page');
|
|
158
|
+
try {
|
|
159
|
+
await this.page.reload({
|
|
160
|
+
waitUntil: 'networkidle2',
|
|
161
|
+
timeout: 30000,
|
|
162
|
+
});
|
|
163
|
+
logger.info('Page reloaded successfully');
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
logger.error({ error }, 'Page reload failed');
|
|
167
|
+
throw new Error(`Page reload failed: ${error}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Execute JavaScript in page context
|
|
172
|
+
*/
|
|
173
|
+
async evaluate(fn) {
|
|
174
|
+
const page = await this.getPage();
|
|
175
|
+
return page.evaluate(fn);
|
|
176
|
+
}
|
|
177
|
+
// Screenshot functionality removed - use Figma REST API's getImages() instead
|
|
178
|
+
// See: figma_take_screenshot and figma_get_component_image tools
|
|
179
|
+
/**
|
|
180
|
+
* Check if browser is connected
|
|
181
|
+
*/
|
|
182
|
+
isRunning() {
|
|
183
|
+
return this.browser !== null && this.browser.isConnected();
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Disconnect from browser (doesn't close Figma Desktop)
|
|
187
|
+
*/
|
|
188
|
+
async close() {
|
|
189
|
+
if (!this.browser) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
logger.info('Disconnecting from Figma Desktop');
|
|
193
|
+
try {
|
|
194
|
+
// Just disconnect, don't close Figma Desktop
|
|
195
|
+
this.browser.disconnect();
|
|
196
|
+
this.browser = null;
|
|
197
|
+
this.page = null;
|
|
198
|
+
logger.info('Disconnected from Figma Desktop successfully');
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
logger.error({ error }, 'Failed to disconnect from browser');
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get current page URL
|
|
207
|
+
*/
|
|
208
|
+
getCurrentUrl() {
|
|
209
|
+
if (!this.page || this.page.isClosed()) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
return this.page.url();
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Check if the browser connection is still alive
|
|
216
|
+
* Returns false if connection is stale (e.g., after computer sleep)
|
|
217
|
+
*/
|
|
218
|
+
async isConnectionAlive() {
|
|
219
|
+
try {
|
|
220
|
+
if (!this.browser || !this.page) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
// Try to get the page title - this will fail if connection is dead
|
|
224
|
+
await this.page.title();
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
logger.warn({ error }, 'Browser connection appears to be dead');
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Reconnect to Figma Desktop if connection was lost
|
|
234
|
+
* Call this before any operation that requires a live connection
|
|
235
|
+
*/
|
|
236
|
+
async ensureConnection() {
|
|
237
|
+
const isAlive = await this.isConnectionAlive();
|
|
238
|
+
if (!isAlive) {
|
|
239
|
+
logger.info('Connection lost, attempting to reconnect to Figma Desktop');
|
|
240
|
+
// Clear stale references
|
|
241
|
+
this.browser = null;
|
|
242
|
+
this.page = null;
|
|
243
|
+
// Reconnect
|
|
244
|
+
await this.launch();
|
|
245
|
+
logger.info('Successfully reconnected to Figma Desktop');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Force a complete reconnection to Figma Desktop
|
|
250
|
+
* Use this when frames become detached or stale even though the browser appears connected
|
|
251
|
+
*/
|
|
252
|
+
async forceReconnect() {
|
|
253
|
+
logger.info('Force reconnecting to Figma Desktop');
|
|
254
|
+
// Disconnect current connection if exists
|
|
255
|
+
if (this.browser) {
|
|
256
|
+
try {
|
|
257
|
+
this.browser.disconnect();
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
// Ignore disconnect errors
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Clear all references
|
|
264
|
+
this.browser = null;
|
|
265
|
+
this.page = null;
|
|
266
|
+
// Reconnect
|
|
267
|
+
await this.launch();
|
|
268
|
+
logger.info('Force reconnect completed');
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Wait for navigation
|
|
272
|
+
*/
|
|
273
|
+
async waitForNavigation(timeout = 30000) {
|
|
274
|
+
if (!this.page || this.page.isClosed()) {
|
|
275
|
+
throw new Error('No active page');
|
|
276
|
+
}
|
|
277
|
+
await this.page.waitForNavigation({
|
|
278
|
+
waitUntil: 'networkidle2',
|
|
279
|
+
timeout,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/browser/local.ts"],"names":[],"mappings":"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"}
|
|
@@ -247,7 +247,7 @@ export class PluginBridgeServer {
|
|
|
247
247
|
logger.info({ clientId, fileKey: incomingFileKey, fileName: incomingFileName }, "Plugin bridge: client registered (fileKey=%s, fileName=%s)", incomingFileKey, incomingFileName);
|
|
248
248
|
ws.send(JSON.stringify({
|
|
249
249
|
type: "welcome",
|
|
250
|
-
bridgeVersion: "1.4.
|
|
250
|
+
bridgeVersion: "1.4.2",
|
|
251
251
|
port: this.port,
|
|
252
252
|
clientId,
|
|
253
253
|
multiClient: true,
|
|
@@ -89,7 +89,7 @@ export async function main() {
|
|
|
89
89
|
bridge.start();
|
|
90
90
|
const server = new McpServer({
|
|
91
91
|
name: "F-MCP ATezer Bridge (Plugin-only)",
|
|
92
|
-
version: "1.4.
|
|
92
|
+
version: "1.4.2",
|
|
93
93
|
});
|
|
94
94
|
// ---- figma_list_connected_files (multi-client discovery) ----
|
|
95
95
|
server.registerTool("figma_list_connected_files", {
|
package/dist/local.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atezer/figma-mcp-bridge",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
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",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"dist/local.js.map",
|
|
19
19
|
"dist/local.d.ts",
|
|
20
20
|
"dist/local.d.ts.map",
|
|
21
|
+
"dist/browser",
|
|
21
22
|
"dist/core",
|
|
22
23
|
"f-mcp-plugin",
|
|
23
24
|
"README.md",
|