Simplify auto-approving code and make it work better with browser actions (#21)

This commit is contained in:
Matt Rubens
2024-11-28 13:44:02 -05:00
committed by GitHub
parent b1c0e9be41
commit d632e621be
6 changed files with 224 additions and 347 deletions

View File

@@ -34,8 +34,18 @@ interface ChatViewProps {
export const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images
const ALLOWED_AUTO_EXECUTE_COMMANDS = [
'npm',
'npx',
'tsc',
'git log',
'git diff',
'git show',
'ls'
] as const
const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryView }: ChatViewProps) => {
const { version, clineMessages: messages, taskHistory, apiConfiguration } = useExtensionState()
const { version, clineMessages: messages, taskHistory, apiConfiguration, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute } = useExtensionState()
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined
const task = useMemo(() => messages.at(0), [messages]) // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see Cline.abort)
@@ -675,6 +685,60 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
[expandedRows, modifiedMessages, groupedMessages.length, toggleRowExpansion, handleRowHeightChange],
)
useEffect(() => {
// Only proceed if we have an ask and buttons are enabled
if (!clineAsk || !enableButtons) return
const isReadOnlyToolAction = () => {
const lastMessage = messages.at(-1)
if (lastMessage?.type === "ask" && lastMessage.text) {
const tool = JSON.parse(lastMessage.text)
return ["readFile", "listFiles", "searchFiles"].includes(tool.tool)
}
return false
}
const isWriteToolAction = () => {
const lastMessage = messages.at(-1)
if (lastMessage?.type === "ask" && lastMessage.text) {
const tool = JSON.parse(lastMessage.text)
return ["editedExistingFile", "newFileCreated"].includes(tool.tool)
}
return false
}
const isAllowedCommand = () => {
const lastMessage = messages.at(-1)
if (lastMessage?.type === "ask" && lastMessage.text) {
const command = lastMessage.text
// Check for command chaining characters
if (command.includes('&&') ||
command.includes(';') ||
command.includes('||') ||
command.includes('|') ||
command.includes('$(') ||
command.includes('`')) {
return false
}
const trimmedCommand = command.trim().toLowerCase()
return ALLOWED_AUTO_EXECUTE_COMMANDS.some(prefix =>
trimmedCommand.startsWith(prefix.toLowerCase())
)
}
return false
}
if (
(alwaysAllowBrowser && clineAsk === "browser_action_launch") ||
(alwaysAllowReadOnly && clineAsk === "tool" && isReadOnlyToolAction()) ||
(alwaysAllowWrite && clineAsk === "tool" && isWriteToolAction()) ||
(alwaysAllowExecute && clineAsk === "command" && isAllowedCommand())
) {
handlePrimaryButtonClick()
}
}, [clineAsk, enableButtons, handlePrimaryButtonClick, alwaysAllowBrowser, alwaysAllowReadOnly, alwaysAllowWrite, alwaysAllowExecute, messages])
return (
<div
style={{