sonance-brand-mcp 1.3.55 → 1.3.56

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.
@@ -686,8 +686,9 @@ export async function POST(request: Request) {
686
686
  const messageContent: Anthropic.MessageCreateParams["messages"][0]["content"] = [];
687
687
 
688
688
  // Add screenshot if provided
689
+ let base64Data = "";
689
690
  if (screenshot) {
690
- const base64Data = screenshot.split(",")[1] || screenshot;
691
+ base64Data = screenshot.split(",")[1] || screenshot;
691
692
  messageContent.push({
692
693
  type: "image",
693
694
  source: {
@@ -698,6 +699,111 @@ export async function POST(request: Request) {
698
699
  });
699
700
  }
700
701
 
702
+ // ========== PHASE A: VISUAL PROBLEM ANALYSIS ==========
703
+ // Before generating patches, analyze WHAT is visually wrong
704
+ // This forces the LLM to articulate the problem before trying to fix it
705
+ interface VisualAnalysis {
706
+ element: string;
707
+ problem: string;
708
+ currentState: string;
709
+ solution: string;
710
+ confidence: "high" | "medium" | "low";
711
+ }
712
+
713
+ let visualAnalysis: VisualAnalysis | null = null;
714
+
715
+ if (screenshot && userPrompt) {
716
+ debugLog("Phase A: Starting visual problem analysis");
717
+
718
+ const analysisClient = new Anthropic({ apiKey });
719
+
720
+ try {
721
+ const analysisResponse = await analysisClient.messages.create({
722
+ model: "claude-sonnet-4-20250514",
723
+ max_tokens: 1024,
724
+ messages: [
725
+ {
726
+ role: "user",
727
+ content: [
728
+ {
729
+ type: "image",
730
+ source: {
731
+ type: "base64",
732
+ media_type: "image/png",
733
+ data: base64Data,
734
+ },
735
+ },
736
+ {
737
+ type: "text",
738
+ text: `You are analyzing a UI screenshot to understand a visual problem.
739
+
740
+ User request: "${userPrompt}"
741
+
742
+ ${focusedElements && focusedElements.length > 0 ? `User clicked on these elements:
743
+ ${focusedElements.map((el) => `- ${el.name} (${el.type}) at position (${el.coordinates.x}, ${el.coordinates.y})`).join("\n")}
744
+ ` : ""}
745
+
746
+ BEFORE any code changes can be made, you must analyze the visual problem.
747
+
748
+ Answer these questions:
749
+ 1. ELEMENT: Which specific UI element has the problem? (describe its location, text content, appearance)
750
+ 2. PROBLEM: What exactly is visually wrong? (invisible text, wrong color, poor contrast, wrong size, etc.)
751
+ 3. CURRENT STATE: What styling/colors appear to be applied to this element?
752
+ 4. SOLUTION: What specific CSS/Tailwind change would fix this problem?
753
+ 5. CONFIDENCE: How confident are you that you've identified the correct element and problem? (high/medium/low)
754
+
755
+ Return ONLY valid JSON with no other text:
756
+ {
757
+ "element": "specific description of the UI element",
758
+ "problem": "what is visually wrong",
759
+ "currentState": "what styling appears to be applied",
760
+ "solution": "specific CSS/Tailwind fix needed",
761
+ "confidence": "high"
762
+ }`,
763
+ },
764
+ ],
765
+ },
766
+ ],
767
+ });
768
+
769
+ const analysisText = analysisResponse.content.find((block) => block.type === "text");
770
+ if (analysisText && analysisText.type === "text") {
771
+ // Parse the JSON response
772
+ let jsonText = analysisText.text.trim();
773
+ // Extract JSON if wrapped in code blocks
774
+ const jsonMatch = jsonText.match(/```(?:json)?\s*([\s\S]*?)\s*```/) || jsonText.match(/(\{[\s\S]*\})/);
775
+ if (jsonMatch) {
776
+ jsonText = jsonMatch[1];
777
+ }
778
+
779
+ try {
780
+ visualAnalysis = JSON.parse(jsonText) as VisualAnalysis;
781
+ debugLog("Phase A: Visual problem analysis complete", visualAnalysis);
782
+
783
+ // If low confidence, return early with clarification request
784
+ if (visualAnalysis.confidence === "low") {
785
+ debugLog("Phase A: Low confidence - requesting clarification");
786
+ return NextResponse.json({
787
+ success: false,
788
+ needsClarification: true,
789
+ analysis: visualAnalysis,
790
+ message: `I can see "${visualAnalysis.element}" but I'm not certain about the problem: "${visualAnalysis.problem}". Can you be more specific about what needs to change?`,
791
+ });
792
+ }
793
+ } catch (parseError) {
794
+ debugLog("Phase A: Failed to parse analysis response", {
795
+ error: String(parseError),
796
+ response: jsonText.substring(0, 500)
797
+ });
798
+ // Continue without analysis if parsing fails
799
+ }
800
+ }
801
+ } catch (analysisError) {
802
+ debugLog("Phase A: Analysis call failed", { error: String(analysisError) });
803
+ // Continue without analysis - fall back to existing behavior
804
+ }
805
+ }
806
+
701
807
  // ========== SMART CONTEXT BUDGETING ==========
702
808
  // Claude can handle 200k tokens (~800k chars), so we can safely include large files
703
809
  // Priority: Recommended file (NEVER truncate) > Page file (limited) > Other components (dynamic)
@@ -731,6 +837,24 @@ User Request: "${userPrompt}"
731
837
  textContent += `FOCUSED ELEMENTS (user clicked on these):
732
838
  ${focusedElements.map((el) => `- ${el.name} (${el.type}) at (${el.coordinates.x}, ${el.coordinates.y})`).join("\n")}
733
839
 
840
+ `;
841
+ }
842
+
843
+ // ========== VISUAL PROBLEM ANALYSIS (from Phase A) ==========
844
+ if (visualAnalysis) {
845
+ textContent += `═══════════════════════════════════════════════════════════════════════════════
846
+ 🔍 VISUAL PROBLEM ANALYSIS (I analyzed the screenshot first)
847
+ ═══════════════════════════════════════════════════════════════════════════════
848
+
849
+ **Element:** ${visualAnalysis.element}
850
+ **Problem:** ${visualAnalysis.problem}
851
+ **Current State:** ${visualAnalysis.currentState}
852
+ **Required Fix:** ${visualAnalysis.solution}
853
+ **Confidence:** ${visualAnalysis.confidence}
854
+
855
+ ⚠️ IMPORTANT: Your patches MUST implement the fix described above for the element described above.
856
+ Find the code that renders "${visualAnalysis.element}" and apply "${visualAnalysis.solution}".
857
+
734
858
  `;
735
859
  }
736
860
 
@@ -695,8 +695,9 @@ export async function POST(request: Request) {
695
695
  const messageContent: Anthropic.MessageCreateParams["messages"][0]["content"] = [];
696
696
 
697
697
  // Add screenshot if provided
698
+ let base64Data = "";
698
699
  if (screenshot) {
699
- const base64Data = screenshot.split(",")[1] || screenshot;
700
+ base64Data = screenshot.split(",")[1] || screenshot;
700
701
  messageContent.push({
701
702
  type: "image",
702
703
  source: {
@@ -707,6 +708,111 @@ export async function POST(request: Request) {
707
708
  });
708
709
  }
709
710
 
711
+ // ========== PHASE A: VISUAL PROBLEM ANALYSIS ==========
712
+ // Before generating patches, analyze WHAT is visually wrong
713
+ // This forces the LLM to articulate the problem before trying to fix it
714
+ interface VisualAnalysis {
715
+ element: string;
716
+ problem: string;
717
+ currentState: string;
718
+ solution: string;
719
+ confidence: "high" | "medium" | "low";
720
+ }
721
+
722
+ let visualAnalysis: VisualAnalysis | null = null;
723
+
724
+ if (screenshot && userPrompt) {
725
+ debugLog("Phase A: Starting visual problem analysis");
726
+
727
+ const analysisClient = new Anthropic({ apiKey });
728
+
729
+ try {
730
+ const analysisResponse = await analysisClient.messages.create({
731
+ model: "claude-sonnet-4-20250514",
732
+ max_tokens: 1024,
733
+ messages: [
734
+ {
735
+ role: "user",
736
+ content: [
737
+ {
738
+ type: "image",
739
+ source: {
740
+ type: "base64",
741
+ media_type: "image/png",
742
+ data: base64Data,
743
+ },
744
+ },
745
+ {
746
+ type: "text",
747
+ text: `You are analyzing a UI screenshot to understand a visual problem.
748
+
749
+ User request: "${userPrompt}"
750
+
751
+ ${focusedElements && focusedElements.length > 0 ? `User clicked on these elements:
752
+ ${focusedElements.map((el) => `- ${el.name} (${el.type}) at position (${el.coordinates.x}, ${el.coordinates.y})`).join("\n")}
753
+ ` : ""}
754
+
755
+ BEFORE any code changes can be made, you must analyze the visual problem.
756
+
757
+ Answer these questions:
758
+ 1. ELEMENT: Which specific UI element has the problem? (describe its location, text content, appearance)
759
+ 2. PROBLEM: What exactly is visually wrong? (invisible text, wrong color, poor contrast, wrong size, etc.)
760
+ 3. CURRENT STATE: What styling/colors appear to be applied to this element?
761
+ 4. SOLUTION: What specific CSS/Tailwind change would fix this problem?
762
+ 5. CONFIDENCE: How confident are you that you've identified the correct element and problem? (high/medium/low)
763
+
764
+ Return ONLY valid JSON with no other text:
765
+ {
766
+ "element": "specific description of the UI element",
767
+ "problem": "what is visually wrong",
768
+ "currentState": "what styling appears to be applied",
769
+ "solution": "specific CSS/Tailwind fix needed",
770
+ "confidence": "high"
771
+ }`,
772
+ },
773
+ ],
774
+ },
775
+ ],
776
+ });
777
+
778
+ const analysisText = analysisResponse.content.find((block) => block.type === "text");
779
+ if (analysisText && analysisText.type === "text") {
780
+ // Parse the JSON response
781
+ let jsonText = analysisText.text.trim();
782
+ // Extract JSON if wrapped in code blocks
783
+ const jsonMatch = jsonText.match(/```(?:json)?\s*([\s\S]*?)\s*```/) || jsonText.match(/(\{[\s\S]*\})/);
784
+ if (jsonMatch) {
785
+ jsonText = jsonMatch[1];
786
+ }
787
+
788
+ try {
789
+ visualAnalysis = JSON.parse(jsonText) as VisualAnalysis;
790
+ debugLog("Phase A: Visual problem analysis complete", visualAnalysis);
791
+
792
+ // If low confidence, return early with clarification request
793
+ if (visualAnalysis.confidence === "low") {
794
+ debugLog("Phase A: Low confidence - requesting clarification");
795
+ return NextResponse.json({
796
+ success: false,
797
+ needsClarification: true,
798
+ analysis: visualAnalysis,
799
+ message: `I can see "${visualAnalysis.element}" but I'm not certain about the problem: "${visualAnalysis.problem}". Can you be more specific about what needs to change?`,
800
+ });
801
+ }
802
+ } catch (parseError) {
803
+ debugLog("Phase A: Failed to parse analysis response", {
804
+ error: String(parseError),
805
+ response: jsonText.substring(0, 500)
806
+ });
807
+ // Continue without analysis if parsing fails
808
+ }
809
+ }
810
+ } catch (analysisError) {
811
+ debugLog("Phase A: Analysis call failed", { error: String(analysisError) });
812
+ // Continue without analysis - fall back to existing behavior
813
+ }
814
+ }
815
+
710
816
  // ========== SMART CONTEXT BUDGETING ==========
711
817
  // Claude can handle 200k tokens (~800k chars), so we can safely include large files
712
818
  // Priority: Recommended file (NEVER truncate) > Page file (limited) > Other components (dynamic)
@@ -740,6 +846,24 @@ User Request: "${userPrompt}"
740
846
  textContent += `FOCUSED ELEMENTS (user clicked on these):
741
847
  ${focusedElements.map((el) => `- ${el.name} (${el.type}) at (${el.coordinates.x}, ${el.coordinates.y})`).join("\n")}
742
848
 
849
+ `;
850
+ }
851
+
852
+ // ========== VISUAL PROBLEM ANALYSIS (from Phase A) ==========
853
+ if (visualAnalysis) {
854
+ textContent += `═══════════════════════════════════════════════════════════════════════════════
855
+ 🔍 VISUAL PROBLEM ANALYSIS (I analyzed the screenshot first)
856
+ ═══════════════════════════════════════════════════════════════════════════════
857
+
858
+ **Element:** ${visualAnalysis.element}
859
+ **Problem:** ${visualAnalysis.problem}
860
+ **Current State:** ${visualAnalysis.currentState}
861
+ **Required Fix:** ${visualAnalysis.solution}
862
+ **Confidence:** ${visualAnalysis.confidence}
863
+
864
+ ⚠️ IMPORTANT: Your patches MUST implement the fix described above for the element described above.
865
+ Find the code that renders "${visualAnalysis.element}" and apply "${visualAnalysis.solution}".
866
+
743
867
  `;
744
868
  }
745
869
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonance-brand-mcp",
3
- "version": "1.3.55",
3
+ "version": "1.3.56",
4
4
  "description": "MCP Server for Sonance Brand Guidelines and Component Library - gives Claude instant access to brand colors, typography, and UI components.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",