Skip to content

Commit d632e62

Browse files
authored
Simplify auto-approving code and make it work better with browser actions (#21)
1 parent b1c0e9b commit d632e62

File tree

6 files changed

+224
-347
lines changed

6 files changed

+224
-347
lines changed

package.json

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,6 @@
116116
"when": "view == claude-dev.SidebarProvider"
117117
}
118118
]
119-
},
120-
"configuration": {
121-
"properties": {
122-
"cline.alwaysAllowBrowser": {
123-
"type": "boolean",
124-
"default": false,
125-
"description": "Always allow browser actions without requiring confirmation"
126-
}
127-
}
128119
}
129120
},
130121
"scripts": {

src/core/Cline.ts

Lines changed: 29 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,6 @@ type UserContent = Array<
5656
Anthropic.TextBlockParam | Anthropic.ImageBlockParam | Anthropic.ToolUseBlockParam | Anthropic.ToolResultBlockParam
5757
>
5858

59-
const ALLOWED_AUTO_EXECUTE_COMMANDS = [
60-
'npm',
61-
'npx',
62-
'tsc',
63-
'git log',
64-
'git diff',
65-
'git show',
66-
'list'
67-
] as const
68-
6959
export class Cline {
7060
readonly taskId: string
7161
api: ApiHandler
@@ -74,10 +64,6 @@ export class Cline {
7464
private browserSession: BrowserSession
7565
private didEditFile: boolean = false
7666
customInstructions?: string
77-
alwaysAllowReadOnly: boolean
78-
alwaysAllowWrite: boolean
79-
alwaysAllowExecute: boolean
80-
alwaysAllowBrowser: boolean
8167

8268
apiConversationHistory: Anthropic.MessageParam[] = []
8369
clineMessages: ClineMessage[] = []
@@ -107,10 +93,6 @@ export class Cline {
10793
provider: ClineProvider,
10894
apiConfiguration: ApiConfiguration,
10995
customInstructions?: string,
110-
alwaysAllowReadOnly?: boolean,
111-
alwaysAllowWrite?: boolean,
112-
alwaysAllowExecute?: boolean,
113-
alwaysAllowBrowser?: boolean,
11496
task?: string,
11597
images?: string[],
11698
historyItem?: HistoryItem,
@@ -122,10 +104,6 @@ export class Cline {
122104
this.browserSession = new BrowserSession(provider.context)
123105
this.diffViewProvider = new DiffViewProvider(cwd)
124106
this.customInstructions = customInstructions
125-
this.alwaysAllowReadOnly = alwaysAllowReadOnly ?? false
126-
this.alwaysAllowWrite = alwaysAllowWrite ?? false
127-
this.alwaysAllowExecute = alwaysAllowExecute ?? false
128-
this.alwaysAllowBrowser = alwaysAllowBrowser ?? false
129107

130108
if (historyItem) {
131109
this.taskId = historyItem.id
@@ -138,25 +116,6 @@ export class Cline {
138116
}
139117
}
140118

141-
private isAllowedCommand(command?: string): boolean {
142-
if (!command) {
143-
return false;
144-
}
145-
// Check for command chaining characters
146-
if (command.includes('&&') ||
147-
command.includes(';') ||
148-
command.includes('||') ||
149-
command.includes('|') ||
150-
command.includes('$(') ||
151-
command.includes('`')) {
152-
return false;
153-
}
154-
const trimmedCommand = command.trim().toLowerCase();
155-
return ALLOWED_AUTO_EXECUTE_COMMANDS.some(prefix =>
156-
trimmedCommand.startsWith(prefix.toLowerCase())
157-
);
158-
}
159-
160119
// Storing task to disk for history
161120

162121
private async ensureTaskDirectoryExists(): Promise<string> {
@@ -1101,11 +1060,7 @@ export class Cline {
11011060
if (block.partial) {
11021061
// update gui message
11031062
const partialMessage = JSON.stringify(sharedMessageProps)
1104-
if (this.alwaysAllowWrite) {
1105-
await this.say("tool", partialMessage, undefined, block.partial)
1106-
} else {
1107-
await this.ask("tool", partialMessage, block.partial).catch(() => {})
1108-
}
1063+
await this.ask("tool", partialMessage, block.partial).catch(() => {})
11091064
// update editor
11101065
if (!this.diffViewProvider.isEditing) {
11111066
// open the editor and prepare to stream content in
@@ -1135,11 +1090,7 @@ export class Cline {
11351090
if (!this.diffViewProvider.isEditing) {
11361091
// show gui message before showing edit animation
11371092
const partialMessage = JSON.stringify(sharedMessageProps)
1138-
if (this.alwaysAllowWrite) {
1139-
await this.say("tool", partialMessage, undefined, true)
1140-
} else {
1141-
await this.ask("tool", partialMessage, true).catch(() => {}) // sending true for partial even though it's not a partial, this shows the edit row before the content is streamed into the editor
1142-
}
1093+
await this.ask("tool", partialMessage, true).catch(() => {}) // sending true for partial even though it's not a partial, this shows the edit row before the content is streamed into the editor
11431094
await this.diffViewProvider.open(relPath)
11441095
}
11451096
await this.diffViewProvider.update(newContent, true)
@@ -1158,7 +1109,7 @@ export class Cline {
11581109
)
11591110
: undefined,
11601111
} satisfies ClineSayTool)
1161-
const didApprove = this.alwaysAllowWrite || (await askApproval("tool", completeMessage))
1112+
const didApprove = await askApproval("tool", completeMessage)
11621113
if (!didApprove) {
11631114
await this.diffViewProvider.revertChanges()
11641115
break
@@ -1211,11 +1162,7 @@ export class Cline {
12111162
...sharedMessageProps,
12121163
content: undefined,
12131164
} satisfies ClineSayTool)
1214-
if (this.alwaysAllowReadOnly) {
1215-
await this.say("tool", partialMessage, undefined, block.partial)
1216-
} else {
1217-
await this.ask("tool", partialMessage, block.partial).catch(() => {})
1218-
}
1165+
await this.ask("tool", partialMessage, block.partial).catch(() => {})
12191166
break
12201167
} else {
12211168
if (!relPath) {
@@ -1229,13 +1176,9 @@ export class Cline {
12291176
...sharedMessageProps,
12301177
content: absolutePath,
12311178
} satisfies ClineSayTool)
1232-
if (this.alwaysAllowReadOnly) {
1233-
await this.say("tool", completeMessage, undefined, false) // need to be sending partialValue bool, since undefined has its own purpose in that the message is treated neither as a partial or completion of a partial, but as a single complete message
1234-
} else {
1235-
const didApprove = await askApproval("tool", completeMessage)
1236-
if (!didApprove) {
1237-
break
1238-
}
1179+
const didApprove = await askApproval("tool", completeMessage)
1180+
if (!didApprove) {
1181+
break
12391182
}
12401183
// now execute the tool like normal
12411184
const content = await extractTextFromFile(absolutePath)
@@ -1261,11 +1204,7 @@ export class Cline {
12611204
...sharedMessageProps,
12621205
content: "",
12631206
} satisfies ClineSayTool)
1264-
if (this.alwaysAllowReadOnly) {
1265-
await this.say("tool", partialMessage, undefined, block.partial)
1266-
} else {
1267-
await this.ask("tool", partialMessage, block.partial).catch(() => {})
1268-
}
1207+
await this.ask("tool", partialMessage, block.partial).catch(() => {})
12691208
break
12701209
} else {
12711210
if (!relDirPath) {
@@ -1281,13 +1220,9 @@ export class Cline {
12811220
...sharedMessageProps,
12821221
content: result,
12831222
} satisfies ClineSayTool)
1284-
if (this.alwaysAllowReadOnly) {
1285-
await this.say("tool", completeMessage, undefined, false)
1286-
} else {
1287-
const didApprove = await askApproval("tool", completeMessage)
1288-
if (!didApprove) {
1289-
break
1290-
}
1223+
const didApprove = await askApproval("tool", completeMessage)
1224+
if (!didApprove) {
1225+
break
12911226
}
12921227
pushToolResult(result)
12931228
break
@@ -1309,11 +1244,7 @@ export class Cline {
13091244
...sharedMessageProps,
13101245
content: "",
13111246
} satisfies ClineSayTool)
1312-
if (this.alwaysAllowReadOnly) {
1313-
await this.say("tool", partialMessage, undefined, block.partial)
1314-
} else {
1315-
await this.ask("tool", partialMessage, block.partial).catch(() => {})
1316-
}
1247+
await this.ask("tool", partialMessage, block.partial).catch(() => {})
13171248
break
13181249
} else {
13191250
if (!relDirPath) {
@@ -1330,13 +1261,9 @@ export class Cline {
13301261
...sharedMessageProps,
13311262
content: result,
13321263
} satisfies ClineSayTool)
1333-
if (this.alwaysAllowReadOnly) {
1334-
await this.say("tool", completeMessage, undefined, false)
1335-
} else {
1336-
const didApprove = await askApproval("tool", completeMessage)
1337-
if (!didApprove) {
1338-
break
1339-
}
1264+
const didApprove = await askApproval("tool", completeMessage)
1265+
if (!didApprove) {
1266+
break
13401267
}
13411268
pushToolResult(result)
13421269
break
@@ -1362,11 +1289,7 @@ export class Cline {
13621289
...sharedMessageProps,
13631290
content: "",
13641291
} satisfies ClineSayTool)
1365-
if (this.alwaysAllowReadOnly) {
1366-
await this.say("tool", partialMessage, undefined, block.partial)
1367-
} else {
1368-
await this.ask("tool", partialMessage, block.partial).catch(() => {})
1369-
}
1292+
await this.ask("tool", partialMessage, block.partial).catch(() => {})
13701293
break
13711294
} else {
13721295
if (!relDirPath) {
@@ -1386,13 +1309,9 @@ export class Cline {
13861309
...sharedMessageProps,
13871310
content: results,
13881311
} satisfies ClineSayTool)
1389-
if (this.alwaysAllowReadOnly) {
1390-
await this.say("tool", completeMessage, undefined, false)
1391-
} else {
1392-
const didApprove = await askApproval("tool", completeMessage)
1393-
if (!didApprove) {
1394-
break
1395-
}
1312+
const didApprove = await askApproval("tool", completeMessage)
1313+
if (!didApprove) {
1314+
break
13961315
}
13971316
pushToolResult(results)
13981317
break
@@ -1421,24 +1340,11 @@ export class Cline {
14211340
try {
14221341
if (block.partial) {
14231342
if (action === "launch") {
1424-
if (this.alwaysAllowBrowser) {
1425-
await this.say(
1426-
"browser_action",
1427-
JSON.stringify({
1428-
action: action as BrowserAction,
1429-
coordinate: undefined,
1430-
text: undefined
1431-
} satisfies ClineSayBrowserAction),
1432-
undefined,
1433-
block.partial
1434-
)
1435-
} else {
1436-
await this.ask(
1437-
"browser_action_launch",
1438-
removeClosingTag("url", url),
1439-
block.partial
1440-
).catch(() => {})
1441-
}
1343+
await this.ask(
1344+
"browser_action_launch",
1345+
removeClosingTag("url", url),
1346+
block.partial
1347+
).catch(() => {})
14421348
} else {
14431349
await this.say(
14441350
"browser_action",
@@ -1464,7 +1370,7 @@ export class Cline {
14641370
break
14651371
}
14661372
this.consecutiveMistakeCount = 0
1467-
const didApprove = this.alwaysAllowBrowser || await askApproval("browser_action_launch", url)
1373+
const didApprove = await askApproval("browser_action_launch", url)
14681374
if (!didApprove) {
14691375
break
14701376
}
@@ -1565,13 +1471,9 @@ export class Cline {
15651471
const command: string | undefined = block.params.command
15661472
try {
15671473
if (block.partial) {
1568-
if (this.alwaysAllowExecute && this.isAllowedCommand(command)) {
1569-
await this.say("command", command, undefined, block.partial)
1570-
} else {
1571-
await this.ask("command", removeClosingTag("command", command), block.partial).catch(
1572-
() => {}
1573-
)
1574-
}
1474+
await this.ask("command", removeClosingTag("command", command), block.partial).catch(
1475+
() => {}
1476+
)
15751477
break
15761478
} else {
15771479
if (!command) {
@@ -1583,8 +1485,7 @@ export class Cline {
15831485
}
15841486
this.consecutiveMistakeCount = 0
15851487

1586-
const didApprove = (this.alwaysAllowExecute && this.isAllowedCommand(command)) ||
1587-
(await askApproval("command", command))
1488+
const didApprove = await askApproval("command", command)
15881489
if (!didApprove) {
15891490
break
15901491
}

0 commit comments

Comments
 (0)