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: 1024,
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.toLowerCase();
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
- // Search for JSX patterns
199
- // Check for HTML tags like <button, <div, etc.
200
- if (content.includes(`<${elementType}`)) {
201
- score += 10;
202
- matches.push(`<${elementType}>`);
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
- // Check for React component like <Button, <Card, etc.
206
- const capitalizedType = el.type.charAt(0).toUpperCase() + el.type.slice(1);
207
- if (file.content.includes(`<${capitalizedType}`)) {
208
- score += 15;
209
- matches.push(`<${capitalizedType}>`);
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
- // Check for component imports
213
- if (content.includes(`import`) && content.includes(componentType)) {
214
- score += 5;
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
- // Check for event handlers commonly associated with buttons
235
+ // LOW VALUE: Event handlers (onClick, onPress, etc.)
218
236
  if (elementType === "button" || componentType === "button") {
219
- if (content.includes("onclick") || content.includes("onpress")) {
220
- score += 3;
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
- // Check for the component being defined in this file
225
- if (file.content.includes(`function ${capitalizedType}`) ||
226
- file.content.includes(`const ${capitalizedType}`)) {
227
- score += 20;
228
- matches.push(`defines ${capitalizedType}`);
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
- // PHASE 3: Ask LLM to pick the best file from actual file list
672
- if (searchResults.length > 0) {
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: 1024,
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.toLowerCase();
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
- // Search for JSX patterns
195
- // Check for HTML tags like <button, <div, etc.
196
- if (content.includes(`<${elementType}`)) {
197
- score += 10;
198
- matches.push(`<${elementType}>`);
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
- // Check for React component like <Button, <Card, etc.
202
- const capitalizedType = el.type.charAt(0).toUpperCase() + el.type.slice(1);
203
- if (file.content.includes(`<${capitalizedType}`)) {
204
- score += 15;
205
- matches.push(`<${capitalizedType}>`);
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
- // Check for component imports
209
- if (content.includes(`import`) && content.includes(componentType)) {
210
- score += 5;
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
- // Check for event handlers commonly associated with buttons
231
+ // LOW VALUE: Event handlers (onClick, onPress, etc.)
214
232
  if (elementType === "button" || componentType === "button") {
215
- if (content.includes("onclick") || content.includes("onpress")) {
216
- score += 3;
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
- // Check for the component being defined in this file
221
- if (file.content.includes(`function ${capitalizedType}`) ||
222
- file.content.includes(`const ${capitalizedType}`)) {
223
- score += 20;
224
- matches.push(`defines ${capitalizedType}`);
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
- // PHASE 3: Ask LLM to pick the best file from actual file list
641
- if (searchResults.length > 0) {
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.62",
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",