fix(cli): auto-approve shell redirections in AUTO_EDIT mode (#27003)

This commit is contained in:
Coco Sheng
2026-05-13 14:28:30 -04:00
committed by GitHub
parent 63b4bbfb5d
commit 08abe4542d
2 changed files with 55 additions and 3 deletions
@@ -49,6 +49,7 @@ import {
debugLogger,
coreEvents,
CoreEvent,
SHELL_TOOL_NAME,
MCPDiscoveryState,
GeminiCliOperation,
getPlanModeExitMessage,
@@ -2449,6 +2450,44 @@ describe('useGeminiStream', () => {
);
});
it('should auto-approve shell commands with redirection when switching to AUTO_EDIT mode', async () => {
const shellCall = createMockToolCall(
SHELL_TOOL_NAME,
'call-shell',
'info',
);
shellCall.request.args = { command: 'ls > files.txt' };
const { result } = await renderTestHook([shellCall]);
await act(async () => {
await result.current.handleApprovalModeChange(ApprovalMode.AUTO_EDIT);
});
// Shell command with redirection should be auto-approved
expect(mockMessageBus.publish).toHaveBeenCalledWith(
expect.objectContaining({ correlationId: 'corr-call-shell' }),
);
});
it('should NOT auto-approve shell commands without redirection when switching to AUTO_EDIT mode', async () => {
const shellCall = createMockToolCall(
SHELL_TOOL_NAME,
'call-shell',
'info',
);
shellCall.request.args = { command: 'ls -la' };
const { result } = await renderTestHook([shellCall]);
await act(async () => {
await result.current.handleApprovalModeChange(ApprovalMode.AUTO_EDIT);
});
// Regular shell command should NOT be auto-approved
expect(mockMessageBus.publish).not.toHaveBeenCalled();
});
it('should not auto-approve any tools when switching to REQUIRE_CONFIRMATION mode', async () => {
const awaitingApprovalToolCalls: TrackedToolCall[] = [
createMockToolCall('replace', 'call1', 'edit'),
+16 -3
View File
@@ -26,6 +26,8 @@ import {
debugLogger,
runInDevTraceSpan,
EDIT_TOOL_NAMES,
SHELL_TOOL_NAME,
hasRedirection,
processRestorableToolCalls,
recordToolCallInteractions,
ToolErrorType,
@@ -1820,10 +1822,21 @@ export const useGeminiStream = (
);
// For AUTO_EDIT mode, only approve edit tools (replace, write_file)
// or shell commands with redirection (which act as edits).
if (newApprovalMode === ApprovalMode.AUTO_EDIT) {
awaitingApprovalCalls = awaitingApprovalCalls.filter((call) =>
EDIT_TOOL_NAMES.has(call.request.name),
);
awaitingApprovalCalls = awaitingApprovalCalls.filter((call) => {
if (EDIT_TOOL_NAMES.has(call.request.name)) {
return true;
}
if (call.request.name === SHELL_TOOL_NAME) {
const command = (call.request.args as { command?: string })
.command;
return command && hasRedirection(command);
}
return false;
});
}
// Process pending tool calls sequentially to reduce UI chaos