sonance-brand-mcp 1.3.26 → 1.3.28
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.
|
@@ -50,10 +50,34 @@ interface ApplyFirstRequest {
|
|
|
50
50
|
interface BackupManifest {
|
|
51
51
|
sessionId: string;
|
|
52
52
|
timestamp: number;
|
|
53
|
-
files: {
|
|
53
|
+
files: {
|
|
54
|
+
original: string;
|
|
55
|
+
backup: string;
|
|
56
|
+
isNewFile: boolean; // Track if file was newly created (needs deletion on revert)
|
|
57
|
+
}[];
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
const BACKUP_ROOT = ".sonance-backups";
|
|
61
|
+
const DEBUG_LOG_FILE = "sonance-debug.log";
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Debug logging utility - writes to sonance-debug.log in project root
|
|
65
|
+
* This helps diagnose issues with file discovery, validation, and revert
|
|
66
|
+
*/
|
|
67
|
+
function debugLog(message: string, data?: unknown) {
|
|
68
|
+
const timestamp = new Date().toISOString();
|
|
69
|
+
const dataStr = data !== undefined ? `\n${JSON.stringify(data, null, 2)}` : "";
|
|
70
|
+
const logEntry = `[${timestamp}] [apply] ${message}${dataStr}\n`;
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const logPath = path.join(process.cwd(), DEBUG_LOG_FILE);
|
|
74
|
+
fs.appendFileSync(logPath, logEntry);
|
|
75
|
+
// Also log to console for terminal visibility
|
|
76
|
+
console.log(`[Sonance] ${message}`, data !== undefined ? data : "");
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.error("[Sonance] Failed to write debug log:", e);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
57
81
|
|
|
58
82
|
const VISION_SYSTEM_PROMPT = `You are an expert React/TypeScript developer with vision capabilities. You can see screenshots and modify code.
|
|
59
83
|
|
|
@@ -373,6 +397,12 @@ CRITICAL: Your modified file should have approximately the same number of lines
|
|
|
373
397
|
validFilePaths.add(comp.path);
|
|
374
398
|
}
|
|
375
399
|
|
|
400
|
+
debugLog("VALIDATION: Valid file paths from page context", {
|
|
401
|
+
pageFile: pageContext.pageFile,
|
|
402
|
+
validFilePaths: Array.from(validFilePaths),
|
|
403
|
+
aiRequestedFiles: aiResponse.modifications.map(m => m.filePath)
|
|
404
|
+
});
|
|
405
|
+
|
|
376
406
|
// Process modifications - apply patches to get modified content
|
|
377
407
|
const modifications: VisionFileModification[] = [];
|
|
378
408
|
const patchErrors: string[] = [];
|
|
@@ -380,7 +410,15 @@ CRITICAL: Your modified file should have approximately the same number of lines
|
|
|
380
410
|
for (const mod of aiResponse.modifications) {
|
|
381
411
|
// Validate that the file path is in the page context
|
|
382
412
|
// This prevents the AI from creating new files
|
|
383
|
-
|
|
413
|
+
const isValidPath = validFilePaths.has(mod.filePath);
|
|
414
|
+
debugLog(`VALIDATION CHECK: ${mod.filePath}`, {
|
|
415
|
+
isValidPath,
|
|
416
|
+
fileExists: fs.existsSync(path.join(projectRoot, mod.filePath)),
|
|
417
|
+
validPaths: Array.from(validFilePaths)
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
if (!isValidPath) {
|
|
421
|
+
debugLog(`REJECTED: File not in page context`, { filePath: mod.filePath });
|
|
384
422
|
console.warn(`[Apply-First] Rejected modification to unknown file: ${mod.filePath}`);
|
|
385
423
|
console.warn(`[Apply-First] Valid files are: ${Array.from(validFilePaths).join(", ")}`);
|
|
386
424
|
patchErrors.push(`${mod.filePath}: This file was not found in the page context. The AI can only modify existing files that are part of the current page.`);
|
|
@@ -512,6 +550,15 @@ async function applyChangesWithBackup(
|
|
|
512
550
|
const backupDir = path.join(projectRoot, BACKUP_ROOT, sessionId);
|
|
513
551
|
const backupPaths: string[] = [];
|
|
514
552
|
|
|
553
|
+
// Track which files exist before we modify them
|
|
554
|
+
const existingFiles = new Set<string>();
|
|
555
|
+
for (const mod of modifications) {
|
|
556
|
+
const fullPath = path.join(projectRoot, mod.filePath);
|
|
557
|
+
if (fs.existsSync(fullPath)) {
|
|
558
|
+
existingFiles.add(mod.filePath);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
515
562
|
try {
|
|
516
563
|
// Step 1: Create backup directory
|
|
517
564
|
fs.mkdirSync(backupDir, { recursive: true });
|
|
@@ -520,7 +567,7 @@ async function applyChangesWithBackup(
|
|
|
520
567
|
for (const mod of modifications) {
|
|
521
568
|
const fullPath = path.join(projectRoot, mod.filePath);
|
|
522
569
|
|
|
523
|
-
if (
|
|
570
|
+
if (existingFiles.has(mod.filePath)) {
|
|
524
571
|
const backupPath = path.join(backupDir, mod.filePath);
|
|
525
572
|
const backupDirForFile = path.dirname(backupPath);
|
|
526
573
|
|
|
@@ -530,13 +577,14 @@ async function applyChangesWithBackup(
|
|
|
530
577
|
}
|
|
531
578
|
}
|
|
532
579
|
|
|
533
|
-
// Step 3: Write manifest
|
|
580
|
+
// Step 3: Write manifest (track which files are new)
|
|
534
581
|
const manifest: BackupManifest = {
|
|
535
582
|
sessionId,
|
|
536
583
|
timestamp: Date.now(),
|
|
537
584
|
files: modifications.map(m => ({
|
|
538
585
|
original: m.filePath,
|
|
539
586
|
backup: path.join(backupDir, m.filePath),
|
|
587
|
+
isNewFile: !existingFiles.has(m.filePath), // Track if file was newly created
|
|
540
588
|
})),
|
|
541
589
|
};
|
|
542
590
|
|
|
@@ -589,9 +637,11 @@ async function revertFromBackups(
|
|
|
589
637
|
sessionId: string,
|
|
590
638
|
projectRoot: string
|
|
591
639
|
): Promise<{ success: boolean; message: string; filesReverted: number }> {
|
|
640
|
+
debugLog("revertFromBackups called", { sessionId, projectRoot });
|
|
592
641
|
const backupDir = path.join(projectRoot, BACKUP_ROOT, sessionId);
|
|
593
642
|
|
|
594
643
|
if (!fs.existsSync(backupDir)) {
|
|
644
|
+
debugLog("REVERT ERROR: Backup directory not found", { backupDir });
|
|
595
645
|
return {
|
|
596
646
|
success: false,
|
|
597
647
|
message: "Backup session not found",
|
|
@@ -603,7 +653,7 @@ async function revertFromBackups(
|
|
|
603
653
|
const manifestPath = path.join(backupDir, "manifest.json");
|
|
604
654
|
|
|
605
655
|
if (!fs.existsSync(manifestPath)) {
|
|
606
|
-
|
|
656
|
+
debugLog("REVERT ERROR: Manifest not found", { manifestPath });
|
|
607
657
|
return {
|
|
608
658
|
success: false,
|
|
609
659
|
message: "Backup manifest not found",
|
|
@@ -614,26 +664,66 @@ async function revertFromBackups(
|
|
|
614
664
|
const manifest: BackupManifest = JSON.parse(
|
|
615
665
|
fs.readFileSync(manifestPath, "utf-8")
|
|
616
666
|
);
|
|
667
|
+
|
|
668
|
+
debugLog("REVERT: Loaded manifest", {
|
|
669
|
+
sessionId: manifest.sessionId,
|
|
670
|
+
fileCount: manifest.files.length,
|
|
671
|
+
files: manifest.files.map(f => ({ path: f.original, isNewFile: f.isNewFile }))
|
|
672
|
+
});
|
|
617
673
|
|
|
618
674
|
let filesReverted = 0;
|
|
675
|
+
let filesDeleted = 0;
|
|
619
676
|
|
|
620
677
|
for (const file of manifest.files) {
|
|
621
|
-
const backupPath = path.join(backupDir, file.original);
|
|
622
678
|
const originalPath = path.join(projectRoot, file.original);
|
|
679
|
+
debugLog(`REVERT: Processing file`, {
|
|
680
|
+
filePath: file.original,
|
|
681
|
+
isNewFile: file.isNewFile,
|
|
682
|
+
fileExists: fs.existsSync(originalPath)
|
|
683
|
+
});
|
|
623
684
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
685
|
+
// Handle new files - delete them
|
|
686
|
+
if (file.isNewFile) {
|
|
687
|
+
debugLog(`REVERT: Attempting to delete new file`, { originalPath });
|
|
688
|
+
if (fs.existsSync(originalPath)) {
|
|
689
|
+
fs.unlinkSync(originalPath);
|
|
690
|
+
filesDeleted++;
|
|
691
|
+
debugLog(`REVERT: Successfully deleted new file`, { originalPath });
|
|
692
|
+
console.log(`[Revert] Deleted new file: ${file.original}`);
|
|
693
|
+
|
|
694
|
+
// Clean up empty parent directories
|
|
695
|
+
try {
|
|
696
|
+
const parentDir = path.dirname(originalPath);
|
|
697
|
+
const entries = fs.readdirSync(parentDir);
|
|
698
|
+
if (entries.length === 0) {
|
|
699
|
+
fs.rmdirSync(parentDir);
|
|
700
|
+
console.log(`[Revert] Removed empty directory: ${path.dirname(file.original)}`);
|
|
701
|
+
}
|
|
702
|
+
} catch {
|
|
703
|
+
// Ignore errors when cleaning up directories
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
} else {
|
|
707
|
+
// Handle existing files - restore from backup
|
|
708
|
+
const backupPath = path.join(backupDir, file.original);
|
|
709
|
+
if (fs.existsSync(backupPath)) {
|
|
710
|
+
fs.copyFileSync(backupPath, originalPath);
|
|
711
|
+
filesReverted++;
|
|
712
|
+
}
|
|
627
713
|
}
|
|
628
714
|
}
|
|
629
715
|
|
|
630
716
|
// Delete backup directory after successful revert
|
|
631
717
|
fs.rmSync(backupDir, { recursive: true });
|
|
632
718
|
|
|
719
|
+
const message = filesDeleted > 0
|
|
720
|
+
? `Reverted ${filesReverted} file(s), deleted ${filesDeleted} new file(s)`
|
|
721
|
+
: `Reverted ${filesReverted} file(s)`;
|
|
722
|
+
|
|
633
723
|
return {
|
|
634
724
|
success: true,
|
|
635
|
-
message
|
|
636
|
-
filesReverted,
|
|
725
|
+
message,
|
|
726
|
+
filesReverted: filesReverted + filesDeleted,
|
|
637
727
|
};
|
|
638
728
|
} catch (error) {
|
|
639
729
|
console.error("Error reverting from backups:", error);
|
|
@@ -812,8 +902,11 @@ function gatherPageContext(
|
|
|
812
902
|
}
|
|
813
903
|
|
|
814
904
|
function discoverPageFile(route: string, projectRoot: string): string | null {
|
|
905
|
+
debugLog("discoverPageFile called", { route, projectRoot });
|
|
906
|
+
|
|
815
907
|
// Handle root route
|
|
816
908
|
if (route === "/" || route === "") {
|
|
909
|
+
debugLog("Handling root route, checking patterns...");
|
|
817
910
|
const rootPatterns = [
|
|
818
911
|
// App Router patterns
|
|
819
912
|
"src/app/page.tsx",
|
|
@@ -860,18 +953,26 @@ function discoverPageFile(route: string, projectRoot: string): string | null {
|
|
|
860
953
|
];
|
|
861
954
|
|
|
862
955
|
for (const pattern of patterns) {
|
|
863
|
-
|
|
956
|
+
const fullPath = path.join(projectRoot, pattern);
|
|
957
|
+
const exists = fs.existsSync(fullPath);
|
|
958
|
+
debugLog(`Checking exact pattern: ${pattern}`, { exists });
|
|
959
|
+
if (exists) {
|
|
960
|
+
debugLog("Found exact match!", { pattern });
|
|
864
961
|
return pattern;
|
|
865
962
|
}
|
|
866
963
|
}
|
|
867
964
|
|
|
965
|
+
debugLog("No exact match found, trying dynamic route matching...");
|
|
966
|
+
|
|
868
967
|
// If exact match not found, try dynamic route matching
|
|
869
968
|
// e.g., /processes/123 -> src/pages/processes/[id].tsx
|
|
870
969
|
const dynamicResult = findDynamicRoute(cleanRoute, projectRoot);
|
|
871
970
|
if (dynamicResult) {
|
|
971
|
+
debugLog("Found dynamic route match!", { dynamicResult });
|
|
872
972
|
return dynamicResult;
|
|
873
973
|
}
|
|
874
974
|
|
|
975
|
+
debugLog("discoverPageFile: NO FILE FOUND for route", { route });
|
|
875
976
|
return null;
|
|
876
977
|
}
|
|
877
978
|
|
|
@@ -881,6 +982,7 @@ function discoverPageFile(route: string, projectRoot: string): string | null {
|
|
|
881
982
|
*/
|
|
882
983
|
function findDynamicRoute(cleanRoute: string, projectRoot: string): string | null {
|
|
883
984
|
const segments = cleanRoute.split("/");
|
|
985
|
+
debugLog("findDynamicRoute called", { cleanRoute, segments });
|
|
884
986
|
|
|
885
987
|
// Try replacing the last segment with dynamic patterns
|
|
886
988
|
const baseDirs = [
|
|
@@ -895,7 +997,10 @@ function findDynamicRoute(cleanRoute: string, projectRoot: string): string | nul
|
|
|
895
997
|
|
|
896
998
|
for (const baseDir of baseDirs) {
|
|
897
999
|
const basePath = path.join(projectRoot, baseDir);
|
|
898
|
-
if (!fs.existsSync(basePath))
|
|
1000
|
+
if (!fs.existsSync(basePath)) {
|
|
1001
|
+
debugLog(`Base dir does not exist: ${baseDir}`);
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
899
1004
|
|
|
900
1005
|
// Build path with all segments except the last one
|
|
901
1006
|
const parentSegments = segments.slice(0, -1);
|
|
@@ -903,6 +1008,8 @@ function findDynamicRoute(cleanRoute: string, projectRoot: string): string | nul
|
|
|
903
1008
|
? path.join(basePath, ...parentSegments)
|
|
904
1009
|
: basePath;
|
|
905
1010
|
|
|
1011
|
+
debugLog(`Checking parent path for dynamic routes`, { baseDir, parentPath, exists: fs.existsSync(parentPath) });
|
|
1012
|
+
|
|
906
1013
|
if (!fs.existsSync(parentPath)) continue;
|
|
907
1014
|
|
|
908
1015
|
// Check for dynamic route files
|
|
@@ -933,31 +1040,43 @@ function findDynamicRoute(cleanRoute: string, projectRoot: string): string | nul
|
|
|
933
1040
|
// Also scan directory for any dynamic segment pattern [...]
|
|
934
1041
|
try {
|
|
935
1042
|
const entries = fs.readdirSync(parentPath, { withFileTypes: true });
|
|
1043
|
+
const dynamicEntries = entries.filter(e => e.name.startsWith("[") && e.name.includes("]"));
|
|
1044
|
+
debugLog(`Scanning directory for dynamic segments`, { parentPath, dynamicEntries: dynamicEntries.map(e => e.name) });
|
|
1045
|
+
|
|
936
1046
|
for (const entry of entries) {
|
|
937
1047
|
if (entry.name.startsWith("[") && entry.name.includes("]")) {
|
|
1048
|
+
debugLog(`Found dynamic segment: ${entry.name}`, { isDirectory: entry.isDirectory() });
|
|
938
1049
|
for (const ext of extensions) {
|
|
939
1050
|
if (entry.isDirectory()) {
|
|
940
1051
|
// App Router or Pages Router with folder
|
|
941
1052
|
const pagePath = path.join(parentPath, entry.name, `page${ext}`);
|
|
942
1053
|
const indexPath = path.join(parentPath, entry.name, `index${ext}`);
|
|
1054
|
+
debugLog(`Checking dynamic folder paths`, { pagePath, indexPath, pageExists: fs.existsSync(pagePath), indexExists: fs.existsSync(indexPath) });
|
|
943
1055
|
if (fs.existsSync(pagePath)) {
|
|
944
|
-
|
|
1056
|
+
const result = path.relative(projectRoot, pagePath);
|
|
1057
|
+
debugLog(`Found dynamic route (folder/page)!`, { result });
|
|
1058
|
+
return result;
|
|
945
1059
|
}
|
|
946
1060
|
if (fs.existsSync(indexPath)) {
|
|
947
|
-
|
|
1061
|
+
const result = path.relative(projectRoot, indexPath);
|
|
1062
|
+
debugLog(`Found dynamic route (folder/index)!`, { result });
|
|
1063
|
+
return result;
|
|
948
1064
|
}
|
|
949
1065
|
} else if (entry.isFile() && entry.name.endsWith(ext)) {
|
|
950
1066
|
// Pages Router file-based
|
|
951
|
-
|
|
1067
|
+
const result = path.relative(projectRoot, path.join(parentPath, entry.name));
|
|
1068
|
+
debugLog(`Found dynamic route (file)!`, { result });
|
|
1069
|
+
return result;
|
|
952
1070
|
}
|
|
953
1071
|
}
|
|
954
1072
|
}
|
|
955
1073
|
}
|
|
956
|
-
} catch {
|
|
957
|
-
|
|
1074
|
+
} catch (e) {
|
|
1075
|
+
debugLog(`Error scanning directory: ${parentPath}`, { error: String(e) });
|
|
958
1076
|
}
|
|
959
1077
|
}
|
|
960
1078
|
|
|
1079
|
+
debugLog("findDynamicRoute: NO DYNAMIC ROUTE FOUND");
|
|
961
1080
|
return null;
|
|
962
1081
|
}
|
|
963
1082
|
|
|
@@ -56,6 +56,27 @@ interface VisionEditResponse {
|
|
|
56
56
|
error?: string;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
const DEBUG_LOG_FILE = "sonance-debug.log";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Debug logging utility - writes to sonance-debug.log in project root
|
|
63
|
+
* This helps diagnose issues with file discovery, validation, and revert
|
|
64
|
+
*/
|
|
65
|
+
function debugLog(message: string, data?: unknown) {
|
|
66
|
+
const timestamp = new Date().toISOString();
|
|
67
|
+
const dataStr = data !== undefined ? `\n${JSON.stringify(data, null, 2)}` : "";
|
|
68
|
+
const logEntry = `[${timestamp}] [edit] ${message}${dataStr}\n`;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const logPath = path.join(process.cwd(), DEBUG_LOG_FILE);
|
|
72
|
+
fs.appendFileSync(logPath, logEntry);
|
|
73
|
+
// Also log to console for terminal visibility
|
|
74
|
+
console.log(`[Sonance] ${message}`, data !== undefined ? data : "");
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error("[Sonance] Failed to write debug log:", e);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
59
80
|
const VISION_SYSTEM_PROMPT = `You are an expert React/TypeScript developer with vision capabilities. You can see screenshots and modify code.
|
|
60
81
|
|
|
61
82
|
═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -381,12 +402,19 @@ CRITICAL: Only use file paths from the VALID FILES list above. Do NOT create new
|
|
|
381
402
|
validPaths.add(comp.path);
|
|
382
403
|
}
|
|
383
404
|
|
|
405
|
+
debugLog("VALIDATION: Valid file paths from page context", {
|
|
406
|
+
pageFile: pageContext.pageFile,
|
|
407
|
+
validPaths: Array.from(validPaths),
|
|
408
|
+
aiRequestedFiles: (aiResponse.modifications || []).map(m => m.filePath)
|
|
409
|
+
});
|
|
410
|
+
|
|
384
411
|
// Validate AI response - reject any file paths not in our valid list
|
|
385
412
|
const invalidMods = (aiResponse.modifications || []).filter(
|
|
386
413
|
(mod) => !validPaths.has(mod.filePath)
|
|
387
414
|
);
|
|
388
415
|
|
|
389
416
|
if (invalidMods.length > 0) {
|
|
417
|
+
debugLog("REJECTED: AI attempted to create new files", { invalidMods: invalidMods.map(m => m.filePath) });
|
|
390
418
|
console.error(
|
|
391
419
|
"AI attempted to create new files:",
|
|
392
420
|
invalidMods.map((m) => m.filePath)
|
|
@@ -761,8 +789,11 @@ function gatherPageContext(
|
|
|
761
789
|
* Supports both App Router (src/app/) and Pages Router (src/pages/, pages/)
|
|
762
790
|
*/
|
|
763
791
|
function discoverPageFile(route: string, projectRoot: string): string | null {
|
|
792
|
+
debugLog("discoverPageFile called", { route, projectRoot });
|
|
793
|
+
|
|
764
794
|
// Handle root route
|
|
765
795
|
if (route === "/" || route === "") {
|
|
796
|
+
debugLog("Handling root route, checking patterns...");
|
|
766
797
|
const rootPatterns = [
|
|
767
798
|
// App Router patterns
|
|
768
799
|
"src/app/page.tsx",
|
|
@@ -810,18 +841,26 @@ function discoverPageFile(route: string, projectRoot: string): string | null {
|
|
|
810
841
|
];
|
|
811
842
|
|
|
812
843
|
for (const pattern of patterns) {
|
|
813
|
-
|
|
844
|
+
const fullPath = path.join(projectRoot, pattern);
|
|
845
|
+
const exists = fs.existsSync(fullPath);
|
|
846
|
+
debugLog(`Checking exact pattern: ${pattern}`, { exists });
|
|
847
|
+
if (exists) {
|
|
848
|
+
debugLog("Found exact match!", { pattern });
|
|
814
849
|
return pattern;
|
|
815
850
|
}
|
|
816
851
|
}
|
|
817
852
|
|
|
853
|
+
debugLog("No exact match found, trying dynamic route matching...");
|
|
854
|
+
|
|
818
855
|
// If exact match not found, try dynamic route matching
|
|
819
856
|
// e.g., /processes/123 -> src/pages/processes/[id].tsx
|
|
820
857
|
const dynamicResult = findDynamicRoute(cleanRoute, projectRoot);
|
|
821
858
|
if (dynamicResult) {
|
|
859
|
+
debugLog("Found dynamic route match!", { dynamicResult });
|
|
822
860
|
return dynamicResult;
|
|
823
861
|
}
|
|
824
862
|
|
|
863
|
+
debugLog("discoverPageFile: NO FILE FOUND for route", { route });
|
|
825
864
|
return null;
|
|
826
865
|
}
|
|
827
866
|
|
|
@@ -831,6 +870,7 @@ function discoverPageFile(route: string, projectRoot: string): string | null {
|
|
|
831
870
|
*/
|
|
832
871
|
function findDynamicRoute(cleanRoute: string, projectRoot: string): string | null {
|
|
833
872
|
const segments = cleanRoute.split("/");
|
|
873
|
+
debugLog("findDynamicRoute called", { cleanRoute, segments });
|
|
834
874
|
|
|
835
875
|
// Try replacing the last segment with dynamic patterns
|
|
836
876
|
const baseDirs = [
|
|
@@ -845,7 +885,10 @@ function findDynamicRoute(cleanRoute: string, projectRoot: string): string | nul
|
|
|
845
885
|
|
|
846
886
|
for (const baseDir of baseDirs) {
|
|
847
887
|
const basePath = path.join(projectRoot, baseDir);
|
|
848
|
-
if (!fs.existsSync(basePath))
|
|
888
|
+
if (!fs.existsSync(basePath)) {
|
|
889
|
+
debugLog(`Base dir does not exist: ${baseDir}`);
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
849
892
|
|
|
850
893
|
// Build path with all segments except the last one
|
|
851
894
|
const parentSegments = segments.slice(0, -1);
|
|
@@ -853,6 +896,8 @@ function findDynamicRoute(cleanRoute: string, projectRoot: string): string | nul
|
|
|
853
896
|
? path.join(basePath, ...parentSegments)
|
|
854
897
|
: basePath;
|
|
855
898
|
|
|
899
|
+
debugLog(`Checking parent path for dynamic routes`, { baseDir, parentPath, exists: fs.existsSync(parentPath) });
|
|
900
|
+
|
|
856
901
|
if (!fs.existsSync(parentPath)) continue;
|
|
857
902
|
|
|
858
903
|
// Check for dynamic route files
|
|
@@ -883,31 +928,43 @@ function findDynamicRoute(cleanRoute: string, projectRoot: string): string | nul
|
|
|
883
928
|
// Also scan directory for any dynamic segment pattern [...]
|
|
884
929
|
try {
|
|
885
930
|
const entries = fs.readdirSync(parentPath, { withFileTypes: true });
|
|
931
|
+
const dynamicEntries = entries.filter(e => e.name.startsWith("[") && e.name.includes("]"));
|
|
932
|
+
debugLog(`Scanning directory for dynamic segments`, { parentPath, dynamicEntries: dynamicEntries.map(e => e.name) });
|
|
933
|
+
|
|
886
934
|
for (const entry of entries) {
|
|
887
935
|
if (entry.name.startsWith("[") && entry.name.includes("]")) {
|
|
936
|
+
debugLog(`Found dynamic segment: ${entry.name}`, { isDirectory: entry.isDirectory() });
|
|
888
937
|
for (const ext of extensions) {
|
|
889
938
|
if (entry.isDirectory()) {
|
|
890
939
|
// App Router or Pages Router with folder
|
|
891
940
|
const pagePath = path.join(parentPath, entry.name, `page${ext}`);
|
|
892
941
|
const indexPath = path.join(parentPath, entry.name, `index${ext}`);
|
|
942
|
+
debugLog(`Checking dynamic folder paths`, { pagePath, indexPath, pageExists: fs.existsSync(pagePath), indexExists: fs.existsSync(indexPath) });
|
|
893
943
|
if (fs.existsSync(pagePath)) {
|
|
894
|
-
|
|
944
|
+
const result = path.relative(projectRoot, pagePath);
|
|
945
|
+
debugLog(`Found dynamic route (folder/page)!`, { result });
|
|
946
|
+
return result;
|
|
895
947
|
}
|
|
896
948
|
if (fs.existsSync(indexPath)) {
|
|
897
|
-
|
|
949
|
+
const result = path.relative(projectRoot, indexPath);
|
|
950
|
+
debugLog(`Found dynamic route (folder/index)!`, { result });
|
|
951
|
+
return result;
|
|
898
952
|
}
|
|
899
953
|
} else if (entry.isFile() && entry.name.endsWith(ext)) {
|
|
900
954
|
// Pages Router file-based
|
|
901
|
-
|
|
955
|
+
const result = path.relative(projectRoot, path.join(parentPath, entry.name));
|
|
956
|
+
debugLog(`Found dynamic route (file)!`, { result });
|
|
957
|
+
return result;
|
|
902
958
|
}
|
|
903
959
|
}
|
|
904
960
|
}
|
|
905
961
|
}
|
|
906
|
-
} catch {
|
|
907
|
-
|
|
962
|
+
} catch (e) {
|
|
963
|
+
debugLog(`Error scanning directory: ${parentPath}`, { error: String(e) });
|
|
908
964
|
}
|
|
909
965
|
}
|
|
910
966
|
|
|
967
|
+
debugLog("findDynamicRoute: NO DYNAMIC ROUTE FOUND");
|
|
911
968
|
return null;
|
|
912
969
|
}
|
|
913
970
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonance-brand-mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.28",
|
|
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",
|