@muloka/figma-console-mcp 0.4.0 → 0.5.1

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 (109) hide show
  1. package/README.md +7 -3
  2. package/dist/core/websocket-connector.d.ts +2 -1
  3. package/dist/core/websocket-connector.d.ts.map +1 -1
  4. package/dist/core/websocket-connector.js +17 -2
  5. package/dist/core/websocket-connector.js.map +1 -1
  6. package/dist/core/websocket-server.d.ts +8 -1
  7. package/dist/core/websocket-server.d.ts.map +1 -1
  8. package/dist/core/websocket-server.js +19 -3
  9. package/dist/core/websocket-server.js.map +1 -1
  10. package/dist/core/write-tools.d.ts +3 -1
  11. package/dist/core/write-tools.d.ts.map +1 -1
  12. package/dist/core/write-tools.js +98 -23
  13. package/dist/core/write-tools.js.map +1 -1
  14. package/dist/local.d.ts +2 -1
  15. package/dist/local.d.ts.map +1 -1
  16. package/dist/local.js +5 -4
  17. package/dist/local.js.map +1 -1
  18. package/figma-desktop-bridge/code.js +57 -27
  19. package/figma-desktop-bridge/ui.html +10 -2
  20. package/package.json +1 -1
  21. package/dist/apps/design-system-dashboard/mcp-app.html +0 -521
  22. package/dist/apps/token-browser/mcp-app.html +0 -410
  23. package/dist/cloudflare/apps/design-system-dashboard/scoring/accessibility.js +0 -277
  24. package/dist/cloudflare/apps/design-system-dashboard/scoring/component-metadata.js +0 -357
  25. package/dist/cloudflare/apps/design-system-dashboard/scoring/consistency.js +0 -341
  26. package/dist/cloudflare/apps/design-system-dashboard/scoring/coverage.js +0 -230
  27. package/dist/cloudflare/apps/design-system-dashboard/scoring/engine.js +0 -92
  28. package/dist/cloudflare/apps/design-system-dashboard/scoring/naming-semantics.js +0 -308
  29. package/dist/cloudflare/apps/design-system-dashboard/scoring/token-architecture.js +0 -349
  30. package/dist/cloudflare/apps/design-system-dashboard/scoring/types.js +0 -40
  31. package/dist/cloudflare/apps/design-system-dashboard/server.js +0 -159
  32. package/dist/cloudflare/apps/token-browser/server.js +0 -136
  33. package/dist/cloudflare/browser-manager.js +0 -157
  34. package/dist/cloudflare/core/accessibility-tools.js +0 -361
  35. package/dist/cloudflare/core/annotation-tools.js +0 -230
  36. package/dist/cloudflare/core/cloud-websocket-connector.js +0 -419
  37. package/dist/cloudflare/core/cloud-websocket-relay.js +0 -198
  38. package/dist/cloudflare/core/comment-tools.js +0 -292
  39. package/dist/cloudflare/core/config.js +0 -153
  40. package/dist/cloudflare/core/console-monitor.js +0 -427
  41. package/dist/cloudflare/core/deep-component-tools.js +0 -128
  42. package/dist/cloudflare/core/design-code-tools.js +0 -2793
  43. package/dist/cloudflare/core/design-system-manifest.js +0 -265
  44. package/dist/cloudflare/core/design-system-tools.js +0 -882
  45. package/dist/cloudflare/core/diagnose-tool.js +0 -100
  46. package/dist/cloudflare/core/diff/changelog-formatter.js +0 -275
  47. package/dist/cloudflare/core/diff/diff-engine.js +0 -334
  48. package/dist/cloudflare/core/diff/property-compare.js +0 -36
  49. package/dist/cloudflare/core/diff/version-cache.js +0 -74
  50. package/dist/cloudflare/core/enrichment/enrichment-service.js +0 -374
  51. package/dist/cloudflare/core/enrichment/index.js +0 -7
  52. package/dist/cloudflare/core/enrichment/relationship-mapper.js +0 -351
  53. package/dist/cloudflare/core/enrichment/style-resolver.js +0 -346
  54. package/dist/cloudflare/core/figjam-tools.js +0 -547
  55. package/dist/cloudflare/core/figma-api.js +0 -509
  56. package/dist/cloudflare/core/figma-connector.js +0 -7
  57. package/dist/cloudflare/core/figma-reconstruction-spec.js +0 -402
  58. package/dist/cloudflare/core/figma-style-extractor.js +0 -311
  59. package/dist/cloudflare/core/figma-tools.js +0 -3353
  60. package/dist/cloudflare/core/identity.js +0 -96
  61. package/dist/cloudflare/core/library-tools.js +0 -580
  62. package/dist/cloudflare/core/logger.js +0 -53
  63. package/dist/cloudflare/core/port-discovery.js +0 -935
  64. package/dist/cloudflare/core/resolve-package-root.js +0 -11
  65. package/dist/cloudflare/core/slides-tools.js +0 -714
  66. package/dist/cloudflare/core/slot-tools.js +0 -334
  67. package/dist/cloudflare/core/snippet-injector.js +0 -96
  68. package/dist/cloudflare/core/tokens/alias-resolver.js +0 -205
  69. package/dist/cloudflare/core/tokens/config.js +0 -294
  70. package/dist/cloudflare/core/tokens/dialect.js +0 -232
  71. package/dist/cloudflare/core/tokens/figma-converter.js +0 -323
  72. package/dist/cloudflare/core/tokens/formatters/css-vars.js +0 -338
  73. package/dist/cloudflare/core/tokens/formatters/dtcg.js +0 -376
  74. package/dist/cloudflare/core/tokens/formatters/index.js +0 -45
  75. package/dist/cloudflare/core/tokens/formatters/json.js +0 -205
  76. package/dist/cloudflare/core/tokens/formatters/less.js +0 -4
  77. package/dist/cloudflare/core/tokens/formatters/scss.js +0 -258
  78. package/dist/cloudflare/core/tokens/formatters/stubs.js +0 -13
  79. package/dist/cloudflare/core/tokens/formatters/style-dictionary-v3.js +0 -213
  80. package/dist/cloudflare/core/tokens/formatters/tailwind-v3.js +0 -237
  81. package/dist/cloudflare/core/tokens/formatters/tailwind-v4.js +0 -335
  82. package/dist/cloudflare/core/tokens/formatters/tokens-studio.js +0 -256
  83. package/dist/cloudflare/core/tokens/formatters/ts-module.js +0 -198
  84. package/dist/cloudflare/core/tokens/index.js +0 -16
  85. package/dist/cloudflare/core/tokens/parsers/css-vars.js +0 -4
  86. package/dist/cloudflare/core/tokens/parsers/dtcg.js +0 -280
  87. package/dist/cloudflare/core/tokens/parsers/index.js +0 -138
  88. package/dist/cloudflare/core/tokens/parsers/json.js +0 -7
  89. package/dist/cloudflare/core/tokens/parsers/scss.js +0 -4
  90. package/dist/cloudflare/core/tokens/parsers/stubs.js +0 -20
  91. package/dist/cloudflare/core/tokens/parsers/style-dictionary-v3.js +0 -4
  92. package/dist/cloudflare/core/tokens/parsers/tailwind-v3.js +0 -4
  93. package/dist/cloudflare/core/tokens/parsers/tailwind-v4.js +0 -4
  94. package/dist/cloudflare/core/tokens/parsers/tokens-studio.js +0 -4
  95. package/dist/cloudflare/core/tokens/schemas.js +0 -152
  96. package/dist/cloudflare/core/tokens/transforms/color.js +0 -12
  97. package/dist/cloudflare/core/tokens/transforms/index.js +0 -29
  98. package/dist/cloudflare/core/tokens/transforms/size.js +0 -7
  99. package/dist/cloudflare/core/tokens/types.js +0 -18
  100. package/dist/cloudflare/core/tokens-tools.js +0 -1788
  101. package/dist/cloudflare/core/types/design-code.js +0 -4
  102. package/dist/cloudflare/core/types/enriched.js +0 -5
  103. package/dist/cloudflare/core/types/index.js +0 -4
  104. package/dist/cloudflare/core/variable-resolver.js +0 -85
  105. package/dist/cloudflare/core/version-tools.js +0 -1199
  106. package/dist/cloudflare/core/websocket-connector.js +0 -436
  107. package/dist/cloudflare/core/websocket-server.js +0 -1009
  108. package/dist/cloudflare/core/write-tools.js +0 -2506
  109. package/dist/cloudflare/index.js +0 -3010
@@ -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
  }
@@ -1524,8 +1524,16 @@
1524
1524
  return;
1525
1525
  }
1526
1526
 
1527
- // Call the handler with a safety timeout, then send back the result
1528
- 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;
1529
1537
  var handlerSettled = false;
1530
1538
  var handlerTimeoutId = null;
1531
1539
  var handlerPromise = Promise.resolve(handler(message.params || {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muloka/figma-console-mcp",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "forkedFrom": {
5
5
  "name": "figma-console-mcp",
6
6
  "version": "1.36.0",