Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/core/tools/ApplyDiffTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,9 @@ export class ApplyDiffTool extends BaseTool<"apply_diff"> {
const state = await provider?.getState()
const diagnosticsEnabled = state?.diagnosticsEnabled ?? true
const writeDelayMs = state?.writeDelayMs ?? DEFAULT_WRITE_DELAY_MS
const isPreventFocusDisruptionEnabled = experiments.isEnabled(
state?.experiments ?? {},
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
)
const isPreventFocusDisruptionEnabled =
experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION) ||
(state?.autoApprovalEnabled === true && state?.alwaysAllowWrite === true)

// Check if file is write-protected
const isWriteProtected = task.rooProtectedController?.isWriteProtected(relPath) || false
Expand Down
14 changes: 6 additions & 8 deletions src/core/tools/ApplyPatchTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,9 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
const state = await provider?.getState()
const diagnosticsEnabled = state?.diagnosticsEnabled ?? true
const writeDelayMs = state?.writeDelayMs ?? DEFAULT_WRITE_DELAY_MS
const isPreventFocusDisruptionEnabled = experiments.isEnabled(
state?.experiments ?? {},
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
)
const isPreventFocusDisruptionEnabled =
experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION) ||
(state?.autoApprovalEnabled === true && state?.alwaysAllowWrite === true)

const sanitizedDiff = sanitizeUnifiedDiff(diff || "")
const diffStats = computeDiffStats(sanitizedDiff) || undefined
Expand Down Expand Up @@ -329,10 +328,9 @@ export class ApplyPatchTool extends BaseTool<"apply_patch"> {
const state = await provider?.getState()
const diagnosticsEnabled = state?.diagnosticsEnabled ?? true
const writeDelayMs = state?.writeDelayMs ?? DEFAULT_WRITE_DELAY_MS
const isPreventFocusDisruptionEnabled = experiments.isEnabled(
state?.experiments ?? {},
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
)
const isPreventFocusDisruptionEnabled =
experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION) ||
(state?.autoApprovalEnabled === true && state?.alwaysAllowWrite === true)

const sanitizedDiff = sanitizeUnifiedDiff(diff)
const diffStats = computeDiffStats(sanitizedDiff) || undefined
Expand Down
7 changes: 3 additions & 4 deletions src/core/tools/EditFileTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,10 +392,9 @@ export class EditFileTool extends BaseTool<"edit_file"> {
const state = await provider?.getState()
const diagnosticsEnabled = state?.diagnosticsEnabled ?? true
const writeDelayMs = state?.writeDelayMs ?? DEFAULT_WRITE_DELAY_MS
const isPreventFocusDisruptionEnabled = experiments.isEnabled(
state?.experiments ?? {},
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
)
const isPreventFocusDisruptionEnabled =
experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION) ||
(state?.autoApprovalEnabled === true && state?.alwaysAllowWrite === true)

const sanitizedDiff = sanitizeUnifiedDiff(diff || "")
const diffStats = computeDiffStats(sanitizedDiff) || undefined
Expand Down
7 changes: 3 additions & 4 deletions src/core/tools/EditTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,9 @@ export class EditTool extends BaseTool<"edit"> {
const state = await provider?.getState()
const diagnosticsEnabled = state?.diagnosticsEnabled ?? true
const writeDelayMs = state?.writeDelayMs ?? DEFAULT_WRITE_DELAY_MS
const isPreventFocusDisruptionEnabled = experiments.isEnabled(
state?.experiments ?? {},
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
)
const isPreventFocusDisruptionEnabled =
experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION) ||
(state?.autoApprovalEnabled === true && state?.alwaysAllowWrite === true)

const sanitizedDiff = sanitizeUnifiedDiff(diff)
const diffStats = computeDiffStats(sanitizedDiff) || undefined
Expand Down
7 changes: 3 additions & 4 deletions src/core/tools/SearchReplaceTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,9 @@ export class SearchReplaceTool extends BaseTool<"search_replace"> {
const state = await provider?.getState()
const diagnosticsEnabled = state?.diagnosticsEnabled ?? true
const writeDelayMs = state?.writeDelayMs ?? DEFAULT_WRITE_DELAY_MS
const isPreventFocusDisruptionEnabled = experiments.isEnabled(
state?.experiments ?? {},
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
)
const isPreventFocusDisruptionEnabled =
experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION) ||
(state?.autoApprovalEnabled === true && state?.alwaysAllowWrite === true)

