@muloka/figma-console-mcp 0.3.0 → 0.5.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.
Files changed (35) hide show
  1. package/README.md +31 -13
  2. package/dist/apps/design-system-dashboard/mcp-app.html +521 -0
  3. package/dist/apps/token-browser/mcp-app.html +410 -0
  4. package/dist/cloudflare/core/figma-tools.js +64 -13
  5. package/dist/cloudflare/core/tokens-tools.js +1 -1
  6. package/dist/cloudflare/core/websocket-server.js +60 -7
  7. package/dist/cloudflare/index.js +3 -3
  8. package/dist/core/port-discovery.d.ts.map +1 -1
  9. package/dist/core/port-discovery.js +101 -20
  10. package/dist/core/port-discovery.js.map +1 -1
  11. package/dist/core/websocket-server.d.ts +18 -1
  12. package/dist/core/websocket-server.d.ts.map +1 -1
  13. package/dist/core/websocket-server.js +44 -3
  14. package/dist/core/websocket-server.js.map +1 -1
  15. package/dist/core/write-tools.d.ts.map +1 -1
  16. package/dist/core/write-tools.js +98 -9
  17. package/dist/core/write-tools.js.map +1 -1
  18. package/dist/local.d.ts.map +1 -1
  19. package/dist/local.js +7 -3
  20. package/dist/local.js.map +1 -1
  21. package/figma-desktop-bridge/code.js +57 -27
  22. package/figma-desktop-bridge/ui.html +76 -7
  23. package/package.json +1 -1
  24. package/dist/browser/base.d.ts +0 -58
  25. package/dist/browser/base.d.ts.map +0 -1
  26. package/dist/browser/base.js +0 -6
  27. package/dist/browser/base.js.map +0 -1
  28. package/dist/browser/local.d.ts +0 -87
  29. package/dist/browser/local.d.ts.map +0 -1
  30. package/dist/browser/local.js +0 -318
  31. package/dist/browser/local.js.map +0 -1
  32. package/dist/core/figma-desktop-connector.d.ts +0 -312
  33. package/dist/core/figma-desktop-connector.d.ts.map +0 -1
  34. package/dist/core/figma-desktop-connector.js +0 -1298
  35. package/dist/core/figma-desktop-connector.js.map +0 -1
