Sync upstream Gemini-CLI v0.8.2 (#838)

This commit is contained in:
tanzhenxin 2025-10-23 09:27:04 +08:00 committed by GitHub
parent 096fabb5d6
commit eb95c131be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
644 changed files with 70389 additions and 23709 deletions

View file

@ -5,9 +5,9 @@
*/
import type React from 'react';
import { useEffect, useState } from 'react';
import { Box, Text } from 'ink';
import { DiffRenderer } from './DiffRenderer.js';
import { Colors } from '../../colors.js';
import { RenderInline } from '../../utils/InlineMarkdownRenderer.js';
import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
import type {
@ -16,11 +16,12 @@ import type {
ToolMcpConfirmationDetails,
Config,
} from '@qwen-code/qwen-code-core';
import { ToolConfirmationOutcome } from '@qwen-code/qwen-code-core';
import { IdeClient, ToolConfirmationOutcome } from '@qwen-code/qwen-code-core';
import type { RadioSelectItem } from '../shared/RadioButtonSelect.js';
import { RadioButtonSelect } from '../shared/RadioButtonSelect.js';
import { MaxSizedBox } from '../shared/MaxSizedBox.js';
import { useKeypress } from '../../hooks/useKeypress.js';
import { theme } from '../../semantic-colors.js';
export interface ToolConfirmationMessageProps {
confirmationDetails: ToolCallConfirmationDetails;
@ -44,10 +45,29 @@ export const ToolConfirmationMessage: React.FC<
const { onConfirm } = confirmationDetails;
const childWidth = terminalWidth - 2; // 2 for padding
const [ideClient, setIdeClient] = useState<IdeClient | null>(null);
const [isDiffingEnabled, setIsDiffingEnabled] = useState(false);
useEffect(() => {
let isMounted = true;
if (config.getIdeMode()) {
const getIdeClient = async () => {
const client = await IdeClient.getInstance();
if (isMounted) {
setIdeClient(client);
setIsDiffingEnabled(client?.isDiffingEnabled() ?? false);
}
};
getIdeClient();
}
return () => {
isMounted = false;
};
}, [config]);
const handleConfirm = async (outcome: ToolConfirmationOutcome) => {
if (confirmationDetails.type === 'edit') {
const ideClient = config.getIdeClient();
if (config.getIdeMode()) {
if (config.getIdeMode() && isDiffingEnabled) {
const cliOutcome =
outcome === ToolConfirmationOutcome.Cancel ? 'rejected' : 'accepted';
await ideClient?.resolveDiffFromCli(
@ -59,7 +79,7 @@ export const ToolConfirmationMessage: React.FC<
onConfirm(outcome);
};
const isTrustedFolder = config.isTrustedFolder() !== false;
const isTrustedFolder = config.isTrustedFolder();
useKeypress(
(key) => {
@ -77,14 +97,17 @@ export const ToolConfirmationMessage: React.FC<
if (compactMode) {
const compactOptions: Array<RadioSelectItem<ToolConfirmationOutcome>> = [
{
key: 'proceed-once',
label: 'Yes, allow once',
value: ToolConfirmationOutcome.ProceedOnce,
},
{
key: 'proceed-always',
label: 'Allow always',
value: ToolConfirmationOutcome.ProceedAlways,
},
{
key: 'cancel',
label: 'No',
value: ToolConfirmationOutcome.Cancel,
},
@ -150,13 +173,13 @@ export const ToolConfirmationMessage: React.FC<
<Box
minWidth="90%"
borderStyle="round"
borderColor={Colors.Gray}
borderColor={theme.border.default}
justifyContent="space-around"
padding={1}
overflow="hidden"
>
<Text>Modify in progress: </Text>
<Text color={Colors.AccentGreen}>
<Text color={theme.text.primary}>Modify in progress: </Text>
<Text color={theme.status.success}>
Save and close external editor to continue
</Text>
</Box>
@ -167,29 +190,29 @@ export const ToolConfirmationMessage: React.FC<
options.push({
label: 'Yes, allow once',
value: ToolConfirmationOutcome.ProceedOnce,
key: 'Yes, allow once',
});
if (isTrustedFolder) {
options.push({
label: 'Yes, allow always',
value: ToolConfirmationOutcome.ProceedAlways,
key: 'Yes, allow always',
});
}
if (config.getIdeMode()) {
options.push({
label: 'No (esc)',
value: ToolConfirmationOutcome.Cancel,
});
} else {
if (!config.getIdeMode() || !isDiffingEnabled) {
options.push({
label: 'Modify with external editor',
value: ToolConfirmationOutcome.ModifyWithEditor,
});
options.push({
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
key: 'Modify with external editor',
});
}
options.push({
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
key: 'No, suggest changes (esc)',
});
bodyContent = (
<DiffRenderer
diffContent={confirmationDetails.fileDiff}
@ -206,16 +229,19 @@ export const ToolConfirmationMessage: React.FC<
options.push({
label: 'Yes, allow once',
value: ToolConfirmationOutcome.ProceedOnce,
key: 'Yes, allow once',
});
if (isTrustedFolder) {
options.push({
label: `Yes, allow always ...`,
value: ToolConfirmationOutcome.ProceedAlways,
key: `Yes, allow always ...`,
});
}
options.push({
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
key: 'No, suggest changes (esc)',
});
let bodyContentHeight = availableBodyContentHeight();
@ -230,7 +256,7 @@ export const ToolConfirmationMessage: React.FC<
maxWidth={Math.max(childWidth - 4, 1)}
>
<Box>
<Text color={Colors.AccentCyan}>{executionProps.command}</Text>
<Text color={theme.text.link}>{executionProps.command}</Text>
</Box>
</MaxSizedBox>
</Box>
@ -241,14 +267,17 @@ export const ToolConfirmationMessage: React.FC<
question = planProps.title;
options.push({
key: 'proceed-always',
label: 'Yes, and auto-accept edits',
value: ToolConfirmationOutcome.ProceedAlways,
});
options.push({
key: 'proceed-once',
label: 'Yes, and manually approve edits',
value: ToolConfirmationOutcome.ProceedOnce,
});
options.push({
key: 'cancel',
label: 'No, keep planning (esc)',
value: ToolConfirmationOutcome.Cancel,
});
@ -273,26 +302,29 @@ export const ToolConfirmationMessage: React.FC<
options.push({
label: 'Yes, allow once',
value: ToolConfirmationOutcome.ProceedOnce,
key: 'Yes, allow once',
});
if (isTrustedFolder) {
options.push({
label: 'Yes, allow always',
value: ToolConfirmationOutcome.ProceedAlways,
key: 'Yes, allow always',
});
}
options.push({
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
key: 'No, suggest changes (esc)',
});
bodyContent = (
<Box flexDirection="column" paddingX={1} marginLeft={1}>
<Text color={Colors.AccentCyan}>
<Text color={theme.text.link}>
<RenderInline text={infoProps.prompt} />
</Text>
{displayUrls && infoProps.urls && infoProps.urls.length > 0 && (
<Box flexDirection="column" marginTop={1}>
<Text>URLs to fetch:</Text>
<Text color={theme.text.primary}>URLs to fetch:</Text>
{infoProps.urls.map((url) => (
<Text key={url}>
{' '}
@ -309,8 +341,8 @@ export const ToolConfirmationMessage: React.FC<
bodyContent = (
<Box flexDirection="column" paddingX={1} marginLeft={1}>
<Text color={Colors.AccentCyan}>MCP Server: {mcpProps.serverName}</Text>
<Text color={Colors.AccentCyan}>Tool: {mcpProps.toolName}</Text>
<Text color={theme.text.link}>MCP Server: {mcpProps.serverName}</Text>
<Text color={theme.text.link}>Tool: {mcpProps.toolName}</Text>
</Box>
);
@ -318,20 +350,24 @@ export const ToolConfirmationMessage: React.FC<
options.push({
label: 'Yes, allow once',
value: ToolConfirmationOutcome.ProceedOnce,
key: 'Yes, allow once',
});
if (isTrustedFolder) {
options.push({
label: `Yes, always allow tool "${mcpProps.toolName}" from server "${mcpProps.serverName}"`,
value: ToolConfirmationOutcome.ProceedAlwaysTool, // Cast until types are updated
key: `Yes, always allow tool "${mcpProps.toolName}" from server "${mcpProps.serverName}"`,
});
options.push({
label: `Yes, always allow all tools from server "${mcpProps.serverName}"`,
value: ToolConfirmationOutcome.ProceedAlwaysServer,
key: `Yes, always allow all tools from server "${mcpProps.serverName}"`,
});
}
options.push({
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
key: 'No, suggest changes (esc)',
});
}
@ -345,7 +381,9 @@ export const ToolConfirmationMessage: React.FC<
{/* Confirmation Question */}
<Box marginBottom={1} flexShrink={0}>
<Text wrap="truncate">{question}</Text>
<Text color={theme.text.primary} wrap="truncate">
{question}
</Text>
</Box>
{/* Select Input for Options */}