|
@@ -200,21 +200,12 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Track the last seen path during streaming to detect when the path has stabilized
|
|
|
|
|
- private lastSeenPartialPath: string | undefined = undefined
|
|
|
|
|
-
|
|
|
|
|
override async handlePartial(task: Task, block: ToolUse<"write_to_file">): Promise<void> {
|
|
override async handlePartial(task: Task, block: ToolUse<"write_to_file">): Promise<void> {
|
|
|
const relPath: string | undefined = block.params.path
|
|
const relPath: string | undefined = block.params.path
|
|
|
let newContent: string | undefined = block.params.content
|
|
let newContent: string | undefined = block.params.content
|
|
|
|
|
|
|
|
- // During streaming, the partial-json library may return truncated string values
|
|
|
|
|
- // when chunk boundaries fall mid-value. To avoid creating files at incorrect paths,
|
|
|
|
|
- // we wait until the path stops changing between consecutive partial blocks before
|
|
|
|
|
- // creating the file. This ensures we have the complete, final path value.
|
|
|
|
|
- const pathHasStabilized = this.lastSeenPartialPath !== undefined && this.lastSeenPartialPath === relPath
|
|
|
|
|
- this.lastSeenPartialPath = relPath
|
|
|
|
|
-
|
|
|
|
|
- if (!pathHasStabilized || !relPath || newContent === undefined) {
|
|
|
|
|
|
|
+ // Wait for path to stabilize before showing UI (prevents truncated paths)
|
|
|
|
|
+ if (!this.hasPathStabilized(relPath) || newContent === undefined) {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -229,8 +220,9 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // relPath is guaranteed non-null after hasPathStabilized
|
|
|
let fileExists: boolean
|
|
let fileExists: boolean
|
|
|
- const absolutePath = path.resolve(task.cwd, relPath)
|
|
|
|
|
|
|
+ const absolutePath = path.resolve(task.cwd, relPath!)
|
|
|
|
|
|
|
|
if (task.diffViewProvider.editType !== undefined) {
|
|
if (task.diffViewProvider.editType !== undefined) {
|
|
|
fileExists = task.diffViewProvider.editType === "modify"
|
|
fileExists = task.diffViewProvider.editType === "modify"
|
|
@@ -245,13 +237,12 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
|
|
|
await createDirectoriesForFile(absolutePath)
|
|
await createDirectoriesForFile(absolutePath)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const isWriteProtected = task.rooProtectedController?.isWriteProtected(relPath) || false
|
|
|
|
|
- const fullPath = absolutePath
|
|
|
|
|
- const isOutsideWorkspace = isPathOutsideWorkspace(fullPath)
|
|
|
|
|
|
|
+ const isWriteProtected = task.rooProtectedController?.isWriteProtected(relPath!) || false
|
|
|
|
|
+ const isOutsideWorkspace = isPathOutsideWorkspace(absolutePath)
|
|
|
|
|
|
|
|
const sharedMessageProps: ClineSayTool = {
|
|
const sharedMessageProps: ClineSayTool = {
|
|
|
tool: fileExists ? "editedExistingFile" : "newFileCreated",
|
|
tool: fileExists ? "editedExistingFile" : "newFileCreated",
|
|
|
- path: getReadablePath(task.cwd, relPath),
|
|
|
|
|
|
|
+ path: getReadablePath(task.cwd, relPath!),
|
|
|
content: newContent || "",
|
|
content: newContent || "",
|
|
|
isOutsideWorkspace,
|
|
isOutsideWorkspace,
|
|
|
isProtected: isWriteProtected,
|
|
isProtected: isWriteProtected,
|
|
@@ -262,7 +253,7 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
|
|
|
|
|
|
|
|
if (newContent) {
|
|
if (newContent) {
|
|
|
if (!task.diffViewProvider.isEditing) {
|
|
if (!task.diffViewProvider.isEditing) {
|
|
|
- await task.diffViewProvider.open(relPath)
|
|
|
|
|
|
|
+ await task.diffViewProvider.open(relPath!)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
await task.diffViewProvider.update(
|
|
await task.diffViewProvider.update(
|
|
@@ -271,13 +262,6 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Reset state when the tool finishes (called from execute or on error)
|
|
|
|
|
- */
|
|
|
|
|
- resetPartialState(): void {
|
|
|
|
|
- this.lastSeenPartialPath = undefined
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export const writeToFileTool = new WriteToFileTool()
|
|
export const writeToFileTool = new WriteToFileTool()
|