sonance-brand-mcp 1.3.100 → 1.3.101

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.
@@ -2087,6 +2087,124 @@ export async function POST(request: Request) {
2087
2087
  }
2088
2088
  }
2089
2089
 
2090
+ // ========== FILE REDIRECT LOGIC (runs BEFORE building instructions) ==========
2091
+ // This determines the ACTUAL target file by checking for text matches in imported components
2092
+ // Must run first so that all subsequent code uses the correct file path
2093
+ let actualTargetFile = recommendedFileContent || (pageContext.pageContent ? { path: pageContext.pageFile, content: pageContext.pageContent } : null);
2094
+ let elementLocation: { lineNumber: number; snippet: string; confidence: 'high' | 'medium' | 'low'; matchedBy: string } | null = null;
2095
+
2096
+ if (actualTargetFile && focusedElements && focusedElements.length > 0) {
2097
+ const content = actualTargetFile.content;
2098
+
2099
+ // Search for focused element in the file using multiple strategies
2100
+ // Priority: DOM id > textContent > className patterns
2101
+ for (const el of focusedElements) {
2102
+ elementLocation = findElementLineInFile(content, el);
2103
+ if (elementLocation) {
2104
+ debugLog("Found focused element in file", {
2105
+ matchedBy: elementLocation.matchedBy,
2106
+ lineNumber: elementLocation.lineNumber,
2107
+ confidence: elementLocation.confidence,
2108
+ file: actualTargetFile.path,
2109
+ });
2110
+ break;
2111
+ }
2112
+ }
2113
+
2114
+ // TEXT SCORING REDIRECT: Score ALL imported files by how many discovered
2115
+ // text strings they contain. The file with the highest score is the TRUE target.
2116
+ if (elementLocation && elementLocation.confidence !== 'high') {
2117
+ const allTextContent = focusedElements
2118
+ .filter(e => e.textContent && e.textContent.length > 5)
2119
+ .map(e => e.textContent!);
2120
+
2121
+ if (allTextContent.length > 0) {
2122
+ debugLog("Medium/low confidence match - scoring imports for all text", {
2123
+ currentFile: actualTargetFile.path,
2124
+ currentConfidence: elementLocation.confidence,
2125
+ textCount: allTextContent.length,
2126
+ texts: allTextContent.slice(0, 5).map(t => t.substring(0, 25))
2127
+ });
2128
+
2129
+ const bestMatch = scoreFilesForTextContent(
2130
+ allTextContent,
2131
+ pageContext.componentSources
2132
+ );
2133
+
2134
+ const currentFileScore = allTextContent.filter(text =>
2135
+ actualTargetFile!.content.includes(text.substring(0, 20))
2136
+ ).length;
2137
+
2138
+ debugLog("Text scoring comparison", {
2139
+ currentFile: actualTargetFile.path,
2140
+ currentScore: currentFileScore,
2141
+ bestImport: bestMatch?.path || 'none',
2142
+ bestImportScore: bestMatch?.score || 0
2143
+ });
2144
+
2145
+ if (bestMatch && bestMatch.score > currentFileScore) {
2146
+ debugLog("TEXT REDIRECT: Imported file has more text matches", {
2147
+ originalFile: actualTargetFile.path,
2148
+ originalScore: currentFileScore,
2149
+ redirectTo: bestMatch.path,
2150
+ redirectScore: bestMatch.score,
2151
+ matchedTexts: bestMatch.matchedTexts
2152
+ });
2153
+
2154
+ actualTargetFile = {
2155
+ path: bestMatch.path,
2156
+ content: bestMatch.content
2157
+ };
2158
+
2159
+ const lines = bestMatch.content.split('\n');
2160
+ const snippetStart = Math.max(0, bestMatch.firstMatchLine - 4);
2161
+ const snippetEnd = Math.min(lines.length, bestMatch.firstMatchLine + 5);
2162
+
2163
+ elementLocation = {
2164
+ lineNumber: bestMatch.firstMatchLine,
2165
+ snippet: lines.slice(snippetStart, snippetEnd).join('\n'),
2166
+ confidence: 'high',
2167
+ matchedBy: `text scoring: ${bestMatch.score} matches in imported file`
2168
+ };
2169
+ }
2170
+ }
2171
+ }
2172
+
2173
+ // DYNAMIC IMPORT SEARCH: If not found in main file, search imported components
2174
+ if (!elementLocation) {
2175
+ debugLog("Element not in main file, searching imported components...", {
2176
+ mainFile: actualTargetFile.path,
2177
+ importedFilesCount: pageContext.componentSources.length
2178
+ });
2179
+
2180
+ const importedMatch = findElementInImportedFiles(
2181
+ focusedElements[0],
2182
+ pageContext.componentSources
2183
+ );
2184
+
2185
+ if (importedMatch) {
2186
+ debugLog("REDIRECT: Element found in imported component", {
2187
+ originalFile: actualTargetFile.path,
2188
+ redirectTo: importedMatch.path,
2189
+ matchedBy: importedMatch.matchedBy,
2190
+ lineNumber: importedMatch.lineNumber
2191
+ });
2192
+
2193
+ actualTargetFile = {
2194
+ path: importedMatch.path,
2195
+ content: importedMatch.content
2196
+ };
2197
+ elementLocation = findElementLineInFile(importedMatch.content, focusedElements[0]);
2198
+ }
2199
+ }
2200
+ }
2201
+
2202
+ debugLog("File redirect complete", {
2203
+ originalRecommended: recommendedFileContent?.path || 'none',
2204
+ actualTarget: actualTargetFile?.path || 'none',
2205
+ wasRedirected: actualTargetFile?.path !== recommendedFileContent?.path
2206
+ });
2207
+
2090
2208
  // Build text content
