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.
|
|
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",
|