@@ -282,31 +282,66 @@ Original error: ${errorMessage}`
282282 ( opResult ) => cline . rooProtectedController ?. isWriteProtected ( opResult . path ) || false ,
283283 )
284284
285- // Prepare batch diff data
286- const batchDiffs = operationsToApprove . map ( ( opResult ) => {
285+ // Stream batch diffs progressively for better UX
286+ const batchDiffs : Array < {
287+ path : string
288+ changeCount : number
289+ key : string
290+ content : string
291+ diffs ?: Array < { content : string ; startLine ?: number } >
292+ } > = [ ]
293+
294+ for ( const opResult of operationsToApprove ) {
287295 const readablePath = getReadablePath ( cline . cwd , opResult . path )
288296 const changeCount = opResult . diffItems ?. length || 0
289297 const changeText = changeCount === 1 ? "1 change" : `${ changeCount } changes`
290298
291- return {
299+ let unified = ""
300+ try {
301+ const original = await fs . readFile ( opResult . absolutePath ! , "utf-8" )
302+ const processed = ! cline . api . getModel ( ) . id . includes ( "claude" )
303+ ? ( opResult . diffItems || [ ] ) . map ( ( item ) => ( {
304+ ...item ,
305+ content : item . content ? unescapeHtmlEntities ( item . content ) : item . content ,
306+ } ) )
307+ : opResult . diffItems || [ ]
308+
309+ const applyRes =
310+ ( await cline . diffStrategy ?. applyDiff ( original , processed ) ) ?? ( { success : false } as any )
311+ const newContent = applyRes . success && applyRes . content ? applyRes . content : original
312+ unified = formatResponse . createPrettyPatch ( opResult . path , original , newContent )
313+ } catch {
314+ unified = ""
315+ }
316+
317+ batchDiffs . push ( {
292318 path : readablePath ,
293319 changeCount,
294320 key : `${ readablePath } (${ changeText } )` ,
295- content : opResult . path , // Full relative path
321+ content : unified ,
296322 diffs : opResult . diffItems ?. map ( ( item ) => ( {
297323 content : item . content ,
298324 startLine : item . startLine ,
299325 } ) ) ,
300- }
301- } )
326+ } )
327+
328+ // Send a partial update after each file preview is ready
329+ const partialMessage = JSON . stringify ( {
330+ tool : "appliedDiff" ,
331+ batchDiffs,
332+ isProtected : hasProtectedFiles ,
333+ } satisfies ClineSayTool )
334+ await cline . ask ( "tool" , partialMessage , true ) . catch ( ( ) => { } )
335+ }
302336
337+ // Final approval message (non-partial)
303338 const completeMessage = JSON . stringify ( {
304339 tool : "appliedDiff" ,
305340 batchDiffs,
306341 isProtected : hasProtectedFiles ,
307342 } satisfies ClineSayTool )
308343
309- const { response, text, images } = await cline . ask ( "tool" , completeMessage , hasProtectedFiles )
344+ const { response, text, images } = await cline . ask ( "tool" , completeMessage , false )
310345
311346 // Process batch response
312347 if ( response === "yesButtonClicked" ) {
@@ -418,6 +453,7 @@ Original error: ${errorMessage}`
418453
419454 try {
420455 let originalContent : string | null = await fs . readFile ( absolutePath , "utf-8" )
456+ let beforeContent : string | null = originalContent
421457 let successCount = 0
422458 let formattedError = ""
423459
@@ -540,9 +576,11 @@ ${errorDetails ? `\nTechnical details:\n${errorDetails}\n` : ""}
540576 if ( operationsToApprove . length === 1 ) {
541577 // Prepare common data for single file operation
542578 const diffContents = diffItems . map ( ( item ) => item . content ) . join ( "\n\n" )
579+ const unifiedPatch = formatResponse . createPrettyPatch ( relPath , beforeContent ! , originalContent ! )
543580 const operationMessage = JSON . stringify ( {
544581 ...sharedMessageProps ,
545582 diff : diffContents ,
583+ content : unifiedPatch ,
546584 } satisfies ClineSayTool )
547585
548586 let toolProgressStatus
0 commit comments