@@ -8,7 +8,7 @@ import { formatResponse } from "../prompts/responses"
88import { ToolUse , AskApproval , HandleError , PushToolResult , RemoveClosingTag } from "../../shared/tools"
99import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
1010import { fileExistsAtPath } from "../../utils/fs"
11- import { stripLineNumbers , everyLineHasLineNumbers } from "../../integrations/misc/extract-text"
11+ import { addLineNumbers , stripLineNumbers , everyLineHasLineNumbers } from "../../integrations/misc/extract-text"
1212import { getReadablePath } from "../../utils/path"
1313import { isPathOutsideWorkspace } from "../../utils/pathUtils"
1414import { detectCodeOmission } from "../../integrations/editor/detect-omission"
@@ -26,28 +26,12 @@ export async function writeToFileTool(
2626 let newContent : string | undefined = block . params . content
2727 let predictedLineCount : number | undefined = parseInt ( block . params . line_count ?? "0" )
2828
29- if ( block . partial && ( ! relPath || newContent === undefined ) ) {
29+ if ( ! relPath || newContent === undefined ) {
3030 // checking for newContent ensure relPath is complete
3131 // wait so we can determine if it's a new file or editing an existing file
3232 return
3333 }
3434
35- if ( ! relPath ) {
36- cline . consecutiveMistakeCount ++
37- cline . recordToolError ( "write_to_file" )
38- pushToolResult ( await cline . sayAndCreateMissingParamError ( "write_to_file" , "path" ) )
39- await cline . diffViewProvider . reset ( )
40- return
41- }
42-
43- if ( newContent === undefined ) {
44- cline . consecutiveMistakeCount ++
45- cline . recordToolError ( "write_to_file" )
46- pushToolResult ( await cline . sayAndCreateMissingParamError ( "write_to_file" , "content" ) )
47- await cline . diffViewProvider . reset ( )
48- return
49- }
50-
5135 const accessAllowed = cline . rooIgnoreController ?. validateAccess ( relPath )
5236
5337 if ( ! accessAllowed ) {
@@ -73,11 +57,11 @@ export async function writeToFileTool(
7357 // pre-processing newContent for cases where weaker models might add artifacts like markdown codeblock markers (deepseek/llama) or extra escape characters (gemini)
7458 if ( newContent . startsWith ( "```" ) ) {
7559 // cline handles cases where it includes language specifiers like ```python ```js
76- newContent = newContent . split ( "\n" ) . slice ( 1 ) . join ( "\n" ) . trim ( )
60+ newContent = newContent . split ( "\n" ) . slice ( 1 ) . join ( "\n" )
7761 }
7862
7963 if ( newContent . endsWith ( "```" ) ) {
80- newContent = newContent . split ( "\n" ) . slice ( 0 , - 1 ) . join ( "\n" ) . trim ( )
64+ newContent = newContent . split ( "\n" ) . slice ( 0 , - 1 ) . join ( "\n" )
8165 }
8266
8367 if ( ! cline . api . getModel ( ) . id . includes ( "claude" ) ) {
@@ -116,7 +100,23 @@ export async function writeToFileTool(
116100
117101 return
118102 } else {
119- if ( predictedLineCount === undefined ) {
103+ if ( ! relPath ) {
104+ cline . consecutiveMistakeCount ++
105+ cline . recordToolError ( "write_to_file" )
106+ pushToolResult ( await cline . sayAndCreateMissingParamError ( "write_to_file" , "path" ) )
107+ await cline . diffViewProvider . reset ( )
108+ return
109+ }
110+
111+ if ( newContent === undefined ) {
112+ cline . consecutiveMistakeCount ++
113+ cline . recordToolError ( "write_to_file" )
114+ pushToolResult ( await cline . sayAndCreateMissingParamError ( "write_to_file" , "content" ) )
115+ await cline . diffViewProvider . reset ( )
116+ return
117+ }
118+
119+ if ( ! predictedLineCount ) {
120120 cline . consecutiveMistakeCount ++
121121 cline . recordToolError ( "write_to_file" )
122122
@@ -212,8 +212,7 @@ export async function writeToFileTool(
212212 return
213213 }
214214
215- // Call saveChanges to update the DiffViewProvider properties
216- await cline . diffViewProvider . saveChanges ( )
215+ const { newProblemsMessage, userEdits, finalContent } = await cline . diffViewProvider . saveChanges ( )
217216
218217 // Track file edit operation
219218 if ( relPath ) {
@@ -222,10 +221,31 @@ export async function writeToFileTool(
222221
223222 cline . didEditFile = true // used to determine if we should wait for busy terminal to update before sending api request
224223
225- // Get the formatted response message
226- const message = await cline . diffViewProvider . pushToolWriteResult ( cline , cline . cwd , ! fileExists )
224+ if ( userEdits ) {
225+ await cline . say (
226+ "user_feedback_diff" ,
227+ JSON . stringify ( {
228+ tool : fileExists ? "editedExistingFile" : "newFileCreated" ,
229+ path : getReadablePath ( cline . cwd , relPath ) ,
230+ diff : userEdits ,
231+ } satisfies ClineSayTool ) ,
232+ )
227233
228- pushToolResult ( message )
234+ pushToolResult (
235+ `The user made the following updates to your content:\n\n${ userEdits } \n\n` +
236+ `The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${ relPath . toPosix ( ) } . Here is the full, updated content of the file, including line numbers:\n\n` +
237+ `<final_file_content path="${ relPath . toPosix ( ) } ">\n${ addLineNumbers (
238+ finalContent || "" ,
239+ ) } \n</final_file_content>\n\n` +
240+ `Please note:\n` +
241+ `1. You do not need to re-write the file with these changes, as they have already been applied.\n` +
242+ `2. Proceed with the task using this updated file content as the new baseline.\n` +
243+ `3. If the user's edits have addressed part of the task or changed the requirements, adjust your approach accordingly.` +
244+ `${ newProblemsMessage } ` ,
245+ )
246+ } else {
247+ pushToolResult ( `The content was successfully saved to ${ relPath . toPosix ( ) } .${ newProblemsMessage } ` )
248+ }
229249
230250 await cline . diffViewProvider . reset ( )
231251
0 commit comments