Skip to content

Commit b8e2dac

Browse files
committed
Only allow usage of diff tool if enabled in settings
1 parent 269ada4 commit b8e2dac

File tree

14 files changed

+850
-40
lines changed

14 files changed

+850
-40
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
Only allow use of the diff tool if it's enabled in settings

src/core/Cline.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Anthropic } from "@anthropic-ai/sdk"
22
import cloneDeep from "clone-deep"
33
import { DiffStrategy, getDiffStrategy, UnifiedDiffStrategy } from "./diff/DiffStrategy"
4-
import { validateToolUse, isToolAllowedForMode } from "./mode-validator"
4+
import { validateToolUse, isToolAllowedForMode, ToolName } from "./mode-validator"
55
import delay from "delay"
66
import fs from "fs/promises"
77
import os from "os"
@@ -827,7 +827,9 @@ export class Cline {
827827
mode,
828828
customPrompts,
829829
customModes,
830+
this.customInstructions,
830831
preferredLanguage,
832+
this.diffEnabled,
831833
)
832834
})()
833835

@@ -1140,11 +1142,13 @@ export class Cline {
11401142
await this.browserSession.closeBrowser()
11411143
}
11421144

1143-
// Validate tool use based on current mode
1145+
// Validate tool use before execution
11441146
const { mode } = (await this.providerRef.deref()?.getState()) ?? {}
11451147
const { customModes } = (await this.providerRef.deref()?.getState()) ?? {}
11461148
try {
1147-
validateToolUse(block.name, mode ?? defaultModeSlug, customModes)
1149+
validateToolUse(block.name as ToolName, mode ?? defaultModeSlug, customModes ?? [], {
1150+
apply_diff: this.diffEnabled,
1151+
})
11481152
} catch (error) {
11491153
this.consecutiveMistakeCount++
11501154
pushToolResult(formatResponse.toolError(error.message))
@@ -2637,8 +2641,10 @@ export class Cline {
26372641

26382642
// Add warning if not in code mode
26392643
if (
2640-
!isToolAllowedForMode("write_to_file", currentMode, customModes ?? []) &&
2641-
!isToolAllowedForMode("apply_diff", currentMode, customModes ?? [])
2644+
!isToolAllowedForMode("write_to_file", currentMode, customModes ?? [], {
2645+
apply_diff: this.diffEnabled,
2646+
}) &&
2647+
!isToolAllowedForMode("apply_diff", currentMode, customModes ?? [], { apply_diff: this.diffEnabled })
26422648
) {
26432649
const currentModeName = getModeBySlug(currentMode, customModes)?.name ?? currentMode
26442650
const defaultModeName = getModeBySlug(defaultModeSlug, customModes)?.name ?? defaultModeSlug

src/core/__tests__/mode-validator.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,50 @@ describe("mode-validator", () => {
7474
// Should not allow tools from other groups
7575
expect(isToolAllowedForMode("write_to_file", codeMode, customModes)).toBe(false)
7676
})
77+
78+
it("respects tool requirements in custom modes", () => {
79+
const customModes = [
80+
{
81+
slug: "custom-mode",
82+
name: "Custom Mode",
83+
roleDefinition: "Custom role",
84+
groups: ["edit"] as const,
85+
},
86+
]
87+
const requirements = { apply_diff: false }
88+
89+
// Should respect disabled requirement even if tool group is allowed
90+
expect(isToolAllowedForMode("apply_diff", "custom-mode", customModes, requirements)).toBe(false)
91+
92+
// Should allow other edit tools
93+
expect(isToolAllowedForMode("write_to_file", "custom-mode", customModes, requirements)).toBe(true)
94+
})
95+
})
96+
97+
describe("tool requirements", () => {
98+
it("respects tool requirements when provided", () => {
99+
const requirements = { apply_diff: false }
100+
expect(isToolAllowedForMode("apply_diff", codeMode, [], requirements)).toBe(false)
101+
102+
const enabledRequirements = { apply_diff: true }
103+
expect(isToolAllowedForMode("apply_diff", codeMode, [], enabledRequirements)).toBe(true)
104+
})
105+
106+
it("allows tools when their requirements are not specified", () => {
107+
const requirements = { some_other_tool: true }
108+
expect(isToolAllowedForMode("apply_diff", codeMode, [], requirements)).toBe(true)
109+
})
110+
111+
it("handles undefined and empty requirements", () => {
112+
expect(isToolAllowedForMode("apply_diff", codeMode, [], undefined)).toBe(true)
113+
expect(isToolAllowedForMode("apply_diff", codeMode, [], {})).toBe(true)
114+
})
115+
116+
it("prioritizes requirements over mode configuration", () => {
117+
const requirements = { apply_diff: false }
118+
// Even in code mode which allows all tools, disabled requirement should take precedence
119+
expect(isToolAllowedForMode("apply_diff", codeMode, [], requirements)).toBe(false)
120+
})
77121
})
78122
})
79123

@@ -87,5 +131,21 @@ describe("mode-validator", () => {
87131
it("does not throw for allowed tools in architect mode", () => {
88132
expect(() => validateToolUse("read_file", "architect", [])).not.toThrow()
89133
})
134+
135+
it("throws error when tool requirement is not met", () => {
136+
const requirements = { apply_diff: false }
137+
expect(() => validateToolUse("apply_diff", codeMode, [], requirements)).toThrow(
138+
'Tool "apply_diff" is not allowed in code mode.',
139+
)
140+
})
141+
142+
it("does not throw when tool requirement is met", () => {
143+
const requirements = { apply_diff: true }
144+
expect(() => validateToolUse("apply_diff", codeMode, [], requirements)).not.toThrow()
145+
})
146+
147+
it("handles undefined requirements gracefully", () => {
148+
expect(() => validateToolUse("apply_diff", codeMode, [], undefined)).not.toThrow()
149+
})
90150
})
91151
})

src/core/mode-validator.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ import { ToolName } from "../shared/tool-groups"
44
export { isToolAllowedForMode }
55
export type { ToolName }
66

7-
export function validateToolUse(toolName: ToolName, mode: Mode, customModes?: ModeConfig[]): void {
8-
if (!isToolAllowedForMode(toolName, mode, customModes ?? [])) {
7+
export function validateToolUse(
8+
toolName: ToolName,
9+
mode: Mode,
10+
customModes?: ModeConfig[],
11+
toolRequirements?: Record<string, boolean>,
12+
): void {
13+
if (!isToolAllowedForMode(toolName, mode, customModes ?? [], toolRequirements)) {
914
throw new Error(`Tool "${toolName}" is not allowed in ${mode} mode.`)
1015
}
1116
}

0 commit comments

Comments
 (0)