@@ -719,40 +719,47 @@ figma.ui.onmessage = async (msg) => {
719
719
  // CREATE_VARIABLE_COLLECTION - Create a new variable collection
720
720
  // ============================================================================
721
721
  else if (msg.type === 'CREATE_VARIABLE_COLLECTION') {
722
+ var newCollection = null;
722
723
  try {
723
724
  console.log('🌉 [Desktop Bridge] Creating collection:', msg.name);
724
725
 
725
- // Create the collection
726
- var collection = figma.variables.createVariableCollection(msg.name);
726
+ newCollection = figma.variables.createVariableCollection(msg.name);
727
727
 
728
728
  // Rename the default mode if a name is provided
729
- if (msg.initialModeName && collection.modes.length > 0) {
730
- collection.renameMode(collection.modes[0].modeId, msg.initialModeName);
729
+ if (msg.initialModeName && newCollection.modes.length > 0) {
730
+ newCollection.renameMode(newCollection.modes[0].modeId, msg.initialModeName);
731
731
  }
732
732
 
733
733
  // Add additional modes if provided
734
734
  if (msg.additionalModes && msg.additionalModes.length > 0) {
735
735
  for (var i = 0; i < msg.additionalModes.length; i++) {
736
- collection.addMode(msg.additionalModes[i]);
736
+ newCollection.addMode(msg.additionalModes[i]);
737
737
  }
738
738
  }
739
739
 
740
- console.log('🌉 [Desktop Bridge] Collection created:', collection.id);
740
+ console.log('🌉 [Desktop Bridge] Collection created:', newCollection.id);
741
741
 
742
742
  figma.ui.postMessage({
743
743
  type: 'CREATE_VARIABLE_COLLECTION_RESULT',
744
744
  requestId: msg.requestId,
745
745
  success: true,
746
- collection: serializeCollection(collection)
746
+ collection: serializeCollection(newCollection)
747
747
  });
748
748
 
749
749
  } catch (error) {
750
+ // Mode setup failed after the collection was created — remove the
751
+ // orphan so a retry cannot create twins (mirrors the rollback in the
752
+ // tokens-tools create phase).
753
+ var ccRolledBack = false;
754
+ if (newCollection) {
755
+ try { newCollection.remove(); ccRolledBack = true; } catch (removeErr) {}
756
+ }
750
757
  console.error('🌉 [Desktop Bridge] Create collection error:', error);
751
758
  figma.ui.postMessage({
752
759
  type: 'CREATE_VARIABLE_COLLECTION_RESULT',
753
760
  requestId: msg.requestId,
754
761
  success: false,
755
- error: error.message || String(error)
762
+ error: (error.message || String(error)) + (ccRolledBack ? ' (partially-created collection rolled back)' : '')
756
763
  });
757
764
  }
758
765
  }
@@ -3751,12 +3758,18 @@ figma.ui.onmessage = async (msg) => {
3751
3758
 
3752
3759
  } catch (error) {
3753
3760
  var errorMsg = error && error.message ? error.message : String(error);
3761
+ // figma.createX() lands the node on the page immediately; a throw from
3762
+ // font load / resize / fills / appendChild would otherwise strand it.
3763
+ var childRemoved = false;
3764
+ if (typeof newNode !== 'undefined' && newNode) {
3765
+ try { newNode.remove(); childRemoved = true; } catch (removeErr) {}
3766
+ }
3754
3767
  console.error('🌉 [Desktop Bridge] Create child node error:', errorMsg);
3755
3768
  figma.ui.postMessage({
3756
3769
  type: 'CREATE_CHILD_NODE_RESULT',
3757
3770
  requestId: msg.requestId,
3758
3771
  success: false,
3759
- error: errorMsg
3772
+ error: errorMsg + (childRemoved ? ' (partially-created node was removed)' : '')
3760
3773
  });
3761
3774
  }
3762
3775
  }
@@ -6022,28 +6035,31 @@ figma.ui.onmessage = async (msg) => {
6022
6035
  var stickyFontLoaded = false;
6023
6036
 
6024
6037
  for (var si = 0; si < msg.stickies.length; si++) {
6038
+ var batchSticky = null;
6025
6039
  try {
6026
6040
  var spec = msg.stickies[si];
6027
- var sticky = figma.createSticky();
6041
+ batchSticky = figma.createSticky();
6028
6042
  if (!stickyFontLoaded) {
6029
- await figma.loadFontAsync(sticky.text.fontName);
6043
+ await figma.loadFontAsync(batchSticky.text.fontName);
6030
6044
  stickyFontLoaded = true;
6031
6045
  }
6032
- sticky.text.characters = spec.text || '';
6046
+ batchSticky.text.characters = spec.text || '';
6033
6047
 
6034
- if (typeof spec.x === 'number') sticky.x = spec.x;
6035
- if (typeof spec.y === 'number') sticky.y = spec.y;
6048
+ if (typeof spec.x === 'number') batchSticky.x = spec.x;
6049
+ if (typeof spec.y === 'number') batchSticky.y = spec.y;
6036
6050
 
6037
6051
  if (spec.color) {
6038
6052
  var sc = __stickyColors[spec.color.toUpperCase()];
6039
6053
  if (sc) {
6040
- sticky.fills = [{ type: 'SOLID', color: sc }];
6054
+ batchSticky.fills = [{ type: 'SOLID', color: sc }];
6041
6055
  }
6042
6056
  }
6043
6057
 
6044
- created.push({ id: sticky.id, type: sticky.type, name: sticky.name, x: sticky.x, y: sticky.y });
6058
+ created.push({ id: batchSticky.id, type: batchSticky.type, name: batchSticky.name, x: batchSticky.x, y: batchSticky.y });
6045
6059
  } catch (e) {
6046
- failed.push({ index: si, error: e.message || String(e) });
6060
+ // A sticky created before the throw EXISTS on the board but is in
6061
+ // neither list — report its id so the caller can find or remove it.
6062
+ failed.push({ index: si, id: batchSticky ? batchSticky.id : undefined, error: e.message || String(e) });
6047
6063
  }
6048
6064
  }
6049
6065
 
@@ -6073,15 +6089,17 @@ figma.ui.onmessage = async (msg) => {
6073
6089
  }
6074
6090
  console.log('🌉 [Desktop Bridge] Creating connector');
6075
6091
 
6076
- var connector = figma.createConnector();
6077
-
6078
- // Set start and end endpoints
6092
+ // Validate endpoints FIRST — a stale nodeId is the most common caller
6093
+ // error, and creating the connector before checking guaranteed an
6094
+ // endpoint-less orphan on every such call.
6079
6095
  var startNode = await figma.getNodeByIdAsync(msg.startNodeId);
6080
6096
  var endNode = await figma.getNodeByIdAsync(msg.endNodeId);
6081
6097
 
6082
6098
  if (!startNode) throw new Error('Start node not found: ' + msg.startNodeId);
6083
6099
  if (!endNode) throw new Error('End node not found: ' + msg.endNodeId);
6084
6100
 
6101
+ var connector = figma.createConnector();
6102
+
6085
6103
  connector.connectorStart = {
6086
6104
  endpointNodeId: msg.startNodeId,
6087
6105
  magnet: msg.startMagnet || 'AUTO'
@@ -6263,16 +6281,16 @@ figma.ui.onmessage = async (msg) => {
6263
6281
  }
6264
6282
  console.log('🌉 [Desktop Bridge] Creating table:', msg.rows, 'x', msg.columns);
6265
6283
 
6266
- var table = figma.createTable(msg.rows, msg.columns);
6284
+ var ctTable = figma.createTable(msg.rows, msg.columns);
6267
6285
 
6268
- if (typeof msg.x === 'number') table.x = msg.x;
6269
- if (typeof msg.y === 'number') table.y = msg.y;
6286
+ if (typeof msg.x === 'number') ctTable.x = msg.x;
6287
+ if (typeof msg.y === 'number') ctTable.y = msg.y;
6270
6288
 
6271
6289
  // Populate cells if data provided
6272
6290
  if (msg.data && Array.isArray(msg.data)) {
6273
6291
  for (var row = 0; row < msg.data.length && row < msg.rows; row++) {
6274
6292
  for (var col = 0; col < msg.data[row].length && col < msg.columns; col++) {
6275
- var cell = table.cellAt(row, col);
6293
+ var cell = ctTable.cellAt(row, col);
6276
6294
  if (cell && msg.data[row][col] != null) {
6277
6295
  await figma.loadFontAsync(cell.text.fontName);
6278
6296
  cell.text.characters = String(msg.data[row][col]);
@@ -6285,16 +6303,21 @@ figma.ui.onmessage = async (msg) => {
6285
6303
  type: 'CREATE_TABLE_RESULT',
6286
6304
  requestId: msg.requestId,
6287
6305
  success: true,
6288
- data: { id: table.id, type: table.type, name: table.name, rows: msg.rows, columns: msg.columns }
6306
+ data: { id: ctTable.id, type: ctTable.type, name: ctTable.name, rows: msg.rows, columns: msg.columns }
6289
6307
  });
6290
6308
 
6291
6309
  } catch (error) {
6310
+ // A font-load failure mid cell-loop leaves a half-populated table.
6311
+ var ctTableRemoved = false;
6312
+ if (typeof ctTable !== 'undefined' && ctTable) {
6313
+ try { ctTable.remove(); ctTableRemoved = true; } catch (removeErr) {}
6314
+ }
6292
6315
  console.error('🌉 [Desktop Bridge] Create table error:', error);
6293
6316
  figma.ui.postMessage({
6294
6317
  type: 'CREATE_TABLE_RESULT',
6295
6318
  requestId: msg.requestId,
6296
6319
  success: false,
6297
- error: error.message || String(error)
6320
+ error: (error.message || String(error)) + (ctTableRemoved ? ' (partially-created node was removed)' : '')
6298
6321
  });
6299
6322
  }
6300
6323
  }
@@ -7154,12 +7177,19 @@ figma.ui.onmessage = async (msg) => {
7154
7177
  });
7155
7178
 
7156
7179
  } catch (error) {
7180
+ // createText() lands on the page; ~7 fallible setters (font load,
7181
+ // textAlign/textCase enums, resize) run before appendChild moves it to
7182
+ // the slide — remove the stranded node on any of their throws.
7183
+ var slideTextRemoved = false;
7184
+ if (typeof textNode !== 'undefined' && textNode) {
7185
+ try { textNode.remove(); slideTextRemoved = true; } catch (removeErr) {}
7186
+ }
7157
7187
  console.error('🌉 [Desktop Bridge] Add text to slide error:', error);
7158
7188
  figma.ui.postMessage({
7159
7189
  type: 'ADD_TEXT_TO_SLIDE_RESULT',
7160
7190
  requestId: msg.requestId,
7161
7191
  success: false,
7162
- error: error.message || String(error)
7192
+ error: (error.message || String(error)) + (slideTextRemoved ? ' (partially-created node was removed)' : '')
7163
7193
  });
7164
7194
  }
7165
7195
  }
@@ -158,6 +158,18 @@
158
158
  white-space: nowrap;
159
159
  }
