refactor(cli): unify shell confirmation dialogs (#16828)

This commit is contained in:
N. Taylor Mullen
2026-01-16 15:06:52 -08:00
committed by GitHub
parent 608da23393
commit 1681ae1842
14 changed files with 102 additions and 446 deletions
@@ -18,6 +18,7 @@ import type {
Config,
ExtensionsStartingEvent,
ExtensionsStoppingEvent,
ToolCallConfirmationDetails,
} from '@google/gemini-cli-core';
import {
GitService,
@@ -39,8 +40,9 @@ import type {
SlashCommandProcessorResult,
HistoryItem,
ConfirmationRequest,
IndividualToolCallDisplay,
} from '../types.js';
import { MessageType } from '../types.js';
import { MessageType, ToolCallStatus } from '../types.js';
import type { LoadedSettings } from '../../config/settings.js';
import { type CommandContext, type SlashCommand } from '../commands/types.js';
import { CommandService } from '../../services/CommandService.js';
@@ -103,14 +105,6 @@ export const useSlashCommandProcessor = (
const reloadCommands = useCallback(() => {
setReloadTrigger((v) => v + 1);
}, []);
const [shellConfirmationRequest, setShellConfirmationRequest] =
useState<null | {
commands: string[];
onConfirm: (
outcome: ToolConfirmationOutcome,
approvedCommands?: string[],
) => void;
}>(null);
const [confirmationRequest, setConfirmationRequest] = useState<null | {
prompt: React.ReactNode;
onConfirm: (confirmed: boolean) => void;
@@ -484,30 +478,59 @@ export const useSlashCommandProcessor = (
content: result.content,
};
case 'confirm_shell_commands': {
const callId = `expansion-${Date.now()}`;
const { outcome, approvedCommands } = await new Promise<{
outcome: ToolConfirmationOutcome;
approvedCommands?: string[];
}>((resolve) => {
setShellConfirmationRequest({
const confirmationDetails: ToolCallConfirmationDetails = {
type: 'exec',
title: `Confirm Shell Expansion`,
command: result.commandsToConfirm[0] || '',
rootCommand: result.commandsToConfirm[0] || '',
rootCommands: result.commandsToConfirm,
commands: result.commandsToConfirm,
onConfirm: (
resolvedOutcome,
resolvedApprovedCommands,
) => {
setShellConfirmationRequest(null); // Close the dialog
onConfirm: async (resolvedOutcome) => {
// Close the pending tool display by resolving
resolve({
outcome: resolvedOutcome,
approvedCommands: resolvedApprovedCommands,
approvedCommands:
resolvedOutcome === ToolConfirmationOutcome.Cancel
? []
: result.commandsToConfirm,
});
},
};
const toolDisplay: IndividualToolCallDisplay = {
callId,
name: 'Expansion',
description: 'Command expansion needs shell access',
status: ToolCallStatus.Confirming,
resultDisplay: undefined,
confirmationDetails,
};
setPendingItem({
type: 'tool_group',
tools: [toolDisplay],
});
});
setPendingItem(null);
if (
outcome === ToolConfirmationOutcome.Cancel ||
!approvedCommands ||
approvedCommands.length === 0
) {
addItem(
{
type: MessageType.INFO,
text: 'Slash command shell execution declined.',
},
Date.now(),
);
return { type: 'handled' };
}
@@ -521,6 +544,8 @@ export const useSlashCommandProcessor = (
result.originalInvocation.raw,
// Pass the approved commands as a one-time grant for this execution.
new Set(approvedCommands),
undefined,
false, // Do not add to history again
);
}
case 'confirm_action': {
@@ -633,7 +658,6 @@ export const useSlashCommandProcessor = (
commands,
commandContext,
addMessage,
setShellConfirmationRequest,
setSessionShellAllowlist,
setIsProcessing,
setConfirmationRequest,
@@ -646,7 +670,6 @@ export const useSlashCommandProcessor = (
slashCommands: commands,
pendingHistoryItems,
commandContext,
shellConfirmationRequest,
confirmationRequest,
};
};