const sanitizedDiff = sanitizeUnifiedDiff(diff)
const diffStats = computeDiffStats(sanitizedDiff) || undefined
Expand Down
14 changes: 6 additions & 8 deletions src/core/tools/WriteToFileTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,9 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {
const state = await provider?.getState()
const diagnosticsEnabled = state?.diagnosticsEnabled ?? true
const writeDelayMs = state?.writeDelayMs ?? DEFAULT_WRITE_DELAY_MS
const isPreventFocusDisruptionEnabled = experiments.isEnabled(
state?.experiments ?? {},
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
)
const isPreventFocusDisruptionEnabled =
experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION) ||
(state?.autoApprovalEnabled === true && state?.alwaysAllowWrite === true)

if (isPreventFocusDisruptionEnabled) {
task.diffViewProvider.editType = fileExists ? "modify" : "create"
Expand Down Expand Up @@ -204,10 +203,9 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> {

const provider = task.providerRef.deref()
const state = await provider?.getState()
const isPreventFocusDisruptionEnabled = experiments.isEnabled(
state?.experiments ?? {},
EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION,
)
const isPreventFocusDisruptionEnabled =
experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.PREVENT_FOCUS_DISRUPTION) ||
(state?.autoApprovalEnabled === true && state?.alwaysAllowWrite === true)

if (isPreventFocusDisruptionEnabled) {
return
Expand Down
68 changes: 68 additions & 0 deletions src/core/tools/__tests__/writeToFileTool.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ describe("writeToFileTool", () => {
userEdits: null,
finalContent: "final content",
}),
saveDirectly: vi.fn().mockResolvedValue({
newProblemsMessage: "",
userEdits: null,
finalContent: "final content",
}),
scrollToFirstDiff: vi.fn(),
updateDiagnosticSettings: vi.fn(),
pushToolWriteResult: vi.fn().mockImplementation(async function (
Expand Down Expand Up @@ -442,6 +447,69 @@ describe("writeToFileTool", () => {
})
})

describe("auto-approve write skips diff view", () => {
it("uses saveDirectly when autoApprovalEnabled and alwaysAllowWrite are both true", async () => {
mockCline.providerRef = {
deref: vi.fn().mockReturnValue({
getState: vi.fn().mockResolvedValue({
diagnosticsEnabled: true,
writeDelayMs: 1000,
autoApprovalEnabled: true,
alwaysAllowWrite: true,
}),
}),
}

await executeWriteFileTool({}, { fileExists: false })

// Should NOT open diff view
expect(mockCline.diffViewProvider.open).not.toHaveBeenCalled()
// Should use saveDirectly instead of saveChanges
expect(mockCline.diffViewProvider.saveDirectly).toHaveBeenCalled()
expect(mockCline.diffViewProvider.saveChanges).not.toHaveBeenCalled()
})

it("uses diff view when autoApprovalEnabled is true but alwaysAllowWrite is false", async () => {
mockCline.providerRef = {
deref: vi.fn().mockReturnValue({
getState: vi.fn().mockResolvedValue({
diagnosticsEnabled: true,
writeDelayMs: 1000,
autoApprovalEnabled: true,
alwaysAllowWrite: false,
}),
}),
}

await executeWriteFileTool({}, { fileExists: false })

// Should open diff view (normal path)
expect(mockCline.diffViewProvider.open).toHaveBeenCalled()
expect(mockCline.diffViewProvider.saveChanges).toHaveBeenCalled()
expect(mockCline.diffViewProvider.saveDirectly).not.toHaveBeenCalled()
})

it("uses diff view when autoApprovalEnabled is false even if alwaysAllowWrite is true", async () => {
mockCline.providerRef = {
deref: vi.fn().mockReturnValue({
getState: vi.fn().mockResolvedValue({
diagnosticsEnabled: true,
writeDelayMs: 1000,
autoApprovalEnabled: false,
alwaysAllowWrite: true,
}),
}),
}

await executeWriteFileTool({}, { fileExists: false })

// Should open diff view (normal path)
expect(mockCline.diffViewProvider.open).toHaveBeenCalled()
expect(mockCline.diffViewProvider.saveChanges).toHaveBeenCalled()
expect(mockCline.diffViewProvider.saveDirectly).not.toHaveBeenCalled()
})
})

describe("error handling", () => {
it("handles general file operation errors", async () => {
mockCline.diffViewProvider.open.mockRejectedValue(new Error("General error"))
Expand Down
Loading