160
160
 
161
+ /* ===== Build version line — plugin files + server, always visible =====
162
+ Deliberately NOT gated on connection state: "is my imported plugin
163
+ stale?" is asked precisely when nothing is connected. */
164
+ .status-version {
165
+ display: flex;
166
+ align-items: center;
167
+ padding-left: 17px; /* same optical alignment as .status-meta */
168
+ font-size: 9px;
169
+ color: var(--figma-color-text-secondary, rgba(255, 255, 255, 0.5));
170
+ white-space: nowrap;
171
+ }
172
+
161
173
  /* Visible recovery instruction for the ERROR state */
162
174
  .status-error-hint {
163
175
  display: none; /* shown from JS while in the error state */
@@ -484,6 +496,9 @@
484
496
  <span id="status-last-action"></span>
485
497
  </div>
486
498
 
499
+ <!-- Build versions — imported plugin files + the sidecar they talk to -->
500
+ <div class="status-version" id="status-version" title="Plugin = the files imported into Figma. Server = the npx sidecar this plugin is connected to."></div>
501
+
487
502
  <!-- Visible recovery instruction, shown only in the error state -->
488
503
  <div class="status-error-hint" id="status-error-hint">Close this window and reopen the plugin.</div>
489
504
 
@@ -601,6 +616,25 @@
601
616
  if (hint) hint.style.display = bridgeError ? 'block' : 'none';
602
617
 
603
618
  renderStatusMeta(live);
619
+ renderVersionLine();
620
+ }
621
+
622
+ // Build-version line under the meta row. Two independently-versioned
623
+ // halves, so both are labelled rather than merged into one number:
624
+ // Plugin — figma-desktop-bridge/code.js, cached by Figma at import time
625
+ // and only bumped on releases that actually touch plugin files
626
+ // Server — the npx sidecar's package version, learned over the wire
627
+ // Either can be unknown: the plugin version arrives from code.js ~500ms
628
+ // after open, the server version only once a connection lands. An unknown
629
+ // half renders "—" rather than a stale or guessed number.
630
+ function renderVersionLine() {
631
+ var el = document.getElementById('status-version');
632
+ if (!el) return;
633
+ var server = (typeof window.__wsServerVersion === 'function')
634
+ ? window.__wsServerVersion()
635
+ : null;
636
+ el.textContent = 'Plugin ' + (PLUGIN_VERSION || '—') +
637
+ ' · Server ' + (server ? 'v' + server : '—');
604
638
  }
