sonance-brand-mcp 1.3.64 → 1.3.65
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.
|
@@ -4,6 +4,7 @@ import * as path from "path";
|
|
|
4
4
|
import Anthropic from "@anthropic-ai/sdk";
|
|
5
5
|
import { randomUUID } from "crypto";
|
|
6
6
|
import { discoverTheme } from "./theme-discovery";
|
|
7
|
+
import * as babelParser from "@babel/parser";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Sonance DevTools API - Apply-First Vision Mode
|
|
@@ -86,6 +87,39 @@ function debugLog(message: string, data?: unknown) {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
/**
|
|
91
|
+
* AST-based syntax validation using Babel parser
|
|
92
|
+
* This catches actual syntax errors, not just tag counting
|
|
93
|
+
*/
|
|
94
|
+
function validateSyntaxWithAST(content: string, filePath: string): { valid: boolean; error?: string } {
|
|
95
|
+
// Only validate JSX/TSX files
|
|
96
|
+
if (!filePath.endsWith('.tsx') && !filePath.endsWith('.jsx') && !filePath.endsWith('.ts') && !filePath.endsWith('.js')) {
|
|
97
|
+
return { valid: true };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const isTypeScript = filePath.endsWith('.tsx') || filePath.endsWith('.ts');
|
|
102
|
+
const hasJsx = filePath.endsWith('.tsx') || filePath.endsWith('.jsx');
|
|
103
|
+
|
|
104
|
+
const plugins: babelParser.ParserPlugin[] = [];
|
|
105
|
+
if (isTypeScript) plugins.push('typescript');
|
|
106
|
+
if (hasJsx) plugins.push('jsx');
|
|
107
|
+
|
|
108
|
+
babelParser.parse(content, {
|
|
109
|
+
sourceType: 'module',
|
|
110
|
+
plugins,
|
|
111
|
+
});
|
|
112
|
+
return { valid: true };
|
|
113
|
+
} catch (e: unknown) {
|
|
114
|
+
const error = e as { message?: string; loc?: { line: number; column: number } };
|
|
115
|
+
const location = error.loc ? ` at line ${error.loc.line}, column ${error.loc.column}` : '';
|
|
116
|
+
return {
|
|
117
|
+
valid: false,
|
|
118
|
+
error: `Syntax error in ${filePath}${location}: ${error.message || 'Unknown parse error'}`
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
89
123
|
/**
|
|
90
124
|
* Result of LLM screenshot analysis for smart file discovery
|
|
91
125
|
*/
|
|
@@ -1236,32 +1270,17 @@ This is better than generating patches with made-up code.`,
|
|
|
1236
1270
|
console.log(`[Apply-First] All ${mod.patches.length} patches applied successfully to ${mod.filePath}`);
|
|
1237
1271
|
}
|
|
1238
1272
|
|
|
1239
|
-
//
|
|
1240
|
-
// This
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
divs: { open: openDivs, close: closeDivs },
|
|
1251
|
-
spans: { open: openSpans, close: closeSpans },
|
|
1252
|
-
});
|
|
1253
|
-
console.warn(`[Apply-First] ⚠️ SYNTAX WARNING: Tag mismatch in ${mod.filePath}`);
|
|
1254
|
-
console.warn(`[Apply-First] divs: ${openDivs} open, ${closeDivs} close`);
|
|
1255
|
-
console.warn(`[Apply-First] spans: ${openSpans} open, ${closeSpans} close`);
|
|
1256
|
-
|
|
1257
|
-
// If there's a significant mismatch, reject the change
|
|
1258
|
-
const divDiff = Math.abs(openDivs - closeDivs);
|
|
1259
|
-
const spanDiff = Math.abs(openSpans - closeSpans);
|
|
1260
|
-
if (divDiff > 0 || spanDiff > 0) {
|
|
1261
|
-
patchErrors.push(`${mod.filePath}: LLM introduced syntax error - tag mismatch detected (${divDiff} div, ${spanDiff} span). Change rejected.`);
|
|
1262
|
-
continue;
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1273
|
+
// AST VALIDATION: Use Babel parser to catch actual syntax errors
|
|
1274
|
+
// This is more accurate than tag counting and catches real issues
|
|
1275
|
+
const syntaxValidation = validateSyntaxWithAST(modifiedContent, mod.filePath);
|
|
1276
|
+
if (!syntaxValidation.valid) {
|
|
1277
|
+
debugLog("SYNTAX ERROR: AST validation failed", {
|
|
1278
|
+
filePath: mod.filePath,
|
|
1279
|
+
error: syntaxValidation.error,
|
|
1280
|
+
});
|
|
1281
|
+
console.warn(`[Apply-First] ⚠️ SYNTAX ERROR: ${syntaxValidation.error}`);
|
|
1282
|
+
patchErrors.push(`${mod.filePath}: ${syntaxValidation.error}`);
|
|
1283
|
+
continue; // Skip this file, trigger retry
|
|
1265
1284
|
}
|
|
1266
1285
|
} else {
|
|
1267
1286
|
// No patches - skip
|
|
@@ -3,6 +3,7 @@ import * as fs from "fs";
|
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import Anthropic from "@anthropic-ai/sdk";
|
|
5
5
|
import { discoverTheme } from "../sonance-vision-apply/theme-discovery";
|
|
6
|
+
import * as babelParser from "@babel/parser";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Sonance DevTools API - Vision Mode Editor
|
|
@@ -82,6 +83,39 @@ function debugLog(message: string, data?: unknown) {
|
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
/**
|
|
87
|
+
* AST-based syntax validation using Babel parser
|
|
88
|
+
* This catches actual syntax errors, not just tag counting
|
|
89
|
+
*/
|
|
90
|
+
function validateSyntaxWithAST(content: string, filePath: string): { valid: boolean; error?: string } {
|
|
91
|
+
// Only validate JSX/TSX files
|
|
92
|
+
if (!filePath.endsWith('.tsx') && !filePath.endsWith('.jsx') && !filePath.endsWith('.ts') && !filePath.endsWith('.js')) {
|
|
93
|
+
return { valid: true };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const isTypeScript = filePath.endsWith('.tsx') || filePath.endsWith('.ts');
|
|
98
|
+
const hasJsx = filePath.endsWith('.tsx') || filePath.endsWith('.jsx');
|
|
99
|
+
|
|
100
|
+
const plugins: babelParser.ParserPlugin[] = [];
|
|
101
|
+
if (isTypeScript) plugins.push('typescript');
|
|
102
|
+
if (hasJsx) plugins.push('jsx');
|
|
103
|
+
|
|
104
|
+
babelParser.parse(content, {
|
|
105
|
+
sourceType: 'module',
|
|
106
|
+
plugins,
|
|
107
|
+
});
|
|
108
|
+
return { valid: true };
|
|
109
|
+
} catch (e: unknown) {
|
|
110
|
+
const error = e as { message?: string; loc?: { line: number; column: number } };
|
|
111
|
+
const location = error.loc ? ` at line ${error.loc.line}, column ${error.loc.column}` : '';
|
|
112
|
+
return {
|
|
113
|
+
valid: false,
|
|
114
|
+
error: `Syntax error in ${filePath}${location}: ${error.message || 'Unknown parse error'}`
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
85
119
|
/**
|
|
86
120
|
* Result of LLM screenshot analysis for smart file discovery
|
|
87
121
|
*/
|
|
@@ -1209,6 +1243,18 @@ This is better than generating patches with made-up code.`,
|
|
|
1209
1243
|
modifiedContent = patchResult.modifiedContent;
|
|
1210
1244
|
console.log(`[Vision Mode] All ${mod.patches.length} patches applied successfully to ${mod.filePath}`);
|
|
1211
1245
|
}
|
|
1246
|
+
|
|
1247
|
+
// AST VALIDATION: Use Babel parser to catch actual syntax errors
|
|
1248
|
+
const syntaxValidation = validateSyntaxWithAST(modifiedContent, mod.filePath);
|
|
1249
|
+
if (!syntaxValidation.valid) {
|
|
1250
|
+
debugLog("SYNTAX ERROR: AST validation failed", {
|
|
1251
|
+
filePath: mod.filePath,
|
|
1252
|
+
error: syntaxValidation.error,
|
|
1253
|
+
});
|
|
1254
|
+
console.warn(`[Vision Mode] ⚠️ SYNTAX ERROR: ${syntaxValidation.error}`);
|
|
1255
|
+
patchErrors.push(`${mod.filePath}: ${syntaxValidation.error}`);
|
|
1256
|
+
continue; // Skip this file, trigger retry
|
|
1257
|
+
}
|
|
1212
1258
|
} else {
|
|
1213
1259
|
// No patches - skip
|
|
1214
1260
|
console.warn(`[Vision Mode] No patches for ${mod.filePath}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonance-brand-mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.65",
|
|
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",
|