2091
2209
  let textContent = `VISION MODE EDIT REQUEST
2092
2210
 
@@ -2110,7 +2228,8 @@ User Request: "${userPrompt}"
2110
2228
 
2111
2229
  // Phase 1: Analyze the screenshot to identify specific problems
2112
2230
  // This is a SEPARATE LLM call that only identifies problems
2113
- const fileContentForAnalysis = recommendedFileContent?.content || pageContext.pageContent || '';
2231
+ // Use actualTargetFile since redirect has already happened
2232
+ const fileContentForAnalysis = actualTargetFile?.content || pageContext.pageContent || '';
2114
2233
  identifiedProblems = await analyzeDesignProblems(
2115
2234
  screenshot,
2116
2235
  fileContentForAnalysis,
@@ -2135,124 +2254,8 @@ User Request: "${userPrompt}"
2135
2254
 
2136
2255
  // ========== TARGET COMPONENT ONLY (with line numbers) ==========
2137
2256
  // CRITICAL: Only include the TARGET file to avoid overwhelming the LLM with noise
2138
- if (recommendedFileContent) {
2139
- const content = recommendedFileContent.content;
2140
-
2141
- // Search for focused element in the file using multiple strategies
2142
- // Priority: DOM id > textContent > className patterns
2143
- let elementLocation: { lineNumber: number; snippet: string; confidence: 'high' | 'medium' | 'low'; matchedBy: string } | null = null;
2144
- let actualTargetFile = recommendedFileContent; // May change if we redirect
2145
-
2146
- if (focusedElements && focusedElements.length > 0) {
2147
- for (const el of focusedElements) {
2148
- elementLocation = findElementLineInFile(content, el);
2149
- if (elementLocation) {
2150
- debugLog("Found focused element in file", {
2151
- matchedBy: elementLocation.matchedBy,
2152
- lineNumber: elementLocation.lineNumber,
2153
- confidence: elementLocation.confidence,
2154
- file: recommendedFileContent.path,
2155
- });
2156
- break;
2157
- }
2158
- }
2159
-
2160
- // TEXT SCORING REDIRECT: Score ALL imported files by how many discovered
2161
- // text strings they contain. The file with the highest score is the TRUE target.
2162
- // This handles parent/child component cases accurately.
2163
- if (elementLocation && elementLocation.confidence !== 'high') {
2164
- // Collect ALL text content from focused elements
2165
- const allTextContent = focusedElements
2166
- .filter(e => e.textContent && e.textContent.length > 5)
2167
- .map(e => e.textContent!);
2168
-
2169
- if (allTextContent.length > 0) {
2170
- debugLog("Medium/low confidence match - scoring imports for all text", {
2171
- currentFile: recommendedFileContent.path,
2172
- currentConfidence: elementLocation.confidence,
2173
- textCount: allTextContent.length,
2174
- texts: allTextContent.slice(0, 5).map(t => t.substring(0, 25))
2175
- });
2176
-
2177
- // Score all imported files
2178
- const bestMatch = scoreFilesForTextContent(
2179
- allTextContent,
2180
- pageContext.componentSources
2181
- );
2182
-
2183
- // Also score the current file for comparison
2184
- const currentFileScore = allTextContent.filter(text =>
2185
- recommendedFileContent.content.includes(text.substring(0, 20))
2186
- ).length;
2187
-
2188
- debugLog("Text scoring comparison", {
2189
- currentFile: recommendedFileContent.path,
2190
- currentScore: currentFileScore,
2191
- bestImport: bestMatch?.path || 'none',
2192
- bestImportScore: bestMatch?.score || 0
2193
- });
2194
-
2195
- // Redirect only if imported file has MORE matches than current file
2196
- if (bestMatch && bestMatch.score > currentFileScore) {
2197
- debugLog("TEXT REDIRECT: Imported file has more text matches", {
2198
- originalFile: recommendedFileContent.path,
2199
- originalScore: currentFileScore,
2200
- redirectTo: bestMatch.path,
2201
- redirectScore: bestMatch.score,
2202
- matchedTexts: bestMatch.matchedTexts
2203
- });
2204
-
2205
- // Switch target file to where most text content lives
2206
- actualTargetFile = {
2207
- path: bestMatch.path,
2208
- content: bestMatch.content
2209
- };
2210
-
2211
- // Find a line with matched text for element location
2212
- const lines = bestMatch.content.split('\n');
2213
- const snippetStart = Math.max(0, bestMatch.firstMatchLine - 4);
2214
- const snippetEnd = Math.min(lines.length, bestMatch.firstMatchLine + 5);
2215
-
2216
- elementLocation = {
2217
- lineNumber: bestMatch.firstMatchLine,
2218
- snippet: lines.slice(snippetStart, snippetEnd).join('\n'),
2219
- confidence: 'high',
2220
- matchedBy: `text scoring: ${bestMatch.score} matches in imported file`
2221
- };
2222
- }
2223
- }
2224
- }
2225
-
2226
- // DYNAMIC IMPORT SEARCH: If not found in main file, search imported components
2227
- if (!elementLocation) {
2228
- debugLog("Element not in main file, searching imported components...", {
2229
- mainFile: recommendedFileContent.path,
2230
- importedFilesCount: pageContext.componentSources.length
2231
- });
2232
-
2233
- const importedMatch = findElementInImportedFiles(
2234
- focusedElements[0],
2235
- pageContext.componentSources
2236
- );
2237
-
2238
- if (importedMatch) {
2239
- debugLog("REDIRECT: Element found in imported component", {
2240
- originalFile: recommendedFileContent.path,
2241
- redirectTo: importedMatch.path,
2242
- matchedBy: importedMatch.matchedBy,
2243
- lineNumber: importedMatch.lineNumber
2244
- });
2245
-
2246
- // Switch target file to where element actually is
2247
- actualTargetFile = {
2248
- path: importedMatch.path,
2249
- content: importedMatch.content
2250
- };
2251
- elementLocation = findElementLineInFile(importedMatch.content, focusedElements[0]);
2252
- }
2253
- }
2254
- }
2255
-
2257
+ // Note: Redirect logic already ran above, so actualTargetFile is the correct file
2258
+ if (actualTargetFile) {
2256
2259
  // Build focused elements section with precise targeting info
2257
2260
  if (focusedElements && focusedElements.length > 0) {
2258
2261
  textContent += `FOCUSED ELEMENTS (user clicked on these):\n`;
@@ -2316,7 +2319,7 @@ ${elementLocation.snippet}
2316
2319
  // Element NOT found in main file OR any imported components
2317
2320
  // BLOCK the LLM from guessing - require empty modifications
2318
2321
  debugLog("BLOCK: Could not locate focused element anywhere", {
2319
- mainFile: recommendedFileContent.path,
2322
+ mainFile: actualTargetFile.path,
2320
2323
  searchedImports: pageContext.componentSources.length,
2321
2324
  focusedElements: focusedElements.map(el => ({
2322
2325
  name: el.name,
@@ -2332,7 +2335,7 @@ ${elementLocation.snippet}
2332
2335
  ⛔ STOP: CANNOT LOCATE THE CLICKED ELEMENT
2333
2336
 
2334
2337
  The user clicked on a specific element, but it could NOT be found in:
2335
- - ${recommendedFileContent.path} (main target file)
2338
+ - ${actualTargetFile.path} (main target file)
2336
2339
  - Any of the ${pageContext.componentSources.length} imported component files
2337
2340
 
2338
2341
  The element may be:
@@ -2447,7 +2450,8 @@ ${variantsMatch[0]}
2447
2450
  }
2448
2451
 
2449
2452
  // ========== SIMPLIFIED INSTRUCTIONS ==========
2450
- const targetPath = recommendedFileContent?.path || pageContext.pageFile || "unknown";
2453
+ // Use actualTargetFile which may have been redirected to an imported component
2454
+ const targetPath = actualTargetFile?.path || pageContext.pageFile || "unknown";
2451
2455
 
2452
2456
  textContent += `═══════════════════════════════════════════════════════════════════════════════