605
639
 
606
640
  // Small always-visible line under the pill: "Connected to N AI app(s)"
@@ -1490,8 +1524,16 @@
1490
1524
  return;
1491
1525
  }
1492
1526
 
1493
- // Call the handler with a safety timeout, then send back the result
1494
- var HANDLER_TIMEOUT_MS = 30000;
1527
+ // Call the handler with a safety timeout, then send back the result.
1528
+ // The server includes each command's real budget as timeoutMs
1529
+ // (see websocket-server.ts sendCommand); race against that plus a
1530
+ // 5s margin so the command's own wrapper timeout — which produces
1531
+ // the method-specific error — always fires first. No field (older
1532
+ // server) or an invalid value falls back to the old 30s default.
1533
+ var requestedBudget = (typeof message.timeoutMs === 'number' && isFinite(message.timeoutMs) && message.timeoutMs > 0)
1534
+ ? message.timeoutMs
1535
+ : null;
1536
+ var HANDLER_TIMEOUT_MS = requestedBudget ? Math.min(requestedBudget + 5000, 310000) : 30000;
1495
1537
  var handlerSettled = false;
1496
1538
  var handlerTimeoutId = null;
1497
1539
  var handlerPromise = Promise.resolve(handler(message.params || {}));
@@ -1658,6 +1700,17 @@
1658
1700
  // The health discovery loop is armed whenever the user hasn't paused —
