Skip to content

Commit 8ae4296

Browse files
committed
fix: show diff view before approval when PREVENT_FOCUS_DISRUPTION is disabled
- Fixed insertContentTool to show diff view before asking for approval - Fixed multiApplyDiffTool for single file operations to show diff before approval - Fixed searchAndReplaceTool to show diff view before asking for approval - Ensures users can see changes before approving them when experiment is off This fixes the issue where users had to approve changes blindly without seeing the diff first.
1 parent c5ba163 commit 8ae4296

File tree

3 files changed

+169
-106
lines changed

3 files changed

+169
-106
lines changed

src/core/tools/insertContentTool.ts

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -136,42 +136,51 @@ export async function insertContentTool(
136136
approvalContent = updatedContent
137137
}
138138

139-
const completeMessage = JSON.stringify({
140-
...sharedMessageProps,
141-
diff,
142-
content: approvalContent,
143-
lineNumber: lineNumber,
144-
isProtected: isWriteProtected,
145-
} satisfies ClineSayTool)
146-
147-
const didApprove = await cline
148-
.ask("tool", completeMessage, isWriteProtected)
149-
.then((response) => response.response === "yesButtonClicked")
150-
151-
if (!didApprove) {
152-
if (!isPreventFocusDisruptionEnabled) {
153-
await cline.diffViewProvider.revertChanges()
139+
if (isPreventFocusDisruptionEnabled) {
140+
// Direct file write without diff view
141+
const completeMessage = JSON.stringify({
142+
...sharedMessageProps,
143+
diff,
144+
content: approvalContent,
145+
lineNumber: lineNumber,
146+
isProtected: isWriteProtected,
147+
} satisfies ClineSayTool)
148+
149+
const didApprove = await cline
150+
.ask("tool", completeMessage, isWriteProtected)
151+
.then((response) => response.response === "yesButtonClicked")
152+
153+
if (!didApprove) {
154+
pushToolResult("Changes were rejected by the user.")
155+
return
154156
}
155-
pushToolResult("Changes were rejected by the user.")
156-
return
157-
}
158157

159-
if (isPreventFocusDisruptionEnabled) {
160-
// Direct file write without diff view or opening the file
158+
// Save directly without showing diff view or opening the file
161159
await cline.diffViewProvider.saveDirectly(relPath, updatedContent, false, diagnosticsEnabled, writeDelayMs)
162160
} else {
163161
// Original behavior with diff view
164-
// Show changes in diff view
165-
if (!cline.diffViewProvider.isEditing) {
166-
await cline.ask("tool", JSON.stringify(sharedMessageProps), true).catch(() => {})
167-
// First open with original content
168-
await cline.diffViewProvider.open(relPath)
169-
await cline.diffViewProvider.update(fileContent, false)
170-
cline.diffViewProvider.scrollToFirstDiff()
171-
await delay(200)
172-
}
173-
162+
// Show diff view BEFORE asking for approval
163+
await cline.diffViewProvider.open(relPath)
174164
await cline.diffViewProvider.update(updatedContent, true)
165+
cline.diffViewProvider.scrollToFirstDiff()
166+
167+
const completeMessage = JSON.stringify({
168+
...sharedMessageProps,
169+
diff,
170+
content: approvalContent,
171+
lineNumber: lineNumber,
172+
isProtected: isWriteProtected,
173+
} satisfies ClineSayTool)
174+
175+
const didApprove = await cline
176+
.ask("tool", completeMessage, isWriteProtected)
177+
.then((response) => response.response === "yesButtonClicked")
178+
179+
if (!didApprove) {
180+
await cline.diffViewProvider.revertChanges()
181+
pushToolResult("Changes were rejected by the user.")
182+
return
183+
}
175184

176185
// Call saveChanges to update the DiffViewProvider properties
177186
await cline.diffViewProvider.saveChanges(diagnosticsEnabled, writeDelayMs)

src/core/tools/multiApplyDiffTool.ts

Lines changed: 96 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -525,61 +525,109 @@ ${errorDetails ? `\nTechnical details:\n${errorDetails}\n` : ""}
525525
isProtected: isWriteProtected,
526526
}
527527

528-
// If single file, ask for approval
528+
// If single file, handle based on PREVENT_FOCUS_DISRUPTION setting
529529
let didApprove = true
530530
if (operationsToApprove.length === 1) {
531-
const diffContents = diffItems.map((item) => item.content).join("\n\n")
532-
const operationMessage = JSON.stringify({
533-
...sharedMessageProps,
534-
diff: diffContents,
535-
} satisfies ClineSayTool)
536-
537-
let toolProgressStatus
538-
539-
if (cline.diffStrategy && cline.diffStrategy.getProgressStatus) {
540-
toolProgressStatus = cline.diffStrategy.getProgressStatus(
541-
{
542-
...block,
543-
params: { ...block.params, diff: diffContents },
544-
},
545-
{ success: true },
531+
if (isPreventFocusDisruptionEnabled) {
532+
// Direct approval without showing diff view
533+
const diffContents = diffItems.map((item) => item.content).join("\n\n")
534+
const operationMessage = JSON.stringify({
535+
...sharedMessageProps,
536+
diff: diffContents,
537+
} satisfies ClineSayTool)
538+
539+
let toolProgressStatus
540+
541+
if (cline.diffStrategy && cline.diffStrategy.getProgressStatus) {
542+
toolProgressStatus = cline.diffStrategy.getProgressStatus(
543+
{
544+
...block,
545+
params: { ...block.params, diff: diffContents },
546+
},
547+
{ success: true },
548+
)
549+
}
550+
551+
// Check if file is write-protected
552+
const isWriteProtected = cline.rooProtectedController?.isWriteProtected(relPath) || false
553+
didApprove = await askApproval("tool", operationMessage, toolProgressStatus, isWriteProtected)
554+
555+
if (!didApprove) {
556+
results.push(`Changes to ${relPath} were not approved by user`)
557+
continue
558+
}
559+
560+
// Direct file write without diff view or opening the file
561+
cline.diffViewProvider.editType = "modify"
562+
cline.diffViewProvider.originalContent = await fs.readFile(absolutePath, "utf-8")
563+
await cline.diffViewProvider.saveDirectly(
564+
relPath,
565+
originalContent!,
566+
false,
567+
diagnosticsEnabled,
568+
writeDelayMs,
546569
)
547-
}
570+
} else {
571+
// Show diff view BEFORE asking for approval
572+
cline.diffViewProvider.editType = "modify"
573+
await cline.diffViewProvider.open(relPath)
574+
await cline.diffViewProvider.update(originalContent!, true)
575+
cline.diffViewProvider.scrollToFirstDiff()
576+
577+
const diffContents = diffItems.map((item) => item.content).join("\n\n")
578+
const operationMessage = JSON.stringify({
579+
...sharedMessageProps,
580+
diff: diffContents,
581+
} satisfies ClineSayTool)
582+
583+
let toolProgressStatus
584+
585+
if (cline.diffStrategy && cline.diffStrategy.getProgressStatus) {
586+
toolProgressStatus = cline.diffStrategy.getProgressStatus(
587+
{
588+
...block,
589+
params: { ...block.params, diff: diffContents },
590+
},
591+
{ success: true },
592+
)
593+
}
548594

549-
// Check if file is write-protected
550-
const isWriteProtected = cline.rooProtectedController?.isWriteProtected(relPath) || false
551-
didApprove = await askApproval("tool", operationMessage, toolProgressStatus, isWriteProtected)
552-
}
595+
// Check if file is write-protected
596+
const isWriteProtected = cline.rooProtectedController?.isWriteProtected(relPath) || false
597+
didApprove = await askApproval("tool", operationMessage, toolProgressStatus, isWriteProtected)
553598

554-
if (!didApprove) {
555-
if (!isPreventFocusDisruptionEnabled) {
556-
await cline.diffViewProvider.revertChanges()
557-
}
558-
results.push(`Changes to ${relPath} were not approved by user`)
559-
continue
560-
}
599+
if (!didApprove) {
600+
await cline.diffViewProvider.revertChanges()
601+
results.push(`Changes to ${relPath} were not approved by user`)
602+
continue
603+
}
561604

562-
if (isPreventFocusDisruptionEnabled) {
563-
// Direct file write without diff view or opening the file
564-
cline.diffViewProvider.editType = "modify"
565-
cline.diffViewProvider.originalContent = await fs.readFile(absolutePath, "utf-8")
566-
await cline.diffViewProvider.saveDirectly(
567-
relPath,
568-
originalContent!,
569-
false,
570-
diagnosticsEnabled,
571-
writeDelayMs,
572-
)
605+
// Call saveChanges to update the DiffViewProvider properties
606+
await cline.diffViewProvider.saveChanges(diagnosticsEnabled, writeDelayMs)
607+
}
573608
} else {
574-
// Original behavior with diff view
575-
// Show diff view before asking for approval (only for single file or after batch approval)
576-
cline.diffViewProvider.editType = "modify"
577-
await cline.diffViewProvider.open(relPath)
578-
await cline.diffViewProvider.update(originalContent!, true)
579-
cline.diffViewProvider.scrollToFirstDiff()
580-
581-
// Call saveChanges to update the DiffViewProvider properties
582-
await cline.diffViewProvider.saveChanges(diagnosticsEnabled, writeDelayMs)
609+
// Batch operations - already approved above
610+
if (isPreventFocusDisruptionEnabled) {
611+
// Direct file write without diff view or opening the file
612+
cline.diffViewProvider.editType = "modify"
613+
cline.diffViewProvider.originalContent = await fs.readFile(absolutePath, "utf-8")
614+
await cline.diffViewProvider.saveDirectly(
615+
relPath,
616+
originalContent!,
617+
false,
618+
diagnosticsEnabled,
619+
writeDelayMs,
620+
)
621+
} else {
622+
// Original behavior with diff view
623+
cline.diffViewProvider.editType = "modify"
624+
await cline.diffViewProvider.open(relPath)
625+
await cline.diffViewProvider.update(originalContent!, true)
626+
cline.diffViewProvider.scrollToFirstDiff()
627+
628+
// Call saveChanges to update the DiffViewProvider properties
629+
await cline.diffViewProvider.saveChanges(diagnosticsEnabled, writeDelayMs)
630+
}
583631
}
584632

585633
// Track file edit operation

src/core/tools/searchAndReplaceTool.ts

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -210,40 +210,46 @@ export async function searchAndReplaceTool(
210210
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
211211
)
212212

213-
// Request user approval for changes
214-
const completeMessage = JSON.stringify({
215-
...sharedMessageProps,
216-
diff,
217-
isProtected: isWriteProtected,
218-
} satisfies ClineSayTool)
219-
const didApprove = await cline
220-
.ask("tool", completeMessage, isWriteProtected)
221-
.then((response) => response.response === "yesButtonClicked")
222-
223-
if (!didApprove) {
224-
if (!isPreventFocusDisruptionEnabled) {
225-
await cline.diffViewProvider.revertChanges()
213+
if (isPreventFocusDisruptionEnabled) {
214+
// Direct approval without showing diff view
215+
const completeMessage = JSON.stringify({
216+
...sharedMessageProps,
217+
diff,
218+
isProtected: isWriteProtected,
219+
} satisfies ClineSayTool)
220+
const didApprove = await cline
221+
.ask("tool", completeMessage, isWriteProtected)
222+
.then((response) => response.response === "yesButtonClicked")
223+
224+
if (!didApprove) {
225+
pushToolResult("Changes were rejected by the user.")
226+
await cline.diffViewProvider.reset()
227+
return
226228
}
227-
pushToolResult("Changes were rejected by the user.")
228-
await cline.diffViewProvider.reset()
229-
return
230-
}
231229

232-
if (isPreventFocusDisruptionEnabled) {
233230
// Direct file write without diff view or opening the file
234231
await cline.diffViewProvider.saveDirectly(validRelPath, newContent, false, diagnosticsEnabled, writeDelayMs)
235232
} else {
236-
// Original behavior with diff view
237-
// Show changes in diff view
238-
if (!cline.diffViewProvider.isEditing) {
239-
await cline.ask("tool", JSON.stringify(sharedMessageProps), true).catch(() => {})
240-
await cline.diffViewProvider.open(validRelPath)
241-
await cline.diffViewProvider.update(fileContent, false)
242-
cline.diffViewProvider.scrollToFirstDiff()
243-
await delay(200)
244-
}
245-
233+
// Show diff view BEFORE asking for approval
234+
await cline.diffViewProvider.open(validRelPath)
246235
await cline.diffViewProvider.update(newContent, true)
236+
cline.diffViewProvider.scrollToFirstDiff()
237+
238+
const completeMessage = JSON.stringify({
239+
...sharedMessageProps,
240+
diff,
241+
isProtected: isWriteProtected,
242+
} satisfies ClineSayTool)
243+
const didApprove = await cline
244+
.ask("tool", completeMessage, isWriteProtected)
245+
.then((response) => response.response === "yesButtonClicked")
246+
247+
if (!didApprove) {
248+
await cline.diffViewProvider.revertChanges()
249+
pushToolResult("Changes were rejected by the user.")
250+
await cline.diffViewProvider.reset()
251+
return
252+
}
247253

248254
// Call saveChanges to update the DiffViewProvider properties
249255
await cline.diffViewProvider.saveChanges(diagnosticsEnabled, writeDelayMs)

0 commit comments

Comments
 (0)