2453
2457
  HOW TO MAKE YOUR EDIT
@@ -2491,10 +2495,14 @@ CRITICAL: Your "search" string MUST exist in the file. If you can't find the exa
2491
2495
  validFilePaths.add(comp.path);
2492
2496
  }
2493
2497
 
2494
- // FIX: Add the recommended file to validFilePaths (it was spliced out for display purposes)
2498
+ // FIX: Add the recommended file and actual target file to validFilePaths
2499
+ // (recommended was spliced out for display, actual may be different due to redirect)
2495
2500
  if (recommendedFileContent) {
2496
2501
  validFilePaths.add(recommendedFileContent.path);
2497
2502
  }
2503
+ if (actualTargetFile && actualTargetFile.path !== recommendedFileContent?.path) {
2504
+ validFilePaths.add(actualTargetFile.path);
2505
+ }
2498
2506
 
2499
2507
  // Retry loop for handling patch failures
2500
2508
  const MAX_RETRIES = 1;
@@ -2630,7 +2638,8 @@ This is better than generating patches with made-up code.`,
2630
2638
 
2631
2639
  // CRITICAL: Warn if LLM is trying to modify a file OTHER than the TARGET COMPONENT
2632
2640
  // This usually means the LLM is trying to modify a file it doesn't have full visibility into
2633
- const targetComponentPath = recommendedFileContent?.path;
2641
+ // Use actualTargetFile since it may have been redirected from recommendedFileContent
2642
+ const targetComponentPath = actualTargetFile?.path;
2634
2643
  if (targetComponentPath && mod.filePath !== targetComponentPath) {
2635
2644
  debugLog("WARNING: LLM trying to modify non-target file", {
2636
2645
  targetComponent: targetComponentPath,
@@ -2056,6 +2056,124 @@ export async function POST(request: Request) {
2056
2056
  }
2057
2057
  }
2058
2058
 
2059
+ // ========== FILE REDIRECT LOGIC (runs BEFORE building instructions) ==========
2060
+ // This determines the ACTUAL target file by checking for text matches in imported components
2061
+ // Must run first so that all subsequent code uses the correct file path
2062
+ let actualTargetFile = recommendedFileContent || (pageContext.pageContent ? { path: pageContext.pageFile, content: pageContext.pageContent } : null);
2063
+ let elementLocation: { lineNumber: number; snippet: string; confidence: 'high' | 'medium' | 'low'; matchedBy: string } | null = null;
2064
+
2065
+ if (actualTargetFile && focusedElements && focusedElements.length > 0) {
2066
+ const content = actualTargetFile.content;
2067
+
2068
+ // Search for focused element in the file using multiple strategies
2069
+ // Priority: DOM id > textContent > className patterns
2070
+ for (const el of focusedElements) {
2071
+ elementLocation = findElementLineInFile(content, el);
2072
+ if (elementLocation) {
2073
+ debugLog("Found focused element in file", {
2074
+ matchedBy: elementLocation.matchedBy,
2075
+ lineNumber: elementLocation.lineNumber,
2076
+ confidence: elementLocation.confidence,
2077
+ file: actualTargetFile.path,
2078
+ });
2079
+ break;
2080
+ }
2081
+ }
2082
+
2083
+ // TEXT SCORING REDIRECT: Score ALL imported files by how many discovered
2084
+ // text strings they contain. The file with the highest score is the TRUE target.
2085
+ if (elementLocation && elementLocation.confidence !== 'high') {
2086
+ const allTextContent = focusedElements
2087
+ .filter(e => e.textContent && e.textContent.length > 5)
2088
+ .map(e => e.textContent!);
2089
+
2090
+ if (allTextContent.length > 0) {
2091
+ debugLog("Medium/low confidence match - scoring imports for all text", {
2092
+ currentFile: actualTargetFile.path,
2093
+ currentConfidence: elementLocation.confidence,
2094
+ textCount: allTextContent.length,
2095
+ texts: allTextContent.slice(0, 5).map(t => t.substring(0, 25))
2096
+ });
2097
+
2098
+ const bestMatch = scoreFilesForTextContent(
2099
+ allTextContent,
2100
+ pageContext.componentSources
2101
+ );
2102
+
2103
+ const currentFileScore = allTextContent.filter(text =>
2104
+ actualTargetFile!.content.includes(text.substring(0, 20))
2105
+ ).length;
2106
+
2107
+ debugLog("Text scoring comparison", {
2108
+ currentFile: actualTargetFile.path,
2109
+ currentScore: currentFileScore,
2110
+ bestImport: bestMatch?.path || 'none',
2111
+ bestImportScore: bestMatch?.score || 0
2112
+ });
2113
+
2114
+ if (bestMatch && bestMatch.score > currentFileScore) {
2115
+ debugLog("TEXT REDIRECT: Imported file has more text matches", {
2116
+ originalFile: actualTargetFile.path,
2117
+ originalScore: currentFileScore,
2118
+ redirectTo: bestMatch.path,
2119
+ redirectScore: bestMatch.score,
2120
+ matchedTexts: bestMatch.matchedTexts
2121
+ });
2122
+
2123
+ actualTargetFile = {
2124
+ path: bestMatch.path,
2125
+ content: bestMatch.content
2126
+ };
2127
+
2128
+ const lines = bestMatch.content.split('\n');
2129
+ const snippetStart = Math.max(0, bestMatch.firstMatchLine - 4);
2130
+ const snippetEnd = Math.min(lines.length, bestMatch.firstMatchLine + 5);
2131
+
2132
+ elementLocation = {
2133
+ lineNumber: bestMatch.firstMatchLine,
2134
+ snippet: lines.slice(snippetStart, snippetEnd).join('\n'),
2135
+ confidence: 'high',
2136
+ matchedBy: `text scoring: ${bestMatch.score} matches in imported file`
2137
+ };
2138
+ }
2139
+ }
2140
+ }
2141
+
2142
+ // DYNAMIC IMPORT SEARCH: If not found in main file, search imported components
2143
+ if (!elementLocation) {
2144
+ debugLog("Element not in main file, searching imported components...", {
2145
+ mainFile: actualTargetFile.path,
2146
+ importedFilesCount: pageContext.componentSources.length
2147
+ });
2148
+
2149
+ const importedMatch = findElementInImportedFiles(
2150
+ focusedElements[0],
2151
+ pageContext.componentSources
2152
+ );
2153
+
2154
+ if (importedMatch) {
2155
+ debugLog("REDIRECT: Element found in imported component", {
2156
+ originalFile: actualTargetFile.path,
2157
+ redirectTo: importedMatch.path,
2158
+ matchedBy: importedMatch.matchedBy,
2159
+ lineNumber: importedMatch.lineNumber
2160
+ });
2161
+
2162
+ actualTargetFile = {
2163
+ path: importedMatch.path,
2164
+ content: importedMatch.content
2165
+ };
2166
+ elementLocation = findElementLineInFile(importedMatch.content, focusedElements[0]);
2167
+ }
2168
+ }
2169
+ }
2170
+
2171
+ debugLog("File redirect complete", {
2172
+ originalRecommended: recommendedFileContent?.path || 'none',
2173
+ actualTarget: actualTargetFile?.path || 'none',
2174
+ wasRedirected: actualTargetFile?.path !== recommendedFileContent?.path
2175
+ });
2176
+
2059
2177
  // Build text content
2060
2178
  let textContent = `VISION MODE EDIT REQUEST