1659
1701
  // used by the status pill to show "Looking for your AI app…" honestly.
1660
1702
  window.__wsIsDiscoveryActive = function() { return !userPaused; };
1703
+ // Version of the server we're actually attached to, for the version
1704
+ // line. Reads from the first LIVE connection so a stale entry that
1705
+ // hasn't been reaped yet can't report a version we're no longer using.
1706
+ // Null when nothing is connected — the line then renders "Server —".
1707
+ window.__wsServerVersion = function() {
1708
+ for (var i = 0; i < activeConnections.length; i++) {
1709
+ var c = activeConnections[i];
1710
+ if (c.ws.readyState === 1 && c.serverVersion) return c.serverVersion;
1711
+ }
1712
+ return null;
1713
+ };
1661
1714
 
1662
1715
  // ======================================================================
1663
1716
  // HTTP /health DISCOVERY LOOP — replaces the old zero-connection-gated
@@ -1909,7 +1962,13 @@
1909
1962
  // STAGE 2 — LOG PANEL, INFO PANEL, CONNECTION, CLIPBOARD EXPORT
1910
1963
  // ============================================================================
1911
1964
 
1912
- var PLUGIN_VERSION = 'v0.3.0';
1965
+ // Populated from code.js's own PLUGIN_VERSION via GET_FILE_INFO_RESULT
1966
+ // (fired unconditionally ~500ms after open, so it does not need a server
1967
+ // connection). Deliberately starts null rather than a hardcoded literal:
1968
+ // a literal here is not touched by scripts/release.sh, and the last one
1969
+ // drifted to the package version (0.3.0) while code.js reported the
1970
+ // plugin version (1.35.0) — two different numbers for the same field.
1971
+ var PLUGIN_VERSION = null;
1913
1972
  var logHistory = [];
1914
1973
  var logEntriesEl = null;
1915
1974
  var _ctaBtn = null;
@@ -1977,7 +2036,7 @@
1977
2036
  });
1978
2037
  var text = 'Figma Desktop Bridge - Session Log\n'
1979
2038
  + 'Exported: ' + new Date().toISOString() + '\n'
1980
- + 'Plugin: ' + PLUGIN_VERSION + '\n'
2039
+ + 'Plugin: ' + (PLUGIN_VERSION || 'unknown') + '\n'
1981
2040
  + '------------------------------------------------\n'
