sonance-brand-mcp 1.3.62 → 1.3.63
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.
|
@@ -106,7 +106,7 @@ async function analyzeScreenshotForSearch(
|
|
|
106
106
|
|
|
107
107
|
const response = await anthropic.messages.create({
|
|
108
108
|
model: "claude-sonnet-4-20250514",
|
|
109
|
-
max_tokens:
|
|
109
|
+
max_tokens: 2048, // Increased for better analysis
|
|
110
110
|
messages: [
|
|
111
111
|
{
|
|
112
112
|
role: "user",
|
|
@@ -174,6 +174,8 @@ Be smart - use your knowledge of React patterns to make educated guesses about c
|
|
|
174
174
|
/**
|
|
175
175
|
* Search candidate files for JSX code matching the focused element
|
|
176
176
|
* This helps identify which file actually contains the element the user clicked on
|
|
177
|
+
*
|
|
178
|
+
* CURSOR-STYLE: Search file CONTENTS for patterns, not just file names
|
|
177
179
|
*/
|
|
178
180
|
function findFilesContainingElement(
|
|
179
181
|
focusedElements: VisionFocusedElement[] | undefined,
|
|
@@ -188,44 +190,68 @@ function findFilesContainingElement(
|
|
|
188
190
|
for (const file of candidateFiles) {
|
|
189
191
|
let score = 0;
|
|
190
192
|
const matches: string[] = [];
|
|
191
|
-
const content = file.content
|
|
193
|
+
const content = file.content;
|
|
194
|
+
const contentLower = content.toLowerCase();
|
|
192
195
|
|
|
193
196
|
for (const el of focusedElements) {
|
|
194
197
|
// Extract element type from the name (e.g., "button #123" -> "button")
|
|
195
198
|
const elementType = el.name.split(/[\s#]/)[0].toLowerCase();
|
|
196
199
|
const componentType = el.type.toLowerCase();
|
|
200
|
+
const capitalizedType = el.type.charAt(0).toUpperCase() + el.type.slice(1);
|
|
197
201
|
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
202
|
+
// HIGH VALUE: Component is EXPORTED from this file (this is likely THE file)
|
|
203
|
+
if (content.includes(`export function ${capitalizedType}`) ||
|
|
204
|
+
content.includes(`export const ${capitalizedType}`) ||
|
|
205
|
+
content.includes(`export default function ${capitalizedType}`)) {
|
|
206
|
+
score += 100;
|
|
207
|
+
matches.push(`EXPORTS ${capitalizedType}`);
|
|
203
208
|
}
|
|
204
209
|
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
+
// HIGH VALUE: Component is DEFINED in this file
|
|
211
|
+
if (content.includes(`function ${capitalizedType}(`) ||
|
|
212
|
+
content.includes(`const ${capitalizedType} =`) ||
|
|
213
|
+
content.includes(`const ${capitalizedType}:`) ||
|
|
214
|
+
content.includes(`function ${capitalizedType} (`)) {
|
|
215
|
+
score += 50;
|
|
216
|
+
matches.push(`defines ${capitalizedType}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// MEDIUM VALUE: JSX usage of this element type (rendered in this file)
|
|
220
|
+
const jsxTagPattern = new RegExp(`<${capitalizedType}[\\s/>]`, 'g');
|
|
221
|
+
const jsxMatches = content.match(jsxTagPattern);
|
|
222
|
+
if (jsxMatches) {
|
|
223
|
+
score += 20 * jsxMatches.length;
|
|
224
|
+
matches.push(`<${capitalizedType}> x${jsxMatches.length}`);
|
|
210
225
|
}
|
|
211
226
|
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
227
|
+
// MEDIUM VALUE: HTML tag usage
|
|
228
|
+
const htmlTagPattern = new RegExp(`<${elementType}[\\s>]`, 'gi');
|
|
229
|
+
const htmlMatches = content.match(htmlTagPattern);
|
|
230
|
+
if (htmlMatches) {
|
|
231
|
+
score += 10 * htmlMatches.length;
|
|
232
|
+
matches.push(`<${elementType}> x${htmlMatches.length}`);
|
|
215
233
|
}
|
|
216
234
|
|
|
217
|
-
//
|
|
235
|
+
// LOW VALUE: Event handlers (onClick, onPress, etc.)
|
|
218
236
|
if (elementType === "button" || componentType === "button") {
|
|
219
|
-
|
|
220
|
-
|
|
237
|
+
const clickHandlers = content.match(/onClick\s*=/gi);
|
|
238
|
+
if (clickHandlers) {
|
|
239
|
+
score += 5 * clickHandlers.length;
|
|
240
|
+
matches.push(`onClick x${clickHandlers.length}`);
|
|
221
241
|
}
|
|
222
242
|
}
|
|
223
243
|
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
score +=
|
|
228
|
-
matches.push(`
|
|
244
|
+
// BONUS: File name contains the element type
|
|
245
|
+
const fileName = file.path.toLowerCase();
|
|
246
|
+
if (fileName.includes(elementType) || fileName.includes(componentType)) {
|
|
247
|
+
score += 30;
|
|
248
|
+
matches.push(`filename contains ${elementType}`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// BONUS: File is a Row/Cell component (likely contains action buttons)
|
|
252
|
+
if (fileName.includes('row') || fileName.includes('cell') || fileName.includes('item')) {
|
|
253
|
+
score += 15;
|
|
254
|
+
matches.push('row/cell component');
|
|
229
255
|
}
|
|
230
256
|
}
|
|
231
257
|
|
|
@@ -668,8 +694,19 @@ export async function POST(request: Request) {
|
|
|
668
694
|
});
|
|
669
695
|
}
|
|
670
696
|
|
|
671
|
-
//
|
|
672
|
-
|
|
697
|
+
// CURSOR-STYLE: If focused element search has high confidence, use it directly
|
|
698
|
+
// Skip the LLM guessing phase - we found the file that contains the code
|
|
699
|
+
const HIGH_CONFIDENCE_THRESHOLD = 50; // Score of 50+ means we found exact matches
|
|
700
|
+
|
|
701
|
+
if (focusedElementHints.length > 0 && focusedElementHints[0].score >= HIGH_CONFIDENCE_THRESHOLD) {
|
|
702
|
+
// HIGH CONFIDENCE: Use focused element match directly
|
|
703
|
+
recommendedFile = {
|
|
704
|
+
path: focusedElementHints[0].path,
|
|
705
|
+
reason: `Content search found element (score: ${focusedElementHints[0].score}, matches: ${focusedElementHints[0].matches.join(', ')})`
|
|
706
|
+
};
|
|
707
|
+
debugLog("HIGH CONFIDENCE: Using focused element match directly", recommendedFile);
|
|
708
|
+
} else if (searchResults.length > 0) {
|
|
709
|
+
// LOW CONFIDENCE: Fall back to LLM selection
|
|
673
710
|
const candidateFiles = searchResults.slice(0, 10).map(r => r.path);
|
|
674
711
|
const selectedFile = await selectBestFileFromList(
|
|
675
712
|
screenshot,
|
|
@@ -2422,3 +2459,4 @@ function applyPatches(originalContent: string, patches: Patch[]): ApplyPatchesRe
|
|
|
2422
2459
|
failedPatches,
|
|
2423
2460
|
};
|
|
2424
2461
|
}
|
|
2462
|
+
|
|
@@ -102,7 +102,7 @@ async function analyzeScreenshotForSearch(
|
|
|
102
102
|
|
|
103
103
|
const response = await anthropic.messages.create({
|
|
104
104
|
model: "claude-sonnet-4-20250514",
|
|
105
|
-
max_tokens:
|
|
105
|
+
max_tokens: 2048, // Increased for better analysis
|
|
106
106
|
messages: [
|
|
107
107
|
{
|
|
108
108
|
role: "user",
|
|
@@ -170,6 +170,8 @@ Be smart - use your knowledge of React patterns to make educated guesses about c
|
|
|
170
170
|
/**
|
|
171
171
|
* Search candidate files for JSX code matching the focused element
|
|
172
172
|
* This helps identify which file actually contains the element the user clicked on
|
|
173
|
+
*
|
|
174
|
+
* CURSOR-STYLE: Search file CONTENTS for patterns, not just file names
|
|
173
175
|
*/
|
|
174
176
|
function findFilesContainingElement(
|
|
175
177
|
focusedElements: VisionFocusedElement[] | undefined,
|
|
@@ -184,44 +186,68 @@ function findFilesContainingElement(
|
|
|
184
186
|
for (const file of candidateFiles) {
|
|
185
187
|
let score = 0;
|
|
186
188
|
const matches: string[] = [];
|
|
187
|
-
const content = file.content
|
|
189
|
+
const content = file.content;
|
|
190
|
+
const contentLower = content.toLowerCase();
|
|
188
191
|
|
|
189
192
|
for (const el of focusedElements) {
|
|
190
193
|
// Extract element type from the name (e.g., "button #123" -> "button")
|
|
191
194
|
const elementType = el.name.split(/[\s#]/)[0].toLowerCase();
|
|
192
195
|
const componentType = el.type.toLowerCase();
|
|
196
|
+
const capitalizedType = el.type.charAt(0).toUpperCase() + el.type.slice(1);
|
|
193
197
|
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
198
|
+
// HIGH VALUE: Component is EXPORTED from this file (this is likely THE file)
|
|
199
|
+
if (content.includes(`export function ${capitalizedType}`) ||
|
|
200
|
+
content.includes(`export const ${capitalizedType}`) ||
|
|
201
|
+
content.includes(`export default function ${capitalizedType}`)) {
|
|
202
|
+
score += 100;
|
|
203
|
+
matches.push(`EXPORTS ${capitalizedType}`);
|
|
199
204
|
}
|
|
200
205
|
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
// HIGH VALUE: Component is DEFINED in this file
|
|
207
|
+
if (content.includes(`function ${capitalizedType}(`) ||
|
|
208
|
+
content.includes(`const ${capitalizedType} =`) ||
|
|
209
|
+
content.includes(`const ${capitalizedType}:`) ||
|
|
210
|
+
content.includes(`function ${capitalizedType} (`)) {
|
|
211
|
+
score += 50;
|
|
212
|
+
matches.push(`defines ${capitalizedType}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// MEDIUM VALUE: JSX usage of this element type (rendered in this file)
|
|
216
|
+
const jsxTagPattern = new RegExp(`<${capitalizedType}[\\s/>]`, 'g');
|
|
217
|
+
const jsxMatches = content.match(jsxTagPattern);
|
|
218
|
+
if (jsxMatches) {
|
|
219
|
+
score += 20 * jsxMatches.length;
|
|
220
|
+
matches.push(`<${capitalizedType}> x${jsxMatches.length}`);
|
|
206
221
|
}
|
|
207
222
|
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
|
|
223
|
+
// MEDIUM VALUE: HTML tag usage
|
|
224
|
+
const htmlTagPattern = new RegExp(`<${elementType}[\\s>]`, 'gi');
|
|
225
|
+
const htmlMatches = content.match(htmlTagPattern);
|
|
226
|
+
if (htmlMatches) {
|
|
227
|
+
score += 10 * htmlMatches.length;
|
|
228
|
+
matches.push(`<${elementType}> x${htmlMatches.length}`);
|
|
211
229
|
}
|
|
212
230
|
|
|
213
|
-
//
|
|
231
|
+
// LOW VALUE: Event handlers (onClick, onPress, etc.)
|
|
214
232
|
if (elementType === "button" || componentType === "button") {
|
|
215
|
-
|
|
216
|
-
|
|
233
|
+
const clickHandlers = content.match(/onClick\s*=/gi);
|
|
234
|
+
if (clickHandlers) {
|
|
235
|
+
score += 5 * clickHandlers.length;
|
|
236
|
+
matches.push(`onClick x${clickHandlers.length}`);
|
|
217
237
|
}
|
|
218
238
|
}
|
|
219
239
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
score +=
|
|
224
|
-
matches.push(`
|
|
240
|
+
// BONUS: File name contains the element type
|
|
241
|
+
const fileName = file.path.toLowerCase();
|
|
242
|
+
if (fileName.includes(elementType) || fileName.includes(componentType)) {
|
|
243
|
+
score += 30;
|
|
244
|
+
matches.push(`filename contains ${elementType}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// BONUS: File is a Row/Cell component (likely contains action buttons)
|
|
248
|
+
if (fileName.includes('row') || fileName.includes('cell') || fileName.includes('item')) {
|
|
249
|
+
score += 15;
|
|
250
|
+
matches.push('row/cell component');
|
|
225
251
|
}
|
|
226
252
|
}
|
|
227
253
|
|
|
@@ -637,8 +663,19 @@ export async function POST(request: Request) {
|
|
|
637
663
|
});
|
|
638
664
|
}
|
|
639
665
|
|
|
640
|
-
//
|
|
641
|
-
|
|
666
|
+
// CURSOR-STYLE: If focused element search has high confidence, use it directly
|
|
667
|
+
// Skip the LLM guessing phase - we found the file that contains the code
|
|
668
|
+
const HIGH_CONFIDENCE_THRESHOLD = 50; // Score of 50+ means we found exact matches
|
|
669
|
+
|
|
670
|
+
if (focusedElementHints.length > 0 && focusedElementHints[0].score >= HIGH_CONFIDENCE_THRESHOLD) {
|
|
671
|
+
// HIGH CONFIDENCE: Use focused element match directly
|
|
672
|
+
recommendedFile = {
|
|
673
|
+
path: focusedElementHints[0].path,
|
|
674
|
+
reason: `Content search found element (score: ${focusedElementHints[0].score}, matches: ${focusedElementHints[0].matches.join(', ')})`
|
|
675
|
+
};
|
|
676
|
+
debugLog("HIGH CONFIDENCE: Using focused element match directly", recommendedFile);
|
|
677
|
+
} else if (searchResults.length > 0) {
|
|
678
|
+
// LOW CONFIDENCE: Fall back to LLM selection
|
|
642
679
|
const candidateFiles = searchResults.slice(0, 10).map(r => r.path);
|
|
643
680
|
const selectedFile = await selectBestFileFromList(
|
|
644
681
|
screenshot,
|
|
@@ -2231,3 +2268,4 @@ function applyPatches(originalContent: string, patches: Patch[]): ApplyPatchesRe
|
|
|
2231
2268
|
failedPatches,
|
|
2232
2269
|
};
|
|
2233
2270
|
}
|
|
2271
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonance-brand-mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.63",
|
|
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",
|