@createlex/figma-swiftui-mcp 1.0.8 → 1.0.9

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.
@@ -30,6 +30,8 @@ const BRIDGE_HTTP_URL = process.env.FIGMA_SWIFTUI_BRIDGE_HTTP_URL || 'http://loc
30
30
  const BRIDGE_WS_URL = process.env.FIGMA_SWIFTUI_BRIDGE_WS_URL || 'ws://localhost:7765/bridge';
31
31
  const REQUEST_TIMEOUT_MS = Number(process.env.FIGMA_SWIFTUI_BRIDGE_TIMEOUT_MS || 30000);
32
32
  const AUTH_REVALIDATION_INTERVAL_MS = Number(process.env.FIGMA_SWIFTUI_AUTH_REVALIDATION_MS || (10 * 60 * 1000));
33
+ const RESPONSE_SIZE_CAP = Number(process.env.FIGMA_SWIFTUI_RESPONSE_SIZE_CAP || 102400); // 100 KB default
34
+ const MAX_DIAGNOSTICS = 20;
33
35
 
34
36
  let bridgeSocket = null;
35
37
  let connectPromise = null;
@@ -666,7 +668,7 @@ server.registerTool('write_generated_swiftui_to_xcode', {
666
668
  }
667
669
 
668
670
  return jsonResult({
669
- ...result,
671
+ ...stripImageData(result),
670
672
  structName: effectiveStructName,
671
673
  });
672
674
  });
@@ -739,16 +741,125 @@ server.registerTool('write_selection_to_xcode', {
739
741
  filePath: result.results?.swiftFile ?? null,
740
742
  });
741
743
 
742
- return jsonResult({
743
- ...result,
744
+ return jsonResult(buildCompactResponse({
745
+ result,
744
746
  structName: effectiveStructName,
745
747
  selection: generated.selection ?? null,
746
748
  diagnostics: generated.diagnostics ?? [],
747
749
  refinementInstructions,
748
- ...(analysisHints ? { analysisHints } : {}),
749
- });
750
+ analysisHints,
751
+ }));
750
752
  });
751
753
 
754
+ // ---------------------------------------------------------------------------
755
+ // Response-size mitigation helpers
756
+ // ---------------------------------------------------------------------------
757
+
758
+ /**
759
+ * Remove base64 / svg binary data from any image results.
760
+ * Files are already on disk — the model only needs names and paths.
761
+ */
762
+ function stripImageData(obj) {
763
+ if (!obj || typeof obj !== 'object') return obj;
764
+
765
+ // Deep-clone to avoid mutating the original
766
+ const clone = JSON.parse(JSON.stringify(obj));
767
+
768
+ const walk = (node) => {
769
+ if (Array.isArray(node)) {
770
+ node.forEach(walk);
771
+ return;
772
+ }
773
+ if (node && typeof node === 'object') {
774
+ delete node.base64;
775
+ delete node.svg;
776
+ delete node.data;
777
+ for (const value of Object.values(node)) {
778
+ walk(value);
779
+ }
780
+ }
781
+ };
782
+
783
+ walk(clone);
784
+ return clone;
785
+ }
786
+
787
+ /**
788
+ * Cap the diagnostics array, prioritising rasterized nodes first.
789
+ */
790
+ function capDiagnostics(diagnostics) {
791
+ if (!Array.isArray(diagnostics) || diagnostics.length <= MAX_DIAGNOSTICS) {
792
+ return diagnostics;
793
+ }
794
+
795
+ // Sort: rasterized nodes first (most useful for refinement)
796
+ const sorted = [...diagnostics].sort((a, b) => {
797
+ const aRaster = a.rasterized || a.reason?.toLowerCase().includes('raster') ? 1 : 0;
798
+ const bRaster = b.rasterized || b.reason?.toLowerCase().includes('raster') ? 1 : 0;
799
+ return bRaster - aRaster;
800
+ });
801
+
802
+ const kept = sorted.slice(0, MAX_DIAGNOSTICS);
803
+ kept.push({
804
+ _truncated: true,
805
+ totalCount: diagnostics.length,
806
+ shownCount: MAX_DIAGNOSTICS,
807
+ message: `${diagnostics.length - MAX_DIAGNOSTICS} additional diagnostic(s) omitted to reduce response size.`,
808
+ });
809
+ return kept;
810
+ }
811
+
812
+ /**
813
+ * Build a compact MCP response for write_selection_to_xcode.
814
+ *
815
+ * Strategy:
816
+ * 1. Strip all binary (base64/svg) data from image results.
817
+ * 2. Cap diagnostics to MAX_DIAGNOSTICS most relevant entries.
818
+ * 3. Estimate serialised size; if still over RESPONSE_SIZE_CAP,
819
+ * compress analysis hints to summary-only.
820
+ */
821
+ function buildCompactResponse({ result, structName, selection, diagnostics, refinementInstructions, analysisHints }) {
822
+ const compact = {
823
+ ...stripImageData(result),
824
+ structName,
825
+ selection,
826
+ diagnostics: capDiagnostics(diagnostics),
827
+ refinementInstructions,
828
+ ...(analysisHints ? { analysisHints } : {}),
829
+ };
830
+
831
+ // First size check
832
+ let serialised = JSON.stringify(compact);
833
+ if (serialised.length <= RESPONSE_SIZE_CAP) {
834
+ return compact;
835
+ }
836
+
837
+ // Compress: remove verbose analysis hints, keep only summary-level data
838
+ if (compact.analysisHints) {
839
+ const { generationHints, manualRefinementHints, ...rest } = compact.analysisHints;
840
+ compact.analysisHints = {
841
+ ...rest,
842
+ _compressed: true,
843
+ generationHintCount: generationHints?.interactiveElements?.length ?? 0,
844
+ manualRefinementHintCount: manualRefinementHints?.length ?? 0,
845
+ };
846
+ }
847
+
848
+ // Second size check — drop the full Swift code echo if still too large
849
+ serialised = JSON.stringify(compact);
850
+ if (serialised.length > RESPONSE_SIZE_CAP && compact.results?.swiftFile) {
851
+ // The code is already on disk at swiftFile; no need to echo it
852
+ if (compact.results) {
853
+ compact.results = { ...compact.results };
854
+ delete compact.results.code;
855
+ }
856
+ compact._responseCapped = true;
857
+ compact._responseNote = `Response was compressed to stay under ${Math.round(RESPONSE_SIZE_CAP / 1024)}KB. All files were written successfully to disk.`;
858
+ }
859
+
860
+ return compact;
861
+ }
862
+
752
863
  function buildRefinementInstructions({ diagnostics, rasterNodes, analysisHints, structName, filePath }) {
753
864
  const instructions = [];
754
865
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "figma-swiftui-companion",
3
- "version": "1.0.0",
3
+ "version": "1.0.9",
4
4
  "description": "Local server that writes Figma-generated SwiftUI code and images into an Xcode project",
5
5
  "main": "server.js",
6
6
  "scripts": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@createlex/figma-swiftui-mcp",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "CreateLex MCP runtime for Figma-to-SwiftUI generation and Xcode export",
5
5
  "bin": {
6
6
  "figma-swiftui-mcp": "bin/figma-swiftui-mcp.js"