1982
2041
  + lines.join('\n') + '\n';
1983
2042
  var ta = document.createElement('textarea');
@@ -2229,6 +2288,11 @@
2229
2288
  if (_ctaBtn.style.display === 'none') _ctaBtn.style.display = '';
2230
2289
  }
2231
2290
 
2291
+ // Paint the version line once up front so its row reserves height before
2292
+ // the first reconcile tick, instead of popping in and reflowing the
2293
+ // auto-sized plugin window at 500ms.
2294
+ renderVersionLine();
2295
+
2232
2296
  // Periodic reconcile of CTA + status pill/meta (cheap, <1ms). Also
2233
2297
  // refreshes "Last action: Xs ago" via renderStatusMeta inside
2234
2298
  // deriveAndRenderStatus.
@@ -2238,9 +2302,11 @@
2238
2302
  }, 2000);
2239
2303
 
2240
2304
  // One-shot on first ready: render honest initial state and capture the
2241
- // plugin's own version (used in the Activity export header) without
2242
- // logging a command line — hence the unwrapped sender. The version is
2243
- // read from the GET_FILE_INFO_RESULT handler below.
2305
+ // plugin's own version (shown in the version line and the Activity export
2306
+ // header) without logging a command line — hence the unwrapped sender.
2307
+ // The version is read from the GET_FILE_INFO_RESULT handler below. This
2308
+ // fires regardless of connection state, which is what lets the version
2309
+ // line show the plugin half while no server is attached.
2244
2310
  setTimeout(function() {
2245
2311
  reconcileCta();
2246
2312
  deriveAndRenderStatus();
@@ -2707,6 +2773,9 @@
2707
2773
  var fileInfo = msg.fileInfo || msg.data;
2708
2774
  if (fileInfo && fileInfo.pluginVersion) {
2709
2775
  PLUGIN_VERSION = 'v' + fileInfo.pluginVersion;
2776
+ // Paint immediately instead of waiting up to 2s for the next
2777
+ // reconcile tick — this is the first moment the version is known.
2778
+ if (typeof renderVersionLine === 'function') renderVersionLine();
2710
2779
  }
2711
2780
  handleResult('GET_FILE_INFO', 'fileInfo');
2712
2781
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muloka/figma-console-mcp",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "forkedFrom": {
5
5
  "name": "figma-console-mcp",
6
6
  "version": "1.36.0",
@@ -1,58 +0,0 @@
1
- /**
2
- * Browser Manager Interface
3
- * Abstract interface for browser automation across different runtimes
4
- */
5
- /**
6
- * Result of a navigateToFigma call indicating what action was taken
7
- */
8
- export interface NavigationResult {
9
- page: any;
10
- action: 'switched_to_existing' | 'navigated';
11
- url: string;
12
- }
13
- /**
14
- * Browser Manager Interface
15
- * Provides unified API for browser automation regardless of runtime (Cloudflare/Local)
16
- *
17
- * Note: Uses 'any' for Page type to support both puppeteer-core and @cloudflare/puppeteer
18
- * implementations which have incompatible type definitions but compatible runtime behavior
19
- */
20
- export interface IBrowserManager {
21
- /**
22
- * Launch or connect to browser instance
23
- */
24
- launch(): Promise<void>;
25
- /**
26
- * Get active page instance
27
- */
28
- getPage(): Promise<any>;
29
- /**
30
- * Navigate to Figma URL
31
- */
32
- navigateToFigma(url?: string): Promise<NavigationResult>;
33
- /**
34
- * Reload current page
35
- */
36
- reload(hardReload?: boolean): Promise<void>;
37
- /**
38
- * Evaluate JavaScript in page context
39
- */
40
- evaluate<T>(fn: () => T): Promise<T>;
41
- /**
42
- * Check if browser is running
43
- */
44
- isRunning(): boolean;
45
- /**
46
- * Close browser instance
47
- */
48
- close(): Promise<void>;
49
- /**
50
- * Get current URL
51
- */
52
- getCurrentUrl(): string | null;
53
- /**
54
- * Wait for navigation to complete
55
- */
56
- waitForNavigation(timeout?: number): Promise<void>;
57
- }
58
- //# sourceMappingURL=base.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/browser/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,GAAG,CAAC;IACV,MAAM,EAAE,sBAAsB,GAAG,WAAW,CAAC;IAC7C,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;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,gBAAgB,CAAC,CAAC;IAEzD;;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"}
@@ -1,6 +0,0 @@
1
- /**
2
- * Browser Manager Interface
3
- * Abstract interface for browser automation across different runtimes
4
- */
5
- export {};
6
- //# sourceMappingURL=base.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/browser/base.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -1,87 +0,0 @@
1
- /**
2
- * Local Browser Manager (Legacy)
3
- * Note: This module is maintained for backwards compatibility but is no longer
4
- * the primary connection method. Use the WebSocket Desktop Bridge plugin instead.
5
- */
6
- import { type Page } from 'puppeteer-core';
7
- import type { IBrowserManager, NavigationResult } from './base.js';
8
- /**
9
- * Local browser configuration
10
- */
11
- export interface LocalBrowserConfig {
12
- debugPort: number;
13
- debugHost: string;
14
- }
15
- /**
16
- * Local Browser Manager
17
- * Connects to existing Figma Desktop instance via remote debugging port
18
- */
19
- export declare class LocalBrowserManager implements IBrowserManager {
20
- private browser;
21
- private page;
22
- private config;
23
- constructor(config: LocalBrowserConfig);
24
- /**
25
- * Connect to Figma Desktop via remote debugging port
26
- */
27
- launch(): Promise<void>;
28
- /**
29
- * Find the best page for plugin debugging
30
- * Actively searches for pages with workers across ALL tabs
31
- */
32
- private findBestPage;
33
- /**
34
- * Find an existing browser tab whose URL matches the given Figma file key
35
- */
36
- private findPageByFileKey;
37
- /**
38
- * Get active Figma page or create new one
39
- * Prefers pages with active plugin workers for plugin debugging
40
- */
41
- getPage(): Promise<Page>;
42
- /**
43
- * Navigate to Figma URL
44
- * If the target file is already open in a tab, switches to it instead of navigating.
45
- */
46
- navigateToFigma(figmaUrl?: string): Promise<NavigationResult>;
47
- /**
48
- * Reload current page
49
- */
50
- reload(hardReload?: boolean): Promise<void>;
51
- /**
52
- * Execute JavaScript in page context
53
- */
54
- evaluate<T>(fn: () => T): Promise<T>;
55
- /**
56
- * Check if browser is connected
57
- */
58
- isRunning(): boolean;
59
- /**
60
- * Disconnect from browser (doesn't close Figma Desktop)
61
- */
62
- close(): Promise<void>;
63
- /**
64
- * Get current page URL
65
- */
66
- getCurrentUrl(): string | null;
67
- /**
68
- * Check if the browser connection is still alive
69
- * Returns false if connection is stale (e.g., after computer sleep)
70
- */
71
- isConnectionAlive(): Promise<boolean>;
72
- /**
73
- * Reconnect to Figma Desktop if connection was lost
74
- * Call this before any operation that requires a live connection
75
- */
76
- ensureConnection(): Promise<void>;
77
- /**
78
- * Force a complete reconnection to Figma Desktop
79
- * Use this when frames become detached or stale even though the browser appears connected
80
- */
81
- forceReconnect(): Promise<void>;
82
- /**
83
- * Wait for navigation
84
- */
85
- waitForNavigation(timeout?: number): Promise<void>;
86
- }
87
- //# sourceMappingURL=local.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/browser/local.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAkB,EAAgB,KAAK,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAInE;;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;IAuC7B;;;OAGG;YACW,YAAY;IA4C1B;;OAEG;YACW,iBAAiB;IAuB/B;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyC9B;;;OAGG;IACG,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAsCnE;;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"}