sonance-brand-mcp 1.3.57 → 1.3.58

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.
@@ -40,12 +40,14 @@ interface VisionFileModification {
40
40
  }
41
41
 
42
42
  interface ApplyFirstRequest {
43
- action: "apply" | "accept" | "revert";
43
+ action: "apply" | "accept" | "revert" | "preview";
44
44
  sessionId?: string;
45
45
  screenshot?: string;
46
46
  pageRoute?: string;
47
47
  userPrompt?: string;
48
48
  focusedElements?: VisionFocusedElement[];
49
+ // For applying a previously previewed set of modifications
50
+ previewedModifications?: VisionFileModification[];
49
51
  }
50
52
 
51
53
  interface BackupManifest {
@@ -436,102 +438,41 @@ function searchFilesSmart(
436
438
  return sortedResults.map(r => ({ path: r.path, content: r.content, score: r.score }));
437
439
  }
438
440
 
439
- const VISION_SYSTEM_PROMPT = `You are an expert React/TypeScript developer with vision capabilities. You can see screenshots and modify code.
440
-
441
- ═══════════════════════════════════════════════════════════════════════════════
442
- UNDERSTAND THE USER'S REQUEST NATURALLY
443
- ═══════════════════════════════════════════════════════════════════════════════
444
-
445
- Read the user's request and do exactly what they ask. You know React, TypeScript, Tailwind CSS, and JSX - use that knowledge naturally.
446
-
447
- - If they say "add X", ADD X to the code (don't replace or remove anything else)
448
- - If they say "change X to Y", find X and change it to Y
449
- - If they say "make X bigger/smaller/different color", adjust the relevant properties
450
- - If they say "remove X", remove X
451
- - If they say "wrap X with Y", add Y as a parent around X
452
-
453
- For any change:
454
- 1. Read the code context provided
455
- 2. Understand what the user wants
456
- 3. Generate patches that accomplish exactly that
457
- 4. If adding a component/icon requires an import, include a patch for the import too
458
-
459
- Don't overthink - just make the change the user requested.
460
-
461
- ═══════════════════════════════════════════════════════════════════════════════
462
- PATCH FORMAT
463
- ═══════════════════════════════════════════════════════════════════════════════
464
-
465
- Return search/replace patches (NOT full files). The system applies your patches to the original.
466
-
467
- **Patch Rules:**
468
- - "search" must match the original code EXACTLY (including whitespace/indentation)
469
- - "replace" contains your modified version
470
- - Include 2-4 lines of context in "search" to make it unique
471
- - You may ONLY edit files provided in the PAGE CONTEXT section
472
- - CRITICAL: NEVER invent or guess code. Your "search" string MUST be copied EXACTLY from the provided file content. If you cannot find the exact code to modify, return an empty modifications array.
473
- - If the file content appears truncated, only modify code that is visible in the provided content.
474
-
475
- ═══════════════════════════════════════════════════════════════════════════════
476
- SONANCE BRAND COLOR SYSTEM
477
- ═══════════════════════════════════════════════════════════════════════════════
478
-
479
- **Core Colors:**
480
- - Primary (Charcoal): #333F48 - main text, dark backgrounds
481
- - Accent (Cyan "The Beam"): #00D3C8 - highlights, interactive elements, CTAs
482
- - Success: Green tones - positive states, confirmations
483
- - Warning: Amber/Orange tones - caution states, alerts
484
- - Destructive: Red tones - errors, delete actions
485
-
486
- **CRITICAL CONTRAST RULES:**
487
- When using colored backgrounds, ALWAYS use high-contrast text:
488
-
489
- | Background | Use This Text | NEVER Use |
490
- |-------------------|------------------------------------|-----------------------|
491
- | bg-accent | text-white | text-accent-foreground |
492
- | bg-primary | text-primary-foreground, text-white | text-primary |
493
- | bg-success | text-white | text-success |
494
- | bg-warning | text-white | text-warning |
495
- | bg-destructive | text-white | text-destructive |
496
-
497
- **SEMANTIC TOKEN PATTERNS:**
498
- - text-{color} = the color itself (use on NEUTRAL backgrounds like white/gray)
499
- - text-{color}-foreground = INTENDED for text on {color} backgrounds, but MAY have contrast issues
500
- - bg-{color} = background in that color
501
- - WHEN IN DOUBT: Use text-white on any colored background for guaranteed contrast
502
-
503
- **BUTTON PATTERNS (Sonance Standard):**
504
- - Primary CTA: bg-primary text-primary-foreground
505
- - Accent/Highlight: bg-accent text-white (NOT text-accent-foreground)
506
- - Success: bg-success text-white
507
- - Warning: bg-warning text-white
508
- - Destructive: bg-destructive text-white
509
- - Outlined: border-border bg-transparent text-foreground
510
-
511
- **COMMON MISTAKES TO AVOID:**
512
- - WRONG: bg-accent text-accent-foreground (accent-foreground is often dark = invisible text)
513
- - RIGHT: bg-accent text-white (white text on cyan = visible)
514
- - WRONG: bg-primary text-primary (same color = invisible)
515
- - RIGHT: bg-primary text-primary-foreground OR text-white
516
-
517
- **RESPONSE FORMAT:**
518
- CRITICAL: Return ONLY the JSON object below. Do NOT include any text, explanation, or thinking before or after the JSON. No preamble. No "Looking at the screenshot..." No markdown code blocks. Just raw JSON:
441
+ const VISION_SYSTEM_PROMPT = `You are a code editor. Make ONLY the change the user requested.
442
+
443
+ RULES:
444
+ 1. Make the SMALLEST possible change to accomplish the request
445
+ 2. Do NOT refactor, rebrand, or "improve" anything else
446
+ 3. Do NOT change import statements unless explicitly required
447
+ 4. Do NOT change component libraries (e.g., heroui to shadcn)
448
+ 5. If fixing a color/visibility issue, change ONLY that element's classes
449
+ 6. Your patch should typically be 1-5 lines, not 50+
450
+ 7. NEVER invent or guess code - your "search" string MUST match the file EXACTLY
451
+ 8. NEVER change data mappings (icon names, keys, enum values) unless user explicitly provides the new values
452
+ 9. If you don't know what values exist in a database or data source, DO NOT guess - ask for clarification
453
+
454
+ CRITICAL - DATA INTEGRITY:
455
+ - If code references database values (like icon_name, type, status), DO NOT change the mapping keys
456
+ - You cannot see database content - only change STRUCTURE, not DATA MAPPINGS
457
+ - Example: If you see iconMap["EyeOff"] = SomeIcon, do NOT change "EyeOff" to something else
458
+ - If user wants different icons, they must tell you the EXACT icon names they want
459
+
460
+ PATCH FORMAT:
461
+ Return ONLY raw JSON (no markdown, no preamble):
519
462
  {
520
- "reasoning": "What you understood from the request and your plan",
521
- "modifications": [
522
- {
523
- "filePath": "path/to/file.tsx",
524
- "patches": [
525
- {
526
- "search": "exact code to find",
527
- "replace": "the replacement code",
528
- "explanation": "what this patch does"
529
- }
530
- ]
531
- }
532
- ],
533
- "explanation": "summary of changes made"
534
- }`;
463
+ "reasoning": "brief explanation",
464
+ "modifications": [{
465
+ "filePath": "path/to/file.tsx",
466
+ "patches": [{
467
+ "search": "exact original code (copy from provided file)",
468
+ "replace": "minimal change",
469
+ "explanation": "what this does"
470
+ }]
471
+ }],
472
+ "explanation": "summary"
473
+ }
474
+
475
+ If you cannot find the exact code to modify, OR if you would need to guess data values, return empty modifications array with explanation.`;
535
476
 
536
477
  export async function POST(request: Request) {
537
478
  // Only allow in development
@@ -544,7 +485,7 @@ export async function POST(request: Request) {
544
485
 
545
486
  try {
546
487
  const body: ApplyFirstRequest = await request.json();
547
- const { action, sessionId, screenshot, pageRoute, userPrompt, focusedElements } = body;
488
+ const { action, sessionId, screenshot, pageRoute, userPrompt, focusedElements, previewedModifications } = body;
548
489
  const projectRoot = process.cwd();
549
490
 
550
491
  // ========== ACCEPT ACTION ==========
@@ -571,6 +512,8 @@ export async function POST(request: Request) {
571
512
 
572
513
  // ========== REVERT ACTION ==========
573
514
  if (action === "revert") {
515
+ console.log(`[Apply-First] Revert requested for session: ${sessionId}`);
516
+
574
517
  if (!sessionId) {
575
518
  return NextResponse.json(
576
519
  { error: "sessionId is required for revert action" },
@@ -579,6 +522,7 @@ export async function POST(request: Request) {
579
522
  }
580
523
 
581
524
  const result = await revertFromBackups(sessionId, projectRoot);
525
+ console.log(`[Apply-First] Revert result:`, result);
582
526
 
583
527
  return NextResponse.json({
584
528
  success: result.success,
@@ -588,11 +532,44 @@ export async function POST(request: Request) {
588
532
  });
589
533
  }
590
534
 
591
- // ========== APPLY ACTION ==========
592
- if (action === "apply") {
535
+ // ========== APPLY FROM PREVIEW ACTION ==========
536
+ // When user accepts a preview, apply the previously generated modifications
537
+ if (action === "apply" && previewedModifications && previewedModifications.length > 0) {
538
+ debugLog("Applying previewed modifications", {
539
+ count: previewedModifications.length,
540
+ files: previewedModifications.map(m => m.filePath)
541
+ });
542
+
543
+ const newSessionId = randomUUID().slice(0, 8);
544
+
545
+ const applyResult = await applyChangesWithBackup(
546
+ previewedModifications,
547
+ newSessionId,
548
+ projectRoot
549
+ );
550
+
551
+ if (!applyResult.success) {
552
+ return NextResponse.json(
553
+ { error: applyResult.error || "Failed to apply previewed changes" },
554
+ { status: 500 }
555
+ );
556
+ }
557
+
558
+ return NextResponse.json({
559
+ success: true,
560
+ sessionId: newSessionId,
561
+ modifications: previewedModifications,
562
+ backupPaths: applyResult.backupPaths,
563
+ explanation: "Applied previewed changes",
564
+ });
565
+ }
566
+
567
+ // ========== APPLY/PREVIEW ACTION (with LLM) ==========
568
+ // Both actions do LLM work; "preview" returns without writing, "apply" writes to files
569
+ if (action === "apply" || action === "preview") {
593
570
  if (!userPrompt) {
594
571
  return NextResponse.json(
595
- { error: "userPrompt is required for apply action" },
572
+ { error: "userPrompt is required for apply/preview action" },
596
573
  { status: 400 }
597
574
  );
598
575
  }
@@ -699,141 +676,6 @@ export async function POST(request: Request) {
699
676
  });
700
677
  }
701
678
 
702
- // ========== PHASE A: VISUAL PROBLEM ANALYSIS ==========
703
- // Before generating patches, analyze WHAT is visually wrong
704
- // This forces the LLM to articulate the problem before trying to fix it
705
- interface VisualAnalysis {
706
- element: string;
707
- elementText: string; // The visible text content of the element (for finding in code)
708
- problem: string;
709
- changeType: "styling" | "structural" | "content" | "other";
710
- currentClasses?: string; // For styling changes: what classes appear to be applied
711
- classChange?: {
712
- remove?: string[]; // Classes to remove
713
- add?: string[]; // Classes to add
714
- };
715
- structuralChange?: string; // For structural changes: what to add/remove/wrap
716
- solution: string;
717
- confidence: "high" | "medium" | "low";
718
- }
719
-
720
- let visualAnalysis: VisualAnalysis | null = null;
721
-
722
- if (screenshot && userPrompt) {
723
- debugLog("Phase A: Starting visual problem analysis");
724
-
725
- const analysisClient = new Anthropic({ apiKey });
726
-
727
- try {
728
- const analysisResponse = await analysisClient.messages.create({
729
- model: "claude-sonnet-4-20250514",
730
- max_tokens: 1024,
731
- messages: [
732
- {
733
- role: "user",
734
- content: [
735
- {
736
- type: "image",
737
- source: {
738
- type: "base64",
739
- media_type: "image/png",
740
- data: base64Data,
741
- },
742
- },
743
- {
744
- type: "text",
745
- text: `You are analyzing a UI screenshot to understand what the user wants changed.
746
-
747
- User request: "${userPrompt}"
748
-
749
- ${focusedElements && focusedElements.length > 0 ? `User clicked on these elements:
750
- ${focusedElements.map((el) => `- ${el.name} (${el.type}) at position (${el.coordinates.x}, ${el.coordinates.y})`).join("\n")}
751
- ` : ""}
752
-
753
- Analyze the request and determine:
754
- 1. ELEMENT: Which specific UI element needs to change? (describe location and appearance)
755
- 2. ELEMENT TEXT: What text is visible inside this element? (EXACT text for finding in code)
756
- 3. PROBLEM: What is wrong or what does the user want changed?
757
- 4. CHANGE TYPE: Is this a "styling" (colors/size/spacing), "structural" (add/remove elements), "content" (text changes), or "other" change?
758
- 5. For STYLING changes: What Tailwind classes should be REMOVED and what should be ADDED?
759
- 6. For STRUCTURAL changes: What element should be added, removed, or wrapped?
760
- 7. SOLUTION: Describe the complete fix
761
- 8. CONFIDENCE: high/medium/low
762
-
763
- IMPORTANT for styling fixes:
764
- - If text is invisible on a background, typically REMOVE the problematic text color class and ADD a contrasting one
765
- - Common fix for invisible text on colored backgrounds: REMOVE "text-accent-foreground" or similar, ADD "text-white" or "text-black"
766
- - Be SPECIFIC about exact class names
767
-
768
- Return ONLY valid JSON:
769
- {
770
- "element": "description of the UI element",
771
- "elementText": "exact visible text in the element",
772
- "problem": "what is wrong",
773
- "changeType": "styling",
774
- "currentClasses": "classes that appear to be applied (best guess)",
775
- "classChange": {
776
- "remove": ["text-accent-foreground"],
777
- "add": ["text-white"]
778
- },
779
- "solution": "complete description of the fix",
780
- "confidence": "high"
781
- }
782
-
783
- For structural changes:
784
- {
785
- "element": "description of the UI element",
786
- "elementText": "text near the element",
787
- "problem": "what is wrong",
788
- "changeType": "structural",
789
- "structuralChange": "Add a new button after the existing one",
790
- "solution": "complete description of the fix",
791
- "confidence": "high"
792
- }`,
793
- },
794
- ],
795
- },
796
- ],
797
- });
798
-
799
- const analysisText = analysisResponse.content.find((block) => block.type === "text");
800
- if (analysisText && analysisText.type === "text") {
801
- // Parse the JSON response
802
- let jsonText = analysisText.text.trim();
803
- // Extract JSON if wrapped in code blocks
804
- const jsonMatch = jsonText.match(/```(?:json)?\s*([\s\S]*?)\s*```/) || jsonText.match(/(\{[\s\S]*\})/);
805
- if (jsonMatch) {
806
- jsonText = jsonMatch[1];
807
- }
808
-
809
- try {
810
- visualAnalysis = JSON.parse(jsonText) as VisualAnalysis;
811
- debugLog("Phase A: Visual problem analysis complete", visualAnalysis);
812
-
813
- // If low confidence, return early with clarification request
814
- if (visualAnalysis.confidence === "low") {
815
- debugLog("Phase A: Low confidence - requesting clarification");
816
- return NextResponse.json({
817
- success: false,
818
- needsClarification: true,
819
- analysis: visualAnalysis,
820
- message: `I can see "${visualAnalysis.element}" but I'm not certain about the problem: "${visualAnalysis.problem}". Can you be more specific about what needs to change?`,
821
- });
822
- }
823
- } catch (parseError) {
824
- debugLog("Phase A: Failed to parse analysis response", {
825
- error: String(parseError),
826
- response: jsonText.substring(0, 500)
827
- });
828
- // Continue without analysis if parsing fails
829
- }
830
- }
831
- } catch (analysisError) {
832
- debugLog("Phase A: Analysis call failed", { error: String(analysisError) });
833
- // Continue without analysis - fall back to existing behavior
834
- }
835
- }
836
-
837
679
  // ========== SMART CONTEXT BUDGETING ==========
838
680
  // Claude can handle 200k tokens (~800k chars), so we can safely include large files
839
681
  // Priority: Recommended file (NEVER truncate) > Page file (limited) > Other components (dynamic)
@@ -870,58 +712,6 @@ ${focusedElements.map((el) => `- ${el.name} (${el.type}) at (${el.coordinates.x}
870
712
  `;
871
713
  }
872
714
 
873
- // ========== VISUAL PROBLEM ANALYSIS (from Phase A) ==========
874
- if (visualAnalysis) {
875
- let analysisInstructions = `═══════════════════════════════════════════════════════════════════════════════
876
- 🔍 VISUAL PROBLEM ANALYSIS (I analyzed the screenshot first)
877
- ═══════════════════════════════════════════════════════════════════════════════
878
-
879
- **Element:** ${visualAnalysis.element}
880
- **Element Text:** "${visualAnalysis.elementText || "unknown"}"
881
- **Problem:** ${visualAnalysis.problem}
882
- **Change Type:** ${visualAnalysis.changeType}
883
- **Solution:** ${visualAnalysis.solution}
884
- **Confidence:** ${visualAnalysis.confidence}
885
-
886
- `;
887
-
888
- // Add specific instructions based on change type
889
- if (visualAnalysis.changeType === "styling" && visualAnalysis.classChange) {
890
- analysisInstructions += `🎯 EXACT CLASS CHANGES REQUIRED:
891
- `;
892
- if (visualAnalysis.classChange.remove && visualAnalysis.classChange.remove.length > 0) {
893
- analysisInstructions += ` REMOVE these classes: ${visualAnalysis.classChange.remove.join(", ")}
894
- `;
895
- }
896
- if (visualAnalysis.classChange.add && visualAnalysis.classChange.add.length > 0) {
897
- analysisInstructions += ` ADD these classes: ${visualAnalysis.classChange.add.join(", ")}
898
- `;
899
- }
900
- analysisInstructions += `
901
- ⚠️ YOUR PATCH MUST:
902
- 1. Find the element containing "${visualAnalysis.elementText || visualAnalysis.element}"
903
- 2. In its className, ${visualAnalysis.classChange.remove?.length ? `REMOVE: ${visualAnalysis.classChange.remove.join(", ")}` : ""}
904
- 3. ${visualAnalysis.classChange.add?.length ? `ADD: ${visualAnalysis.classChange.add.join(", ")}` : ""}
905
- 4. Do NOT add unrelated changes like font-weight or hover states unless specifically requested
906
-
907
- `;
908
- } else if (visualAnalysis.changeType === "structural" && visualAnalysis.structuralChange) {
909
- analysisInstructions += `🔧 STRUCTURAL CHANGE REQUIRED:
910
- ${visualAnalysis.structuralChange}
911
-
912
- ⚠️ YOUR PATCH MUST implement this structural change exactly as described.
913
-
914
- `;
915
- } else {
916
- analysisInstructions += `⚠️ IMPORTANT: Your patches MUST implement the fix described above.
917
- Find the code that renders "${visualAnalysis.element}" and apply: ${visualAnalysis.solution}
918
-
919
- `;
920
- }
921
-
922
- textContent += analysisInstructions;
923
- }
924
-
925
715
  // ========== TARGET COMPONENT (RECOMMENDED FILE) - SHOWN FIRST ==========
926
716
  if (recommendedFileContent) {
927
717
  // Never truncate the recommended file - AI needs full context to avoid hallucination
@@ -986,17 +776,27 @@ ${truncatedContent}${wasTruncated ? "\n// ... (truncated)" : ""}
986
776
  }
987
777
  }
988
778
 
989
- // ========== THEME DISCOVERY ==========
779
+ // ========== THEME DISCOVERY (REFERENCE ONLY) ==========
990
780
  // Dynamically discover theme tokens from the target codebase
781
+ // This is marked as REFERENCE ONLY so the LLM doesn't use it to justify extra changes
991
782
  const discoveredTheme = await discoverTheme(projectRoot);
992
783
  const themeContext = formatThemeForPrompt(discoveredTheme);
993
784
 
994
785
  if (discoveredTheme.discoveredFiles.length > 0) {
995
786
  textContent += `
996
787
  ═══════════════════════════════════════════════════════════════════════════════
997
- ${themeContext}
788
+ REFERENCE ONLY (do not use this to justify additional changes)
998
789
  ═══════════════════════════════════════════════════════════════════════════════
999
790
 
791
+ If you need to pick a color for a VISIBILITY fix, these are safe choices:
792
+ - bg-accent text-white (cyan button with white text)
793
+ - bg-primary text-white (charcoal button with white text)
794
+ - bg-success text-white (green button with white text)
795
+ - bg-destructive text-white (red button with white text)
796
+
797
+ But ONLY use these if the user is asking for a color/visibility change.
798
+ Do NOT rebrand or change other elements to match.
799
+
1000
800
  `;
1001
801
  debugLog("Theme discovery complete", {
1002
802
  filesFound: discoveredTheme.discoveredFiles,
@@ -1369,7 +1169,23 @@ This is better than generating patches with made-up code.`,
1369
1169
  break;
1370
1170
  } // End of retry loop
1371
1171
 
1372
- // Create backups and apply changes atomically
1172
+ // ========== PREVIEW MODE: Return modifications without writing ==========
1173
+ if (action === "preview") {
1174
+ debugLog("Preview mode: returning modifications without applying", {
1175
+ fileCount: modifications.length,
1176
+ files: modifications.map(m => m.filePath)
1177
+ });
1178
+
1179
+ return NextResponse.json({
1180
+ success: true,
1181
+ preview: true,
1182
+ modifications,
1183
+ explanation: finalExplanation,
1184
+ reasoning: finalReasoning,
1185
+ });
1186
+ }
1187
+
1188
+ // ========== APPLY MODE: Create backups and apply changes atomically ==========
1373
1189
  const applyResult = await applyChangesWithBackup(
1374
1190
  modifications,
1375
1191
  newSessionId,
@@ -1394,7 +1210,7 @@ This is better than generating patches with made-up code.`,
1394
1210
  }
1395
1211
 
1396
1212
  return NextResponse.json(
1397
- { error: "Invalid action. Use 'apply', 'accept', or 'revert'." },
1213
+ { error: "Invalid action. Use 'apply', 'preview', 'accept', or 'revert'." },
1398
1214
  { status: 400 }
1399
1215
  );
1400
1216
  } catch (error) {
@@ -1414,6 +1230,12 @@ async function applyChangesWithBackup(
1414
1230
  sessionId: string,
1415
1231
  projectRoot: string
1416
1232
  ): Promise<{ success: boolean; backupPaths: string[]; error?: string }> {
1233
+ console.log(`[Apply-First] applyChangesWithBackup called`, {
1234
+ sessionId,
1235
+ fileCount: modifications.length,
1236
+ files: modifications.map(m => m.filePath)
1237
+ });
1238
+
1417
1239
  const backupDir = path.join(projectRoot, BACKUP_ROOT, sessionId);
1418
1240
  const backupPaths: string[] = [];
1419
1241
 
@@ -1428,6 +1250,7 @@ async function applyChangesWithBackup(
1428
1250
 
1429
1251
  try {
1430
1252
  // Step 1: Create backup directory
1253
+ console.log(`[Apply-First] Creating backup directory: ${backupDir}`);
1431
1254
  fs.mkdirSync(backupDir, { recursive: true });
1432
1255
 
1433
1256
  // Step 2: Create ALL backups FIRST (before any writes)
@@ -1441,6 +1264,9 @@ async function applyChangesWithBackup(
1441
1264
  fs.mkdirSync(backupDirForFile, { recursive: true });
1442
1265
  fs.copyFileSync(fullPath, backupPath);
1443
1266
  backupPaths.push(backupPath);
1267
+ console.log(`[Apply-First] Backed up: ${mod.filePath}`);
1268
+ } else {
1269
+ console.log(`[Apply-First] New file (no backup needed): ${mod.filePath}`);
1444
1270
  }
1445
1271
  }
1446
1272
 
@@ -1455,10 +1281,9 @@ async function applyChangesWithBackup(
1455
1281
  })),
1456
1282
  };
1457
1283
 
1458
- fs.writeFileSync(
1459
- path.join(backupDir, "manifest.json"),
1460
- JSON.stringify(manifest, null, 2)
1461
- );
1284
+ const manifestPath = path.join(backupDir, "manifest.json");
1285
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
1286
+ console.log(`[Apply-First] Manifest written: ${manifestPath}`);
1462
1287
 
1463
1288
  // Step 4: Apply all changes
1464
1289
  for (const mod of modifications) {
@@ -1476,8 +1301,10 @@ async function applyChangesWithBackup(
1476
1301
  }
1477
1302
 
1478
1303
  fs.writeFileSync(fullPath, mod.modifiedContent, "utf-8");
1304
+ console.log(`[Apply-First] File written: ${mod.filePath}`);
1479
1305
  }
1480
1306
 
1307
+ console.log(`[Apply-First] All changes applied successfully, session: ${sessionId}`);
1481
1308
  return { success: true, backupPaths };
1482
1309
  } catch (error) {
1483
1310
  // Rollback on error - restore all backed up files