@createlex/figma-swiftui-mcp 1.0.7 → 1.0.8

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.
@@ -672,7 +672,7 @@ server.registerTool('write_generated_swiftui_to_xcode', {
672
672
  });
673
673
 
674
674
  server.registerTool('write_selection_to_xcode', {
675
- description: 'Generate SwiftUI from the connected Figma selection and write it directly into the configured Xcode project.',
675
+ description: 'Generate SwiftUI from the connected Figma selection, write it into the configured Xcode project, and return refinement hints. After writing, the AI assistant SHOULD automatically apply the returned refinementInstructions to make the generated code adaptive and interactive — replacing raster placeholders with native SwiftUI controls, adding GeometryReader for adaptive layout, and wiring basic interactions.',
676
676
  inputSchema: {
677
677
  nodeIds: z.array(z.string()).optional().describe('Optional list of Figma node ids. If omitted, uses the current selection'),
678
678
  includeOverflow: z.boolean().default(false).describe('Ignore Figma clipping when generating layout'),
@@ -681,6 +681,29 @@ server.registerTool('write_selection_to_xcode', {
681
681
  },
682
682
  }, async ({ nodeIds, includeOverflow, generationMode, projectPath }) => {
683
683
  const targetDir = resolveTargetProjectPath(projectPath);
684
+
685
+ // Try hosted analysis first to get refinement hints alongside code
686
+ let analysisHints = null;
687
+ try {
688
+ const analysis = await tryHostedSemanticGeneration({
689
+ nodeIds,
690
+ generationMode,
691
+ includeOverflow,
692
+ analyze: true,
693
+ });
694
+ if (analysis) {
695
+ analysisHints = {
696
+ generationHints: analysis.generationHints,
697
+ manualRefinementHints: analysis.manualRefinementHints,
698
+ reusableComponents: analysis.reusableComponents,
699
+ assetExportPlan: analysis.assetExportPlan,
700
+ };
701
+ }
702
+ } catch (err) {
703
+ // Non-fatal — continue with generation even if analysis fails
704
+ console.error('[figma-swiftui-mcp] Hosted analysis failed (non-fatal):', err?.message ?? err);
705
+ }
706
+
684
707
  const generated = await callBridge('generate_swiftui', {
685
708
  nodeIds,
686
709
  includeOverflow,
@@ -704,14 +727,83 @@ server.registerTool('write_selection_to_xcode', {
704
727
  throw new Error(result.results.errors.join(' | ') || 'Failed to write generated selection to Xcode');
705
728
  }
706
729
 
730
+ // Build refinement instructions from diagnostics and hints
731
+ const rasterNodes = (generated.diagnostics ?? []).filter(
732
+ (d) => d.rasterized || d.reason?.toLowerCase().includes('raster')
733
+ );
734
+ const refinementInstructions = buildRefinementInstructions({
735
+ diagnostics: generated.diagnostics ?? [],
736
+ rasterNodes,
737
+ analysisHints,
738
+ structName: effectiveStructName,
739
+ filePath: result.results?.swiftFile ?? null,
740
+ });
741
+
707
742
  return jsonResult({
708
743
  ...result,
709
744
  structName: effectiveStructName,
710
745
  selection: generated.selection ?? null,
711
746
  diagnostics: generated.diagnostics ?? [],
747
+ refinementInstructions,
748
+ ...(analysisHints ? { analysisHints } : {}),
712
749
  });
713
750
  });
714
751
 
752
+ function buildRefinementInstructions({ diagnostics, rasterNodes, analysisHints, structName, filePath }) {
753
+ const instructions = [];
754
+
755
+ // Adaptive layout
756
+ instructions.push(
757
+ `Make ${structName} adaptive: replace any fixed .frame(width:height:) on the root body with GeometryReader or .frame(maxWidth: .infinity, maxHeight: .infinity) so the screen fills any device.`
758
+ );
759
+
760
+ // Raster replacements
761
+ if (rasterNodes.length > 0) {
762
+ instructions.push(
763
+ `${rasterNodes.length} element(s) were exported as raster images because Figma could not map them to native SwiftUI. Review these and replace obvious UI controls (buttons, text fields, toggles, tab bars) with native SwiftUI equivalents. Keep actual images/illustrations as Image assets.`
764
+ );
765
+ }
766
+
767
+ // Hosted analysis hints
768
+ if (analysisHints?.manualRefinementHints?.length) {
769
+ for (const hint of analysisHints.manualRefinementHints) {
770
+ const text = typeof hint === 'string' ? hint : hint.description || hint.message || hint.text || hint.title || null;
771
+ if (text) {
772
+ instructions.push(text);
773
+ }
774
+ }
775
+ }
776
+
777
+ if (analysisHints?.generationHints?.interactiveElements?.length) {
778
+ const names = analysisHints.generationHints.interactiveElements
779
+ .map((e) => e.name || e.nodeId || e.id || '(unnamed)')
780
+ .filter(Boolean)
781
+ .join(', ');
782
+ if (names) {
783
+ instructions.push(`These elements likely need interaction: ${names}`);
784
+ }
785
+ }
786
+
787
+ // Reusable components
788
+ if (analysisHints?.reusableComponents?.length) {
789
+ const names = analysisHints.reusableComponents
790
+ .map((c) => c.name || c.componentName || c.id || '(unnamed)')
791
+ .filter(Boolean)
792
+ .join(', ');
793
+ if (names) {
794
+ instructions.push(
795
+ `Consider extracting ${analysisHints.reusableComponents.length} reusable component(s): ${names}`
796
+ );
797
+ }
798
+ }
799
+
800
+ return {
801
+ summary: `After writing ${structName}.swift, apply these refinements to make it production-ready:`,
802
+ steps: instructions,
803
+ filePath,
804
+ };
805
+ }
806
+
715
807
  async function shutdownBridgeAndExit(message, exitCode = 1) {
716
808
  console.error(message);
717
809
  if (authValidationTimer) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@createlex/figma-swiftui-mcp",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
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"