2061
2179
 
@@ -2079,7 +2197,8 @@ User Request: "${userPrompt}"
2079
2197
 
2080
2198
  // Phase 1: Analyze the screenshot to identify specific problems
2081
2199
  // This is a SEPARATE LLM call that only identifies problems
2082
- const fileContentForAnalysis = recommendedFileContent?.content || pageContext.pageContent || '';
2200
+ // Use actualTargetFile since redirect has already happened
2201
+ const fileContentForAnalysis = actualTargetFile?.content || pageContext.pageContent || '';
2083
2202
  identifiedProblems = await analyzeDesignProblems(
2084
2203
  screenshot,
2085
2204
  fileContentForAnalysis,
@@ -2104,124 +2223,8 @@ User Request: "${userPrompt}"
2104
2223
 
2105
2224
  // ========== TARGET COMPONENT ONLY (with line numbers) ==========
2106
2225
  // CRITICAL: Only include the TARGET file to avoid overwhelming the LLM with noise
2107
- if (recommendedFileContent) {
2108
- const content = recommendedFileContent.content;
2109
-
2110
- // Search for focused element in the file using multiple strategies
2111
- // Priority: DOM id > textContent > className patterns
2112
- let elementLocation: { lineNumber: number; snippet: string; confidence: 'high' | 'medium' | 'low'; matchedBy: string } | null = null;
2113
- let actualTargetFile = recommendedFileContent; // May change if we redirect
2114
-
2115
- if (focusedElements && focusedElements.length > 0) {
2116
- for (const el of focusedElements) {
2117
- elementLocation = findElementLineInFile(content, el);
2118
- if (elementLocation) {
2119
- debugLog("Found focused element in file", {
2120
- matchedBy: elementLocation.matchedBy,
2121
- lineNumber: elementLocation.lineNumber,
2122
- confidence: elementLocation.confidence,
2123
- file: recommendedFileContent.path,
2124
- });
2125
- break;
2126
- }
2127
- }
2128
-
2129
- // TEXT SCORING REDIRECT: Score ALL imported files by how many discovered
2130
- // text strings they contain. The file with the highest score is the TRUE target.
2131
- // This handles parent/child component cases accurately.
2132
- if (elementLocation && elementLocation.confidence !== 'high') {
2133
- // Collect ALL text content from focused elements
2134
- const allTextContent = focusedElements
2135
- .filter(e => e.textContent && e.textContent.length > 5)
2136
- .map(e => e.textContent!);
2137
-
2138
- if (allTextContent.length > 0) {
2139
- debugLog("Medium/low confidence match - scoring imports for all text", {
2140
- currentFile: recommendedFileContent.path,
2141
- currentConfidence: elementLocation.confidence,
2142
- textCount: allTextContent.length,
2143
- texts: allTextContent.slice(0, 5).map(t => t.substring(0, 25))
2144
- });
2145
-
2146
- // Score all imported files
2147
- const bestMatch = scoreFilesForTextContent(
2148
- allTextContent,
2149
- pageContext.componentSources
2150
- );
2151
-
2152
- // Also score the current file for comparison
2153
- const currentFileScore = allTextContent.filter(text =>
2154
- recommendedFileContent.content.includes(text.substring(0, 20))
2155
- ).length;
2156
-
2157
- debugLog("Text scoring comparison", {
2158
- currentFile: recommendedFileContent.path,
2159
- currentScore: currentFileScore,
2160
- bestImport: bestMatch?.path || 'none',
2161
- bestImportScore: bestMatch?.score || 0
2162
- });
2163
-
2164
- // Redirect only if imported file has MORE matches than current file
2165
- if (bestMatch && bestMatch.score > currentFileScore) {
2166
- debugLog("TEXT REDIRECT: Imported file has more text matches", {
2167
- originalFile: recommendedFileContent.path,
2168
- originalScore: currentFileScore,
2169
- redirectTo: bestMatch.path,
2170
- redirectScore: bestMatch.score,
2171
- matchedTexts: bestMatch.matchedTexts
2172
- });
2173
-
2174
- // Switch target file to where most text content lives
2175
- actualTargetFile = {
2176
- path: bestMatch.path,
2177
- content: bestMatch.content
2178
- };
2179
-
2180
- // Find a line with matched text for element location
2181
- const lines = bestMatch.content.split('\n');
2182
- const snippetStart = Math.max(0, bestMatch.firstMatchLine - 4);
2183
- const snippetEnd = Math.min(lines.length, bestMatch.firstMatchLine + 5);
2184
-
2185
- elementLocation = {
2186
- lineNumber: bestMatch.firstMatchLine,
2187
- snippet: lines.slice(snippetStart, snippetEnd).join('\n'),
2188
- confidence: 'high',
2189
- matchedBy: `text scoring: ${bestMatch.score} matches in imported file`
2190
- };
2191
- }
2192
- }
2193
- }
2194
-
2195
- // DYNAMIC IMPORT SEARCH: If not found in main file, search imported components
2196
- if (!elementLocation) {
2197
- debugLog("Element not in main file, searching imported components...", {
2198
- mainFile: recommendedFileContent.path,
2199
- importedFilesCount: pageContext.componentSources.length
2200
- });
2201
-
2202
- const importedMatch = findElementInImportedFiles(
2203
- focusedElements[0],
2204
- pageContext.componentSources
2205
- );
2206
-
2207
- if (importedMatch) {
2208
- debugLog("REDIRECT: Element found in imported component", {
2209
- originalFile: recommendedFileContent.path,
2210
- redirectTo: importedMatch.path,
2211
- matchedBy: importedMatch.matchedBy,
2212
- lineNumber: importedMatch.lineNumber
2213
- });
2214
-
2215
- // Switch target file to where element actually is
2216
- actualTargetFile = {
2217
- path: importedMatch.path,
2218
- content: importedMatch.content
2219
- };
2220
- elementLocation = findElementLineInFile(importedMatch.content, focusedElements[0]);
2221
- }
2222
- }
2223
- }
2224
-
2226
+ // Note: Redirect logic already ran above, so actualTargetFile is the correct file
2227
+ if (actualTargetFile) {
2225
2228
  // Build focused elements section with precise targeting info
2226
2229
  if (focusedElements && focusedElements.length > 0) {
2227
2230
  textContent += `FOCUSED ELEMENTS (user clicked on these):\n`;
@@ -2285,7 +2288,7 @@ ${elementLocation.snippet}
2285
2288
  // Element NOT found in main file OR any imported components
2286
2289
  // BLOCK the LLM from guessing - require empty modifications
2287
2290
  debugLog("BLOCK: Could not locate focused element anywhere", {
2288
- mainFile: recommendedFileContent.path,
2291
+ mainFile: actualTargetFile.path,
2289
2292
  searchedImports: pageContext.componentSources.length,
2290
2293
  focusedElements: focusedElements.map(el => ({
2291
2294
  name: el.name,
@@ -2301,7 +2304,7 @@ ${elementLocation.snippet}
2301
2304
  ⛔ STOP: CANNOT LOCATE THE CLICKED ELEMENT
2302
2305
 
2303
2306
  The user clicked on a specific element, but it could NOT be found in:
2304
- - ${recommendedFileContent.path} (main target file)
2307
+ - ${actualTargetFile.path} (main target file)
2305
2308
  - Any of the ${pageContext.componentSources.length} imported component files
2306
2309
 
2307
2310
  The element may be:
@@ -2343,7 +2346,7 @@ ${linesWithNumbers}
2343
2346
  path: actualTargetFile.path,
2344
2347
  lines: targetContent.split('\n').length,
2345
2348
  size: targetContent.length,
2346
- wasRedirected: actualTargetFile.path !== recommendedFileContent.path
2349
+ wasRedirected: actualTargetFile.path !== recommendedFileContent?.path
2347
2350
  });
2348
2351
  } else if (pageContext.pageContent) {
2349
2352
  // Fallback: use page file if no recommended file
@@ -2416,7 +2419,8 @@ ${variantsMatch[0]}
2416
2419
  }
2417
2420
 
2418
2421
  // ========== SIMPLIFIED INSTRUCTIONS ==========
2419
- const targetPath = recommendedFileContent?.path || pageContext.pageFile || "unknown";
2422
+ // Use actualTargetFile which may have been redirected to an imported component
2423
+ const targetPath = actualTargetFile?.path || pageContext.pageFile || "unknown";
2420
2424
 
2421
2425
  textContent += `═══════════════════════════════════════════════════════════════════════════════
2422
2426
  HOW TO MAKE YOUR EDIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonance-brand-mcp",
3
- "version": "1.3.100",
3
+ "version": "1.3.101",
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",