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

@@ -46,6 +46,11 @@ jest.mock('../ChatRow', () => ({
}
}))
jest.mock('../AutoApproveMenu', () => ({
__esModule: true,
default: () => null,
}))
interface ChatTextAreaProps {
onSend: (value: string) => void;
inputValue?: string;
@@ -139,6 +144,187 @@ describe('ChatView - Auto Approval Tests', () => {
jest.clearAllMocks()
})
it('defaults autoApprovalEnabled to true if any individual auto-approval flags are true', async () => {
render(
<ExtensionStateContextProvider>
<ChatView
isHidden={false}
showAnnouncement={false}
hideAnnouncement={() => {}}
showHistoryView={() => {}}
/>
</ExtensionStateContextProvider>
)
// Test cases with different individual flags
const testCases = [
{ alwaysAllowBrowser: true },
{ alwaysAllowReadOnly: true },
{ alwaysAllowWrite: true },
{ alwaysAllowExecute: true },
{ alwaysAllowMcp: true }
]
for (const flags of testCases) {
// Reset state
mockPostMessage({
...flags,
clineMessages: []
})
// Send an action that should be auto-approved
mockPostMessage({
...flags,
clineMessages: [
{
type: 'say',
say: 'task',
ts: Date.now() - 2000,
text: 'Initial task'
},
{
type: 'ask',
ask: flags.alwaysAllowBrowser ? 'browser_action_launch' :
flags.alwaysAllowReadOnly ? 'tool' :
flags.alwaysAllowWrite ? 'tool' :
flags.alwaysAllowExecute ? 'command' :
'use_mcp_server',
ts: Date.now(),
text: flags.alwaysAllowBrowser ? JSON.stringify({ action: 'launch', url: 'http://example.com' }) :
flags.alwaysAllowReadOnly ? JSON.stringify({ tool: 'readFile', path: 'test.txt' }) :
flags.alwaysAllowWrite ? JSON.stringify({ tool: 'editedExistingFile', path: 'test.txt' }) :
flags.alwaysAllowExecute ? 'npm test' :
JSON.stringify({ type: 'use_mcp_tool', serverName: 'test', toolName: 'test' }),
partial: false
}
]
})
// Wait for auto-approval
await waitFor(() => {
expect(vscode.postMessage).toHaveBeenCalledWith({
type: 'askResponse',
askResponse: 'yesButtonClicked'
})
})
}
// Verify no auto-approval when no flags are true
jest.clearAllMocks()
mockPostMessage({
alwaysAllowBrowser: false,
alwaysAllowReadOnly: false,
alwaysAllowWrite: false,
alwaysAllowExecute: false,
alwaysAllowMcp: false,
clineMessages: [
{
type: 'say',
say: 'task',
ts: Date.now() - 2000,
text: 'Initial task'
},
{
type: 'ask',
ask: 'browser_action_launch',
ts: Date.now(),
text: JSON.stringify({ action: 'launch', url: 'http://example.com' }),
partial: false
}
]
})
// Wait a bit to ensure no auto-approval happens
await new Promise(resolve => setTimeout(resolve, 100))
expect(vscode.postMessage).not.toHaveBeenCalledWith({
type: 'askResponse',
askResponse: 'yesButtonClicked'
})
})
it('does not auto-approve any actions when autoApprovalEnabled is false', () => {
render(
<ExtensionStateContextProvider>
<ChatView
isHidden={false}
showAnnouncement={false}
hideAnnouncement={() => {}}
showHistoryView={() => {}}
/>
</ExtensionStateContextProvider>
)
// First hydrate state with initial task
mockPostMessage({
autoApprovalEnabled: false,
alwaysAllowBrowser: true,
alwaysAllowReadOnly: true,
alwaysAllowWrite: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test'],
clineMessages: [
{
type: 'say',
say: 'task',
ts: Date.now() - 2000,
text: 'Initial task'
}
]
})
// Test various types of actions that should not be auto-approved
const testCases = [
{
ask: 'browser_action_launch',
text: JSON.stringify({ action: 'launch', url: 'http://example.com' })
},
{
ask: 'tool',
text: JSON.stringify({ tool: 'readFile', path: 'test.txt' })
},
{
ask: 'tool',
text: JSON.stringify({ tool: 'editedExistingFile', path: 'test.txt' })
},
{
ask: 'command',
text: 'npm test'
}
]
testCases.forEach(testCase => {
mockPostMessage({
autoApprovalEnabled: false,
alwaysAllowBrowser: true,
alwaysAllowReadOnly: true,
alwaysAllowWrite: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test'],
clineMessages: [
{
type: 'say',
say: 'task',
ts: Date.now() - 2000,
text: 'Initial task'
},
{
type: 'ask',
ask: testCase.ask,
ts: Date.now(),
text: testCase.text,
partial: false
}
]
})
// Verify no auto-approval message was sent
expect(vscode.postMessage).not.toHaveBeenCalledWith({
type: 'askResponse',
askResponse: 'yesButtonClicked'
})
})
})
it('auto-approves browser actions when alwaysAllowBrowser is enabled', async () => {
render(
<ExtensionStateContextProvider>
@@ -153,6 +339,7 @@ describe('ChatView - Auto Approval Tests', () => {
// First hydrate state with initial task
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowBrowser: true,
clineMessages: [
{
@@ -166,6 +353,7 @@ describe('ChatView - Auto Approval Tests', () => {
// Then send the browser action ask message
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowBrowser: true,
clineMessages: [
{
@@ -207,6 +395,7 @@ describe('ChatView - Auto Approval Tests', () => {
// First hydrate state with initial task
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowReadOnly: true,
clineMessages: [
{
@@ -220,6 +409,7 @@ describe('ChatView - Auto Approval Tests', () => {
// Then send the read-only tool ask message
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowReadOnly: true,
clineMessages: [
{
@@ -262,6 +452,7 @@ describe('ChatView - Auto Approval Tests', () => {
// First hydrate state with initial task
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowWrite: true,
writeDelayMs: 0,
clineMessages: [
@@ -276,6 +467,7 @@ describe('ChatView - Auto Approval Tests', () => {
// Then send the write tool ask message
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowWrite: true,
writeDelayMs: 0,
clineMessages: [
@@ -318,6 +510,7 @@ describe('ChatView - Auto Approval Tests', () => {
// First hydrate state with initial task
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowWrite: true,
clineMessages: [
{
@@ -331,6 +524,7 @@ describe('ChatView - Auto Approval Tests', () => {
// Then send a non-tool write operation message
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowWrite: true,
clineMessages: [
{
@@ -371,6 +565,7 @@ describe('ChatView - Auto Approval Tests', () => {
// First hydrate state with initial task
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test'],
clineMessages: [
@@ -385,6 +580,7 @@ describe('ChatView - Auto Approval Tests', () => {
// Then send the command ask message
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test'],
clineMessages: [
@@ -427,6 +623,7 @@ describe('ChatView - Auto Approval Tests', () => {
// First hydrate state with initial task
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test'],
clineMessages: [
@@ -441,6 +638,7 @@ describe('ChatView - Auto Approval Tests', () => {
// Then send the disallowed command ask message
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test'],
clineMessages: [
@@ -498,6 +696,7 @@ describe('ChatView - Auto Approval Tests', () => {
// First hydrate state with initial task
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test', 'npm run build', 'echo', 'Select-String'],
clineMessages: [
@@ -512,6 +711,7 @@ describe('ChatView - Auto Approval Tests', () => {
// Then send the chained command ask message
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test', 'npm run build', 'echo', 'Select-String'],
clineMessages: [
@@ -585,6 +785,7 @@ describe('ChatView - Auto Approval Tests', () => {
// Then send the chained command ask message
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test', 'Select-String'],
clineMessages: [
@@ -643,6 +844,7 @@ describe('ChatView - Auto Approval Tests', () => {
jest.clearAllMocks()
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test', 'Select-String'],
clineMessages: [
@@ -656,6 +858,7 @@ describe('ChatView - Auto Approval Tests', () => {
})
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test', 'Select-String'],
clineMessages: [
@@ -688,6 +891,7 @@ describe('ChatView - Auto Approval Tests', () => {
jest.clearAllMocks()
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test', 'Select-String'],
clineMessages: [
@@ -701,6 +905,7 @@ describe('ChatView - Auto Approval Tests', () => {
})
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowExecute: true,
allowedCommands: ['npm test', 'Select-String'],
clineMessages: [
@@ -748,6 +953,7 @@ describe('ChatView - Sound Playing Tests', () => {
// First hydrate state with initial task and streaming
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowBrowser: true,
clineMessages: [
{
@@ -768,6 +974,7 @@ describe('ChatView - Sound Playing Tests', () => {
// Then send the browser action ask message (streaming finished)
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowBrowser: true,
clineMessages: [
{
@@ -807,6 +1014,7 @@ describe('ChatView - Sound Playing Tests', () => {
// First hydrate state with initial task and streaming
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowBrowser: false,
clineMessages: [
{
@@ -827,6 +1035,7 @@ describe('ChatView - Sound Playing Tests', () => {
// Then send the browser action ask message (streaming finished)
mockPostMessage({
autoApprovalEnabled: true,
alwaysAllowBrowser: false,
clineMessages: [
{