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
644 changed files with 70389 additions and 23709 deletions

View File

@@ -6,8 +6,9 @@
import type React from 'react';
import { useState } from 'react';
import { Box, Text, useInput } from 'ink';
import { Box, Text } from 'ink';
import { Colors } from '../colors.js';
import { useKeypress } from '../hooks/useKeypress.js';
interface OpenAIKeyPromptProps {
onSubmit: (apiKey: string, baseUrl: string, model: string) => void;
@@ -25,104 +26,130 @@ export function OpenAIKeyPrompt({
'apiKey' | 'baseUrl' | 'model'
>('apiKey');
useInput((input, key) => {
// 过滤粘贴相关的控制序列
let cleanInput = (input || '')
// 过滤 ESC 开头的控制序列(如 \u001b[200~、\u001b[201~ 等)
.replace(/\u001b\[[0-9;]*[a-zA-Z]/g, '') // eslint-disable-line no-control-regex
// 过滤粘贴开始标记 [200~
.replace(/\[200~/g, '')
// 过滤粘贴结束标记 [201~
.replace(/\[201~/g, '')
// 过滤单独的 [ 和 ~ 字符(可能是粘贴标记的残留)
.replace(/^\[|~$/g, '');
// 再过滤所有不可见字符ASCII < 32除了回车换行
cleanInput = cleanInput
.split('')
.filter((ch) => ch.charCodeAt(0) >= 32)
.join('');
if (cleanInput.length > 0) {
if (currentField === 'apiKey') {
setApiKey((prev) => prev + cleanInput);
} else if (currentField === 'baseUrl') {
setBaseUrl((prev) => prev + cleanInput);
} else if (currentField === 'model') {
setModel((prev) => prev + cleanInput);
useKeypress(
(key) => {
// Handle escape
if (key.name === 'escape') {
onCancel();
return;
}
return;
}
// 检查是否是 Enter 键(通过检查输入是否包含换行符)
if (input.includes('\n') || input.includes('\r')) {
if (currentField === 'apiKey') {
// 允许空 API key 跳转到下一个字段,让用户稍后可以返回修改
setCurrentField('baseUrl');
// Handle Enter key
if (key.name === 'return') {
if (currentField === 'apiKey') {
// 允许空 API key 跳转到下一个字段,让用户稍后可以返回修改
setCurrentField('baseUrl');
return;
} else if (currentField === 'baseUrl') {
setCurrentField('model');
return;
} else if (currentField === 'model') {
// 只有在提交时才检查 API key 是否为空
if (apiKey.trim()) {
onSubmit(apiKey.trim(), baseUrl.trim(), model.trim());
} else {
// 如果 API key 为空,回到 API key 字段
setCurrentField('apiKey');
}
}
return;
} else if (currentField === 'baseUrl') {
setCurrentField('model');
return;
} else if (currentField === 'model') {
// 只有在提交时才检查 API key 是否为空
if (apiKey.trim()) {
onSubmit(apiKey.trim(), baseUrl.trim(), model.trim());
} else {
// 如果 API key 为空,回到 API key 字段
}
// Handle Tab key for field navigation
if (key.name === 'tab') {
if (currentField === 'apiKey') {
setCurrentField('baseUrl');
} else if (currentField === 'baseUrl') {
setCurrentField('model');
} else if (currentField === 'model') {
setCurrentField('apiKey');
}
return;
}
return;
}
if (key.escape) {
onCancel();
return;
}
// Handle Tab key for field navigation
if (key.tab) {
if (currentField === 'apiKey') {
setCurrentField('baseUrl');
} else if (currentField === 'baseUrl') {
setCurrentField('model');
} else if (currentField === 'model') {
setCurrentField('apiKey');
// Handle arrow keys for field navigation
if (key.name === 'up') {
if (currentField === 'baseUrl') {
setCurrentField('apiKey');
} else if (currentField === 'model') {
setCurrentField('baseUrl');
}
return;
}
return;
}
// Handle arrow keys for field navigation
if (key.upArrow) {
if (currentField === 'baseUrl') {
setCurrentField('apiKey');
} else if (currentField === 'model') {
setCurrentField('baseUrl');
if (key.name === 'down') {
if (currentField === 'apiKey') {
setCurrentField('baseUrl');
} else if (currentField === 'baseUrl') {
setCurrentField('model');
}
return;
}
return;
}
if (key.downArrow) {
if (currentField === 'apiKey') {
setCurrentField('baseUrl');
} else if (currentField === 'baseUrl') {
setCurrentField('model');
// Handle backspace/delete
if (key.name === 'backspace' || key.name === 'delete') {
if (currentField === 'apiKey') {
setApiKey((prev) => prev.slice(0, -1));
} else if (currentField === 'baseUrl') {
setBaseUrl((prev) => prev.slice(0, -1));
} else if (currentField === 'model') {
setModel((prev) => prev.slice(0, -1));
}
return;
}
return;
}
// Handle backspace - check both key.backspace and delete key
if (key.backspace || key.delete) {
if (currentField === 'apiKey') {
setApiKey((prev) => prev.slice(0, -1));
} else if (currentField === 'baseUrl') {
setBaseUrl((prev) => prev.slice(0, -1));
} else if (currentField === 'model') {
setModel((prev) => prev.slice(0, -1));
// Handle paste mode - if it's a paste event with content
if (key.paste && key.sequence) {
// 过滤粘贴相关的控制序列
let cleanInput = key.sequence
// 过滤 ESC 开头的控制序列(如 \u001b[200~、\u001b[201~ 等)
.replace(/\u001b\[[0-9;]*[a-zA-Z]/g, '') // eslint-disable-line no-control-regex
// 过滤粘贴开始标记 [200~
.replace(/\[200~/g, '')
// 过滤粘贴结束标记 [201~
.replace(/\[201~/g, '')
// 过滤单独的 [ 和 ~ 字符(可能是粘贴标记的残留)
.replace(/^\[|~$/g, '');
// 再过滤所有不可见字符ASCII < 32除了回车换行
cleanInput = cleanInput
.split('')
.filter((ch) => ch.charCodeAt(0) >= 32)
.join('');
if (cleanInput.length > 0) {
if (currentField === 'apiKey') {
setApiKey((prev) => prev + cleanInput);
} else if (currentField === 'baseUrl') {
setBaseUrl((prev) => prev + cleanInput);
} else if (currentField === 'model') {
setModel((prev) => prev + cleanInput);
}
}
return;
}
return;
}
});
// Handle regular character input
if (key.sequence && !key.ctrl && !key.meta && !key.name) {
// Filter control characters
const cleanInput = key.sequence
.split('')
.filter((ch) => ch.charCodeAt(0) >= 32)
.join('');
if (cleanInput.length > 0) {
if (currentField === 'apiKey') {
setApiKey((prev) => prev + cleanInput);
} else if (currentField === 'baseUrl') {
setBaseUrl((prev) => prev + cleanInput);
} else if (currentField === 'model') {
setModel((prev) => prev + cleanInput);
}
}
}
},
{ isActive: true },
);
return (
<Box