Customize for Roo

This commit is contained in:
Matt Rubens
2025-01-15 22:28:43 -05:00
parent 4b4905ec9e
commit b65c8d0ec6
9 changed files with 842 additions and 133 deletions

View File

@@ -1,11 +1,12 @@
import { VSCodeCheckbox, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
import { useCallback, useState } from "react"
import styled from "styled-components"
import { useExtensionState } from "../../context/ExtensionStateContext"
interface AutoApproveAction {
id: string
label: string
enabled: boolean
shortName: string
description: string
}
@@ -13,58 +14,97 @@ interface AutoApproveMenuProps {
style?: React.CSSProperties
}
const DEFAULT_MAX_REQUESTS = 50
const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
const [isExpanded, setIsExpanded] = useState(false)
const [actions, setActions] = useState<AutoApproveAction[]>([
const {
alwaysAllowReadOnly,
setAlwaysAllowReadOnly,
alwaysAllowWrite,
setAlwaysAllowWrite,
alwaysAllowExecute,
setAlwaysAllowExecute,
alwaysAllowBrowser,
setAlwaysAllowBrowser,
alwaysAllowMcp,
setAlwaysAllowMcp,
alwaysApproveResubmit,
setAlwaysApproveResubmit,
autoApprovalEnabled,
setAutoApprovalEnabled,
} = useExtensionState()
const actions: AutoApproveAction[] = [
{
id: "readFiles",
label: "Read files and directories",
enabled: false,
shortName: "Read",
enabled: alwaysAllowReadOnly ?? false,
description: "Allows access to read any file on your computer.",
},
{
id: "editFiles",
label: "Edit files",
enabled: false,
shortName: "Edit",
enabled: alwaysAllowWrite ?? false,
description: "Allows modification of any files on your computer.",
},
{
id: "executeCommands",
label: "Execute safe commands",
enabled: false,
shortName: "Commands",
enabled: alwaysAllowExecute ?? false,
description:
"Allows automatic execution of safe terminal commands. The model will determine if a command is potentially destructive and ask for explicit approval.",
"Allows execution of approved terminal commands. You can configure this in the settings panel.",
},
{
id: "useBrowser",
label: "Use the browser",
enabled: false,
shortName: "Browser",
enabled: alwaysAllowBrowser ?? false,
description: "Allows ability to launch and interact with any website in a headless browser.",
},
{
id: "useMcp",
label: "Use MCP servers",
enabled: false,
shortName: "MCP",
enabled: alwaysAllowMcp ?? false,
description: "Allows use of configured MCP servers which may modify filesystem or interact with APIs.",
},
])
const [maxRequests, setMaxRequests] = useState(DEFAULT_MAX_REQUESTS)
const [enableNotifications, setEnableNotifications] = useState(false)
{
id: "retryRequests",
label: "Retry failed requests",
shortName: "Retries",
enabled: alwaysApproveResubmit ?? false,
description: "Automatically retry failed API requests when the provider returns an error response.",
},
]
const toggleExpanded = useCallback(() => {
setIsExpanded((prev) => !prev)
}, [])
const toggleAction = useCallback((actionId: string) => {
setActions((prev) =>
prev.map((action) => (action.id === actionId ? { ...action, enabled: !action.enabled } : action)),
)
}, [])
const enabledActionsList = actions
.filter((action) => action.enabled)
.map((action) => action.shortName)
.join(", ")
const enabledActions = actions.filter((action) => action.enabled)
const enabledActionsList = enabledActions.map((action) => action.label).join(", ")
// Individual checkbox handlers - each one only updates its own state
const handleReadOnlyChange = useCallback(() => setAlwaysAllowReadOnly(!(alwaysAllowReadOnly ?? false)), [alwaysAllowReadOnly, setAlwaysAllowReadOnly])
const handleWriteChange = useCallback(() => setAlwaysAllowWrite(!(alwaysAllowWrite ?? false)), [alwaysAllowWrite, setAlwaysAllowWrite])
const handleExecuteChange = useCallback(() => setAlwaysAllowExecute(!(alwaysAllowExecute ?? false)), [alwaysAllowExecute, setAlwaysAllowExecute])
const handleBrowserChange = useCallback(() => setAlwaysAllowBrowser(!(alwaysAllowBrowser ?? false)), [alwaysAllowBrowser, setAlwaysAllowBrowser])
const handleMcpChange = useCallback(() => setAlwaysAllowMcp(!(alwaysAllowMcp ?? false)), [alwaysAllowMcp, setAlwaysAllowMcp])
const handleRetryChange = useCallback(() => setAlwaysApproveResubmit(!(alwaysApproveResubmit ?? false)), [alwaysApproveResubmit, setAlwaysApproveResubmit])
// Map action IDs to their specific handlers
const actionHandlers: Record<AutoApproveAction['id'], () => void> = {
readFiles: handleReadOnlyChange,
editFiles: handleWriteChange,
executeCommands: handleExecuteChange,
useBrowser: handleBrowserChange,
useMcp: handleMcpChange,
retryRequests: handleRetryChange,
}
return (
<div
@@ -86,39 +126,41 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
cursor: "pointer",
}}
onClick={toggleExpanded}>
<VSCodeCheckbox
checked={enabledActions.length > 0}
onChange={(e) => {
const checked = (e.target as HTMLInputElement).checked
setActions((prev) =>
prev.map((action) => ({
...action,
enabled: checked,
})),
)
e.stopPropagation()
}}
onClick={(e) => e.stopPropagation()}
/>
<CollapsibleSection>
<span style={{ color: "var(--vscode-foreground)" }}>Auto-approve:</span>
<span
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}>
{enabledActions.length === 0 ? "None" : enabledActionsList}
<div onClick={(e) => e.stopPropagation()}>
<VSCodeCheckbox
checked={autoApprovalEnabled ?? false}
onChange={() => setAutoApprovalEnabled(!(autoApprovalEnabled ?? false))}
/>
</div>
<div style={{
display: 'flex',
alignItems: 'center',
gap: '4px',
flex: 1,
minWidth: 0
}}>
<span style={{
color: "var(--vscode-foreground)",
flexShrink: 0
}}>Auto-approve:</span>
<span style={{
color: "var(--vscode-descriptionForeground)",
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
flex: 1,
minWidth: 0
}}>
{enabledActionsList || "None"}
</span>
<span
className={`codicon codicon-chevron-${isExpanded ? "down" : "right"}`}
style={{
// fontSize: "14px",
flexShrink: 0,
marginLeft: isExpanded ? "2px" : "-2px",
}}
/>
</CollapsibleSection>
</div>
</div>
{isExpanded && (
<div style={{ padding: "0" }}>
@@ -129,13 +171,17 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
fontSize: "12px",
}}>
Auto-approve allows Cline to perform actions without asking for permission. Only enable for
actions you fully trust, and consider setting a low request limit as a safeguard.
actions you fully trust.
</div>
{actions.map((action) => (
<div key={action.id} style={{ margin: "6px 0" }}>
<VSCodeCheckbox checked={action.enabled} onChange={() => toggleAction(action.id)}>
{action.label}
</VSCodeCheckbox>
<div onClick={(e) => e.stopPropagation()}>
<VSCodeCheckbox
checked={action.enabled}
onChange={actionHandlers[action.id]}>
{action.label}
</VSCodeCheckbox>
</div>
<div
style={{
marginLeft: "28px",
@@ -146,76 +192,10 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
</div>
</div>
))}
<div
style={{
height: "0.5px",
background: "var(--vscode-titleBar-inactiveForeground)",
margin: "15px 0",
opacity: 0.2,
}}
/>
<div
style={{
display: "flex",
alignItems: "center",
gap: "8px",
marginTop: "10px",
marginBottom: "8px",
color: "var(--vscode-foreground)",
}}>
<span style={{ flexShrink: 1, minWidth: 0 }}>Max Requests:</span>
<VSCodeTextField
value={maxRequests.toString()}
onChange={(e) => {
const value = parseInt((e.target as HTMLInputElement).value)
if (!isNaN(value) && value > 0) {
setMaxRequests(value)
}
}}
style={{ flex: 1 }}
/>
</div>
<div
style={{
color: "var(--vscode-descriptionForeground)",
fontSize: "12px",
marginBottom: "10px",
}}>
Cline will make this many API requests before asking for approval to proceed with the task.
</div>
<div style={{ margin: "6px 0" }}>
<VSCodeCheckbox
checked={enableNotifications}
onChange={() => setEnableNotifications((prev) => !prev)}>
Enable Notifications
</VSCodeCheckbox>
<div
style={{
marginLeft: "28px",
color: "var(--vscode-descriptionForeground)",
fontSize: "12px",
}}>
Receive system notifications when Cline requires approval to proceed or when a task is
completed.
</div>
</div>
</div>
)}
</div>
)
}
const CollapsibleSection = styled.div`
display: flex;
align-items: center;
gap: 4px;
color: var(--vscode-descriptionForeground);
flex: 1;
min-width: 0;
&:hover {
color: var(--vscode-foreground);
}
`
export default AutoApproveMenu