sonance-brand-mcp 1.3.59 → 1.3.60
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.
|
@@ -511,48 +511,81 @@ function searchFilesSmart(
|
|
|
511
511
|
return sortedResults.map(r => ({ path: r.path, content: r.content, score: r.score }));
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
-
const VISION_SYSTEM_PROMPT = `You are a code editor.
|
|
514
|
+
const VISION_SYSTEM_PROMPT = `You are a code editor like Cursor. Before making changes, REASON about what needs to be done.
|
|
515
|
+
|
|
516
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
517
|
+
STEP 1: ANALYZE (Think like Cursor)
|
|
518
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
519
|
+
|
|
520
|
+
Before writing any patches, analyze the screenshot and answer:
|
|
521
|
+
|
|
522
|
+
1. CURRENT STATE: What do I see in the screenshot?
|
|
523
|
+
- Is the element visible/readable right now?
|
|
524
|
+
- What colors/styles are currently applied?
|
|
525
|
+
|
|
526
|
+
2. PROBLEM IDENTIFICATION: What's actually wrong?
|
|
527
|
+
- Contrast issue? (text blending with background)
|
|
528
|
+
- Hidden element? (not showing at all)
|
|
529
|
+
- Hover state issue? (only visible on interaction)
|
|
530
|
+
- Layout issue? (wrong size/position)
|
|
531
|
+
- Or is it already correct?
|
|
532
|
+
|
|
533
|
+
3. FIX STRATEGY: What should I change?
|
|
534
|
+
- DEFAULT state only (element needs to look different normally)
|
|
535
|
+
- HOVER state only (element needs different hover effect)
|
|
536
|
+
- BOTH states (element needs overall visibility improvement)
|
|
537
|
+
- ASK for clarification (request is too vague)
|
|
538
|
+
|
|
539
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
540
|
+
STEP 2: GENERATE PATCHES (Only after reasoning)
|
|
541
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
542
|
+
|
|
543
|
+
CRITICAL - FILE SELECTION:
|
|
544
|
+
- You MUST modify the file marked "TARGET COMPONENT" - this is the file you have FULL visibility into
|
|
545
|
+
- Do NOT try to modify other files listed in context - you only see their imports/exports, not full content
|
|
546
|
+
- If the TARGET COMPONENT is not the right file, return clarification_needed
|
|
547
|
+
|
|
548
|
+
COPY EXACTLY from the TARGET COMPONENT section:
|
|
549
|
+
- Your "search" string must match the file CHARACTER-FOR-CHARACTER
|
|
550
|
+
- Include exact indentation and at least 3 lines of context
|
|
551
|
+
- If the element looks FINE in the screenshot, say so
|
|
515
552
|
|
|
516
553
|
RULES:
|
|
517
|
-
1. Make the SMALLEST possible change
|
|
518
|
-
2. Do NOT refactor
|
|
519
|
-
3.
|
|
520
|
-
4.
|
|
521
|
-
5. If
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
- When a focused element is mentioned, SEARCH the provided file content for that EXACT element
|
|
529
|
-
- Look for the actual JSX/HTML code: <button, <Button, <div, className, onClick, etc.
|
|
530
|
-
- If you cannot find the element in the TARGET COMPONENT section, it may be in a child component
|
|
531
|
-
- NEVER guess what element code looks like - find it in the file or report "element not found"
|
|
532
|
-
- If the element is not in the provided file, return: {"modifications": [], "explanation": "The focused element appears to be in a child component, not in [filename]"}
|
|
533
|
-
|
|
534
|
-
CRITICAL - DATA INTEGRITY:
|
|
535
|
-
- If code references database values (like icon_name, type, status), DO NOT change the mapping keys
|
|
536
|
-
- You cannot see database content - only change STRUCTURE, not DATA MAPPINGS
|
|
537
|
-
- Example: If you see iconMap["EyeOff"] = SomeIcon, do NOT change "EyeOff" to something else
|
|
538
|
-
- If user wants different icons, they must tell you the EXACT icon names they want
|
|
539
|
-
|
|
540
|
-
PATCH FORMAT:
|
|
541
|
-
Return ONLY raw JSON (no markdown, no preamble):
|
|
554
|
+
1. Make the SMALLEST possible change
|
|
555
|
+
2. Do NOT refactor or "improve" other code
|
|
556
|
+
3. NEVER invent code - COPY exact code from file
|
|
557
|
+
4. NEVER change data mappings unless user provides new values
|
|
558
|
+
5. If visibility issue: prefer explicit colors (text-white, text-black) over semantic tokens
|
|
559
|
+
|
|
560
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
561
|
+
RESPONSE FORMAT
|
|
562
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
563
|
+
|
|
564
|
+
Return ONLY raw JSON:
|
|
542
565
|
{
|
|
543
|
-
"
|
|
566
|
+
"analysis": {
|
|
567
|
+
"currentState": "what I see in the screenshot",
|
|
568
|
+
"problem": "the actual issue (or 'none - element appears correct')",
|
|
569
|
+
"fixStrategy": "default|hover|both|clarification_needed"
|
|
570
|
+
},
|
|
571
|
+
"reasoning": "my diagnosis and approach",
|
|
544
572
|
"modifications": [{
|
|
545
573
|
"filePath": "path/to/file.tsx",
|
|
546
574
|
"patches": [{
|
|
547
|
-
"search": "
|
|
548
|
-
"replace": "
|
|
549
|
-
"explanation": "what this
|
|
575
|
+
"search": "EXACT copy from file",
|
|
576
|
+
"replace": "changed code",
|
|
577
|
+
"explanation": "what this changes and why"
|
|
550
578
|
}]
|
|
551
579
|
}],
|
|
552
|
-
"explanation": "summary"
|
|
580
|
+
"explanation": "summary of what was changed"
|
|
553
581
|
}
|
|
554
582
|
|
|
555
|
-
If
|
|
583
|
+
If the element looks correct, return:
|
|
584
|
+
{
|
|
585
|
+
"analysis": { "currentState": "...", "problem": "none", "fixStrategy": "clarification_needed" },
|
|
586
|
+
"modifications": [],
|
|
587
|
+
"explanation": "The element appears visible/correct in the screenshot. Please specify what needs to change."
|
|
588
|
+
}`;
|
|
556
589
|
|
|
557
590
|
export async function POST(request: Request) {
|
|
558
591
|
// Only allow in development
|
|
@@ -875,30 +908,59 @@ ${truncatedContent}${wasTruncated ? "\n// ... (truncated)" : ""}
|
|
|
875
908
|
|
|
876
909
|
// ========== THEME DISCOVERY (REFERENCE ONLY) ==========
|
|
877
910
|
// Dynamically discover theme tokens from the target codebase
|
|
878
|
-
// This is marked as REFERENCE ONLY so the LLM doesn't use it to justify extra changes
|
|
879
911
|
const discoveredTheme = await discoverTheme(projectRoot);
|
|
880
912
|
const themeContext = formatThemeForPrompt(discoveredTheme);
|
|
881
913
|
|
|
914
|
+
// Check if this is a visibility-related request
|
|
915
|
+
const isVisibilityRequest = /visible|can't see|cant see|not visible|hidden|color|contrast/i.test(userPrompt);
|
|
916
|
+
|
|
882
917
|
if (discoveredTheme.discoveredFiles.length > 0) {
|
|
883
|
-
|
|
918
|
+
// Only include detailed color guidance for visibility requests
|
|
919
|
+
if (isVisibilityRequest) {
|
|
920
|
+
// Extract available text color classes from discovered theme
|
|
921
|
+
const textColorClasses = Object.keys(discoveredTheme.cssVariables)
|
|
922
|
+
.filter(key => key.includes('foreground') || key.includes('text'))
|
|
923
|
+
.map(key => `text-${key.replace('--', '').replace(/-/g, '-')}`)
|
|
924
|
+
.slice(0, 10);
|
|
925
|
+
|
|
926
|
+
textContent += `
|
|
884
927
|
═══════════════════════════════════════════════════════════════════════════════
|
|
885
|
-
|
|
928
|
+
COLOR FIX GUIDANCE (for visibility issues only)
|
|
886
929
|
═══════════════════════════════════════════════════════════════════════════════
|
|
887
930
|
|
|
888
|
-
|
|
889
|
-
-
|
|
890
|
-
-
|
|
891
|
-
-
|
|
892
|
-
-
|
|
931
|
+
AVAILABLE TEXT COLORS (use these for contrast fixes):
|
|
932
|
+
- text-white (always visible on dark backgrounds)
|
|
933
|
+
- text-black (always visible on light backgrounds)
|
|
934
|
+
- text-foreground (theme default)
|
|
935
|
+
- text-primary-foreground (for bg-primary)
|
|
936
|
+
- text-accent-foreground (for bg-accent - CHECK IF THIS HAS GOOD CONTRAST)
|
|
937
|
+
- text-destructive-foreground (for bg-destructive)
|
|
938
|
+
|
|
939
|
+
SAFE BUTTON PATTERNS:
|
|
940
|
+
- bg-accent text-white (cyan button, guaranteed visible)
|
|
941
|
+
- bg-primary text-white (charcoal button, guaranteed visible)
|
|
942
|
+
- bg-destructive text-white (red button, guaranteed visible)
|
|
943
|
+
- bg-muted text-foreground (gray button, guaranteed visible)
|
|
893
944
|
|
|
894
|
-
|
|
895
|
-
|
|
945
|
+
IMPORTANT: If current code has text-accent-foreground or similar semantic colors
|
|
946
|
+
that result in poor contrast, REPLACE with text-white or text-black.
|
|
896
947
|
|
|
897
948
|
`;
|
|
949
|
+
} else {
|
|
950
|
+
// For non-visibility requests, minimal reference
|
|
951
|
+
textContent += `
|
|
952
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
953
|
+
REFERENCE ONLY (do not use this to justify additional changes)
|
|
954
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
955
|
+
Theme discovered from: ${discoveredTheme.discoveredFiles.join(', ')}
|
|
956
|
+
`;
|
|
957
|
+
}
|
|
958
|
+
|
|
898
959
|
debugLog("Theme discovery complete", {
|
|
899
960
|
filesFound: discoveredTheme.discoveredFiles,
|
|
900
961
|
cssVariableCount: Object.keys(discoveredTheme.cssVariables).length,
|
|
901
962
|
tailwindColorCount: Object.keys(discoveredTheme.tailwindColors).length,
|
|
963
|
+
isVisibilityRequest,
|
|
902
964
|
});
|
|
903
965
|
}
|
|
904
966
|
|
|
@@ -1043,6 +1105,11 @@ This is better than generating patches with made-up code.`,
|
|
|
1043
1105
|
|
|
1044
1106
|
// Parse AI response - now expecting patches instead of full file content
|
|
1045
1107
|
let aiResponse: {
|
|
1108
|
+
analysis?: {
|
|
1109
|
+
currentState?: string;
|
|
1110
|
+
problem?: string;
|
|
1111
|
+
fixStrategy?: string;
|
|
1112
|
+
};
|
|
1046
1113
|
reasoning?: string;
|
|
1047
1114
|
modifications: Array<{
|
|
1048
1115
|
filePath: string;
|
|
@@ -1090,9 +1157,31 @@ This is better than generating patches with made-up code.`,
|
|
|
1090
1157
|
);
|
|
1091
1158
|
}
|
|
1092
1159
|
|
|
1160
|
+
// Log the LLM's analysis/reasoning (like Cursor showing its thought process)
|
|
1161
|
+
if (aiResponse.analysis) {
|
|
1162
|
+
debugLog("LLM Analysis (Step 1)", {
|
|
1163
|
+
currentState: aiResponse.analysis.currentState,
|
|
1164
|
+
problem: aiResponse.analysis.problem,
|
|
1165
|
+
fixStrategy: aiResponse.analysis.fixStrategy,
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1093
1169
|
finalExplanation = aiResponse.explanation;
|
|
1094
1170
|
finalReasoning = aiResponse.reasoning;
|
|
1095
1171
|
|
|
1172
|
+
// If LLM says clarification is needed, return that to the user
|
|
1173
|
+
if (aiResponse.analysis?.fixStrategy === "clarification_needed" &&
|
|
1174
|
+
(!aiResponse.modifications || aiResponse.modifications.length === 0)) {
|
|
1175
|
+
return NextResponse.json({
|
|
1176
|
+
success: true,
|
|
1177
|
+
sessionId: newSessionId,
|
|
1178
|
+
needsClarification: true,
|
|
1179
|
+
analysis: aiResponse.analysis,
|
|
1180
|
+
explanation: aiResponse.explanation || "The element appears correct. Please specify what needs to change.",
|
|
1181
|
+
modifications: [],
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1096
1185
|
if (!aiResponse.modifications || aiResponse.modifications.length === 0) {
|
|
1097
1186
|
return NextResponse.json({
|
|
1098
1187
|
success: true,
|
|
@@ -1131,6 +1220,19 @@ This is better than generating patches with made-up code.`,
|
|
|
1131
1220
|
continue;
|
|
1132
1221
|
}
|
|
1133
1222
|
|
|
1223
|
+
// CRITICAL: Warn if LLM is trying to modify a file OTHER than the TARGET COMPONENT
|
|
1224
|
+
// This usually means the LLM is trying to modify a file it doesn't have full visibility into
|
|
1225
|
+
const targetComponentPath = recommendedFileContent?.path;
|
|
1226
|
+
if (targetComponentPath && mod.filePath !== targetComponentPath) {
|
|
1227
|
+
debugLog("WARNING: LLM trying to modify non-target file", {
|
|
1228
|
+
targetComponent: targetComponentPath,
|
|
1229
|
+
attemptedFile: mod.filePath,
|
|
1230
|
+
warning: "LLM may be hallucinating code since it only has full content of the TARGET COMPONENT"
|
|
1231
|
+
});
|
|
1232
|
+
console.warn(`[Apply-First] ⚠️ LLM is modifying ${mod.filePath} but TARGET COMPONENT is ${targetComponentPath}`);
|
|
1233
|
+
console.warn(`[Apply-First] ⚠️ This may cause hallucination since LLM only has full visibility into the TARGET COMPONENT`);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1134
1236
|
const fullPath = path.join(projectRoot, mod.filePath);
|
|
1135
1237
|
let originalContent = "";
|
|
1136
1238
|
if (fs.existsSync(fullPath)) {
|
|
@@ -1206,6 +1308,34 @@ This is better than generating patches with made-up code.`,
|
|
|
1206
1308
|
modifiedContent = patchResult.modifiedContent;
|
|
1207
1309
|
console.log(`[Apply-First] All ${mod.patches.length} patches applied successfully to ${mod.filePath}`);
|
|
1208
1310
|
}
|
|
1311
|
+
|
|
1312
|
+
// SYNTAX VALIDATION: Check for common JSX/HTML tag mismatches
|
|
1313
|
+
// This catches cases where the LLM changes opening tags but not closing tags
|
|
1314
|
+
if (mod.filePath.endsWith('.tsx') || mod.filePath.endsWith('.jsx')) {
|
|
1315
|
+
const openDivs = (modifiedContent.match(/<div[\s>]/g) || []).length;
|
|
1316
|
+
const closeDivs = (modifiedContent.match(/<\/div>/g) || []).length;
|
|
1317
|
+
const openSpans = (modifiedContent.match(/<span[\s>]/g) || []).length;
|
|
1318
|
+
const closeSpans = (modifiedContent.match(/<\/span>/g) || []).length;
|
|
1319
|
+
|
|
1320
|
+
if (openDivs !== closeDivs || openSpans !== closeSpans) {
|
|
1321
|
+
debugLog("SYNTAX WARNING: Tag mismatch detected", {
|
|
1322
|
+
filePath: mod.filePath,
|
|
1323
|
+
divs: { open: openDivs, close: closeDivs },
|
|
1324
|
+
spans: { open: openSpans, close: closeSpans },
|
|
1325
|
+
});
|
|
1326
|
+
console.warn(`[Apply-First] ⚠️ SYNTAX WARNING: Tag mismatch in ${mod.filePath}`);
|
|
1327
|
+
console.warn(`[Apply-First] divs: ${openDivs} open, ${closeDivs} close`);
|
|
1328
|
+
console.warn(`[Apply-First] spans: ${openSpans} open, ${closeSpans} close`);
|
|
1329
|
+
|
|
1330
|
+
// If there's a significant mismatch, reject the change
|
|
1331
|
+
const divDiff = Math.abs(openDivs - closeDivs);
|
|
1332
|
+
const spanDiff = Math.abs(openSpans - closeSpans);
|
|
1333
|
+
if (divDiff > 0 || spanDiff > 0) {
|
|
1334
|
+
patchErrors.push(`${mod.filePath}: LLM introduced syntax error - tag mismatch detected (${divDiff} div, ${spanDiff} span). Change rejected.`);
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1209
1339
|
} else if (mod.modifiedContent) {
|
|
1210
1340
|
// Legacy: AI returned full file content
|
|
1211
1341
|
console.warn(`[Apply-First] Legacy modifiedContent received for ${mod.filePath} - patch-based format preferred`);
|
|
@@ -507,50 +507,83 @@ function searchFilesSmart(
|
|
|
507
507
|
return sortedResults.map(r => ({ path: r.path, content: r.content, score: r.score }));
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
-
const VISION_SYSTEM_PROMPT = `You are a code editor.
|
|
510
|
+
const VISION_SYSTEM_PROMPT = `You are a code editor like Cursor. Before making changes, REASON about what needs to be done.
|
|
511
|
+
|
|
512
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
513
|
+
STEP 1: ANALYZE (Think like Cursor)
|
|
514
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
515
|
+
|
|
516
|
+
Before writing any patches, analyze the screenshot and answer:
|
|
517
|
+
|
|
518
|
+
1. CURRENT STATE: What do I see in the screenshot?
|
|
519
|
+
- Is the element visible/readable right now?
|
|
520
|
+
- What colors/styles are currently applied?
|
|
521
|
+
|
|
522
|
+
2. PROBLEM IDENTIFICATION: What's actually wrong?
|
|
523
|
+
- Contrast issue? (text blending with background)
|
|
524
|
+
- Hidden element? (not showing at all)
|
|
525
|
+
- Hover state issue? (only visible on interaction)
|
|
526
|
+
- Layout issue? (wrong size/position)
|
|
527
|
+
- Or is it already correct?
|
|
528
|
+
|
|
529
|
+
3. FIX STRATEGY: What should I change?
|
|
530
|
+
- DEFAULT state only (element needs to look different normally)
|
|
531
|
+
- HOVER state only (element needs different hover effect)
|
|
532
|
+
- BOTH states (element needs overall visibility improvement)
|
|
533
|
+
- ASK for clarification (request is too vague)
|
|
534
|
+
|
|
535
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
536
|
+
STEP 2: GENERATE PATCHES (Only after reasoning)
|
|
537
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
538
|
+
|
|
539
|
+
CRITICAL - FILE SELECTION:
|
|
540
|
+
- You MUST modify the file marked "TARGET COMPONENT" - this is the file you have FULL visibility into
|
|
541
|
+
- Do NOT try to modify other files listed in context - you only see their imports/exports, not full content
|
|
542
|
+
- If the TARGET COMPONENT is not the right file, return clarification_needed
|
|
543
|
+
|
|
544
|
+
COPY EXACTLY from the TARGET COMPONENT section:
|
|
545
|
+
- Your "search" string must match the file CHARACTER-FOR-CHARACTER
|
|
546
|
+
- Include exact indentation and at least 3 lines of context
|
|
547
|
+
- If the element looks FINE in the screenshot, say so
|
|
511
548
|
|
|
512
549
|
RULES:
|
|
513
|
-
1. Make the SMALLEST possible change
|
|
514
|
-
2. Do NOT refactor
|
|
515
|
-
3.
|
|
516
|
-
4.
|
|
517
|
-
5. If
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
- When a focused element is mentioned, SEARCH the provided file content for that EXACT element
|
|
525
|
-
- Look for the actual JSX/HTML code: <button, <Button, <div, className, onClick, etc.
|
|
526
|
-
- If you cannot find the element in the TARGET COMPONENT section, it may be in a child component
|
|
527
|
-
- NEVER guess what element code looks like - find it in the file or report "element not found"
|
|
528
|
-
- If the element is not in the provided file, return: {"modifications": [], "explanation": "The focused element appears to be in a child component, not in [filename]"}
|
|
529
|
-
|
|
530
|
-
CRITICAL - DATA INTEGRITY:
|
|
531
|
-
- If code references database values (like icon_name, type, status), DO NOT change the mapping keys
|
|
532
|
-
- You cannot see database content - only change STRUCTURE, not DATA MAPPINGS
|
|
533
|
-
- Example: If you see iconMap["EyeOff"] = SomeIcon, do NOT change "EyeOff" to something else
|
|
534
|
-
- If user wants different icons, they must tell you the EXACT icon names they want
|
|
535
|
-
|
|
536
|
-
PATCH FORMAT:
|
|
537
|
-
Return ONLY raw JSON (no markdown, no preamble):
|
|
550
|
+
1. Make the SMALLEST possible change
|
|
551
|
+
2. Do NOT refactor or "improve" other code
|
|
552
|
+
3. NEVER invent code - COPY exact code from file
|
|
553
|
+
4. NEVER change data mappings unless user provides new values
|
|
554
|
+
5. If visibility issue: prefer explicit colors (text-white, text-black) over semantic tokens
|
|
555
|
+
|
|
556
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
557
|
+
RESPONSE FORMAT
|
|
558
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
559
|
+
|
|
560
|
+
Return ONLY raw JSON:
|
|
538
561
|
{
|
|
539
|
-
"
|
|
562
|
+
"analysis": {
|
|
563
|
+
"currentState": "what I see in the screenshot",
|
|
564
|
+
"problem": "the actual issue (or 'none - element appears correct')",
|
|
565
|
+
"fixStrategy": "default|hover|both|clarification_needed"
|
|
566
|
+
},
|
|
567
|
+
"reasoning": "my diagnosis and approach",
|
|
540
568
|
"modifications": [{
|
|
541
569
|
"filePath": "path/to/file.tsx",
|
|
542
570
|
"patches": [{
|
|
543
|
-
"search": "
|
|
544
|
-
"replace": "
|
|
545
|
-
"explanation": "what this
|
|
571
|
+
"search": "EXACT copy from file",
|
|
572
|
+
"replace": "changed code",
|
|
573
|
+
"explanation": "what this changes and why"
|
|
546
574
|
}],
|
|
547
575
|
"previewCSS": "optional CSS for live preview"
|
|
548
576
|
}],
|
|
549
577
|
"aggregatedPreviewCSS": "combined CSS for all changes",
|
|
550
|
-
"explanation": "summary"
|
|
578
|
+
"explanation": "summary of what was changed"
|
|
551
579
|
}
|
|
552
580
|
|
|
553
|
-
If
|
|
581
|
+
If the element looks correct, return:
|
|
582
|
+
{
|
|
583
|
+
"analysis": { "currentState": "...", "problem": "none", "fixStrategy": "clarification_needed" },
|
|
584
|
+
"modifications": [],
|
|
585
|
+
"explanation": "The element appears visible/correct in the screenshot. Please specify what needs to change."
|
|
586
|
+
}`;
|
|
554
587
|
|
|
555
588
|
export async function POST(request: Request) {
|
|
556
589
|
// Only allow in development
|
|
@@ -846,30 +879,59 @@ ${truncatedContent}${wasTruncated ? "\n// ... (truncated)" : ""}
|
|
|
846
879
|
|
|
847
880
|
// ========== THEME DISCOVERY (REFERENCE ONLY) ==========
|
|
848
881
|
// Dynamically discover theme tokens from the target codebase
|
|
849
|
-
// This is marked as REFERENCE ONLY so the LLM doesn't use it to justify extra changes
|
|
850
882
|
const discoveredTheme = await discoverTheme(projectRoot);
|
|
851
883
|
const themeContext = formatThemeForPrompt(discoveredTheme);
|
|
852
884
|
|
|
885
|
+
// Check if this is a visibility-related request
|
|
886
|
+
const isVisibilityRequest = /visible|can't see|cant see|not visible|hidden|color|contrast/i.test(userPrompt);
|
|
887
|
+
|
|
853
888
|
if (discoveredTheme.discoveredFiles.length > 0) {
|
|
854
|
-
|
|
889
|
+
// Only include detailed color guidance for visibility requests
|
|
890
|
+
if (isVisibilityRequest) {
|
|
891
|
+
// Extract available text color classes from discovered theme
|
|
892
|
+
const textColorClasses = Object.keys(discoveredTheme.cssVariables)
|
|
893
|
+
.filter(key => key.includes('foreground') || key.includes('text'))
|
|
894
|
+
.map(key => `text-${key.replace('--', '').replace(/-/g, '-')}`)
|
|
895
|
+
.slice(0, 10);
|
|
896
|
+
|
|
897
|
+
textContent += `
|
|
855
898
|
═══════════════════════════════════════════════════════════════════════════════
|
|
856
|
-
|
|
899
|
+
COLOR FIX GUIDANCE (for visibility issues only)
|
|
857
900
|
═══════════════════════════════════════════════════════════════════════════════
|
|
858
901
|
|
|
859
|
-
|
|
860
|
-
-
|
|
861
|
-
-
|
|
862
|
-
-
|
|
863
|
-
-
|
|
902
|
+
AVAILABLE TEXT COLORS (use these for contrast fixes):
|
|
903
|
+
- text-white (always visible on dark backgrounds)
|
|
904
|
+
- text-black (always visible on light backgrounds)
|
|
905
|
+
- text-foreground (theme default)
|
|
906
|
+
- text-primary-foreground (for bg-primary)
|
|
907
|
+
- text-accent-foreground (for bg-accent - CHECK IF THIS HAS GOOD CONTRAST)
|
|
908
|
+
- text-destructive-foreground (for bg-destructive)
|
|
864
909
|
|
|
865
|
-
|
|
866
|
-
|
|
910
|
+
SAFE BUTTON PATTERNS:
|
|
911
|
+
- bg-accent text-white (cyan button, guaranteed visible)
|
|
912
|
+
- bg-primary text-white (charcoal button, guaranteed visible)
|
|
913
|
+
- bg-destructive text-white (red button, guaranteed visible)
|
|
914
|
+
- bg-muted text-foreground (gray button, guaranteed visible)
|
|
867
915
|
|
|
916
|
+
IMPORTANT: If current code has text-accent-foreground or similar semantic colors
|
|
917
|
+
that result in poor contrast, REPLACE with text-white or text-black.
|
|
918
|
+
|
|
919
|
+
`;
|
|
920
|
+
} else {
|
|
921
|
+
// For non-visibility requests, minimal reference
|
|
922
|
+
textContent += `
|
|
923
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
924
|
+
REFERENCE ONLY (do not use this to justify additional changes)
|
|
925
|
+
═══════════════════════════════════════════════════════════════════════════════
|
|
926
|
+
Theme discovered from: ${discoveredTheme.discoveredFiles.join(', ')}
|
|
868
927
|
`;
|
|
928
|
+
}
|
|
929
|
+
|
|
869
930
|
debugLog("Theme discovery complete", {
|
|
870
931
|
filesFound: discoveredTheme.discoveredFiles,
|
|
871
932
|
cssVariableCount: Object.keys(discoveredTheme.cssVariables).length,
|
|
872
933
|
tailwindColorCount: Object.keys(discoveredTheme.tailwindColors).length,
|
|
934
|
+
isVisibilityRequest,
|
|
873
935
|
});
|
|
874
936
|
}
|
|
875
937
|
|
|
@@ -1010,6 +1072,11 @@ This is better than generating patches with made-up code.`,
|
|
|
1010
1072
|
|
|
1011
1073
|
// Parse AI response - now expecting patches instead of full file content
|
|
1012
1074
|
let aiResponse: {
|
|
1075
|
+
analysis?: {
|
|
1076
|
+
currentState?: string;
|
|
1077
|
+
problem?: string;
|
|
1078
|
+
fixStrategy?: string;
|
|
1079
|
+
};
|
|
1013
1080
|
reasoning?: string;
|
|
1014
1081
|
modifications: Array<{
|
|
1015
1082
|
filePath: string;
|
|
@@ -1061,10 +1128,31 @@ This is better than generating patches with made-up code.`,
|
|
|
1061
1128
|
);
|
|
1062
1129
|
}
|
|
1063
1130
|
|
|
1131
|
+
// Log the LLM's analysis/reasoning (like Cursor showing its thought process)
|
|
1132
|
+
if (aiResponse.analysis) {
|
|
1133
|
+
debugLog("LLM Analysis (Step 1)", {
|
|
1134
|
+
currentState: aiResponse.analysis.currentState,
|
|
1135
|
+
problem: aiResponse.analysis.problem,
|
|
1136
|
+
fixStrategy: aiResponse.analysis.fixStrategy,
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1064
1140
|
finalExplanation = aiResponse.explanation;
|
|
1065
1141
|
finalReasoning = aiResponse.reasoning;
|
|
1066
1142
|
finalAggregatedCSS = aiResponse.aggregatedPreviewCSS;
|
|
1067
1143
|
|
|
1144
|
+
// If LLM says clarification is needed, return that to the user
|
|
1145
|
+
if (aiResponse.analysis?.fixStrategy === "clarification_needed" &&
|
|
1146
|
+
(!aiResponse.modifications || aiResponse.modifications.length === 0)) {
|
|
1147
|
+
return NextResponse.json({
|
|
1148
|
+
success: true,
|
|
1149
|
+
needsClarification: true,
|
|
1150
|
+
analysis: aiResponse.analysis,
|
|
1151
|
+
explanation: aiResponse.explanation || "The element appears correct. Please specify what needs to change.",
|
|
1152
|
+
modifications: [],
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1068
1156
|
debugLog("VALIDATION: Known file paths from page context", {
|
|
1069
1157
|
pageFile: pageContext.pageFile,
|
|
1070
1158
|
knownPaths: Array.from(knownPaths),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonance-brand-mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.60",
|
|
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",
|