sonance-brand-mcp 1.3.87 → 1.3.88

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.
@@ -981,6 +981,49 @@ export async function POST(request: Request) {
981
981
  const phase2aConfirmed = phase2aMatches.length > 0 &&
982
982
  focusedElementHints.some(h => phase2aMatches.includes(h.path) && h.score > 0);
983
983
 
984
+ // Helper: Find best Phase 2a match based on user prompt keywords
985
+ // e.g., "duplicate button" should prefer ProcessRow.tsx over ProcessCatalogueView.tsx
986
+ const findBestPhase2aMatch = (): string | null => {
987
+ if (phase2aMatches.length === 0) return null;
988
+ if (phase2aMatches.length === 1) return phase2aMatches[0];
989
+
990
+ // Extract keywords from user prompt
991
+ const promptLower = userPrompt.toLowerCase();
992
+ const keywords = ['row', 'cell', 'item', 'button', 'action', 'duplicate', 'edit', 'delete'];
993
+
994
+ // Prefer more specific files (Row > View, Cell > Table, etc.)
995
+ const specificity = ['row', 'cell', 'item', 'card', 'modal', 'panel', 'detail'];
996
+
997
+ // Score each Phase 2a match
998
+ let bestMatch = phase2aMatches[0];
999
+ let bestScore = 0;
1000
+
1001
+ for (const match of phase2aMatches) {
1002
+ const matchLower = match.toLowerCase();
1003
+ let score = 0;
1004
+
1005
+ // Bonus for specificity (Row/Cell/Item components)
1006
+ for (const spec of specificity) {
1007
+ if (matchLower.includes(spec)) score += 10;
1008
+ }
1009
+
1010
+ // Bonus for keyword match (prompt mentions button → prefer file with button/action)
1011
+ for (const kw of keywords) {
1012
+ if (promptLower.includes(kw) && matchLower.includes(kw)) score += 20;
1013
+ }
1014
+
1015
+ // Penalty for generic view/container files
1016
+ if (matchLower.includes('view.tsx') && !matchLower.includes('detail')) score -= 5;
1017
+
1018
+ if (score > bestScore) {
1019
+ bestScore = score;
1020
+ bestMatch = match;
1021
+ }
1022
+ }
1023
+
1024
+ return bestMatch;
1025
+ };
1026
+
984
1027
  if (phase2aConfirmed) {
985
1028
  // PRIORITY 1: Phase 2a match confirmed by element search - highest confidence
986
1029
  const confirmedPath = phase2aMatches.find(p =>
@@ -998,6 +1041,18 @@ export async function POST(request: Request) {
998
1041
  reason: `Focused element match (score: ${focusedTopScore}, exceeds threshold)`
999
1042
  };
1000
1043
  debugLog("PRIORITY 2: Strong focused element match", recommendedFile);
1044
+ } else if (phase2aMatches.length > 0) {
1045
+ // PRIORITY 2.5: Phase 2a match WITHOUT focused element - still strong signal
1046
+ // Use prompt-aware selection to pick the best match
1047
+ const bestMatch = findBestPhase2aMatch()!;
1048
+ recommendedFile = {
1049
+ path: bestMatch,
1050
+ reason: `Phase 2a component-name match (prompt-aware selection from ${phase2aMatches.length} candidates)`
1051
+ };
1052
+ debugLog("PRIORITY 2.5: Phase 2a match (no focused element)", {
1053
+ selectedPath: bestMatch,
1054
+ allCandidates: phase2aMatches
1055
+ });
1001
1056
  } else if (smartSearchTopPath) {
1002
1057
  // PRIORITY 3: Smart search top result - trusted baseline
1003
1058
  recommendedFile = {
@@ -950,6 +950,49 @@ export async function POST(request: Request) {
950
950
  const phase2aConfirmed = phase2aMatches.length > 0 &&
951
951
  focusedElementHints.some(h => phase2aMatches.includes(h.path) && h.score > 0);
952
952
 
953
+ // Helper: Find best Phase 2a match based on user prompt keywords
954
+ // e.g., "duplicate button" should prefer ProcessRow.tsx over ProcessCatalogueView.tsx
955
+ const findBestPhase2aMatch = (): string | null => {
956
+ if (phase2aMatches.length === 0) return null;
957
+ if (phase2aMatches.length === 1) return phase2aMatches[0];
958
+
959
+ // Extract keywords from user prompt
960
+ const promptLower = userPrompt.toLowerCase();
961
+ const keywords = ['row', 'cell', 'item', 'button', 'action', 'duplicate', 'edit', 'delete'];
962
+
963
+ // Prefer more specific files (Row > View, Cell > Table, etc.)
964
+ const specificity = ['row', 'cell', 'item', 'card', 'modal', 'panel', 'detail'];
965
+
966
+ // Score each Phase 2a match
967
+ let bestMatch = phase2aMatches[0];
968
+ let bestScore = 0;
969
+
970
+ for (const match of phase2aMatches) {
971
+ const matchLower = match.toLowerCase();
972
+ let score = 0;
973
+
974
+ // Bonus for specificity (Row/Cell/Item components)
975
+ for (const spec of specificity) {
976
+ if (matchLower.includes(spec)) score += 10;
977
+ }
978
+
979
+ // Bonus for keyword match (prompt mentions button → prefer file with button/action)
980
+ for (const kw of keywords) {
981
+ if (promptLower.includes(kw) && matchLower.includes(kw)) score += 20;
982
+ }
983
+
984
+ // Penalty for generic view/container files
985
+ if (matchLower.includes('view.tsx') && !matchLower.includes('detail')) score -= 5;
986
+
987
+ if (score > bestScore) {
988
+ bestScore = score;
989
+ bestMatch = match;
990
+ }
991
+ }
992
+
993
+ return bestMatch;
994
+ };
995
+
953
996
  if (phase2aConfirmed) {
954
997
  // PRIORITY 1: Phase 2a match confirmed by element search - highest confidence
955
998
  const confirmedPath = phase2aMatches.find(p =>
@@ -967,6 +1010,18 @@ export async function POST(request: Request) {
967
1010
  reason: `Focused element match (score: ${focusedTopScore}, exceeds threshold)`
968
1011
  };
969
1012
  debugLog("PRIORITY 2: Strong focused element match", recommendedFile);
1013
+ } else if (phase2aMatches.length > 0) {
1014
+ // PRIORITY 2.5: Phase 2a match WITHOUT focused element - still strong signal
1015
+ // Use prompt-aware selection to pick the best match
1016
+ const bestMatch = findBestPhase2aMatch()!;
1017
+ recommendedFile = {
1018
+ path: bestMatch,
1019
+ reason: `Phase 2a component-name match (prompt-aware selection from ${phase2aMatches.length} candidates)`
1020
+ };
1021
+ debugLog("PRIORITY 2.5: Phase 2a match (no focused element)", {
1022
+ selectedPath: bestMatch,
1023
+ allCandidates: phase2aMatches
1024
+ });
970
1025
  } else if (smartSearchTopPath) {
971
1026
  // PRIORITY 3: Smart search top result - trusted baseline
972
1027
  recommendedFile = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonance-brand-mcp",
3
- "version": "1.3.87",
3
+ "version": "1.3.88",
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",