From e6d67afdadd77cc85b495b661278162256099dd1 Mon Sep 17 00:00:00 2001 From: digua Date: Sat, 13 Jun 2026 13:39:04 +0800 Subject: [PATCH] fix(ai,cli): remove top capture button from AI chat and support arrow key selection in CLI update prompt Co-authored-by: Cursor --- apps/cli/src/update-checker.ts | 54 ++++++++++++++++++++------ src/components/AIChat/ChatExplorer.vue | 16 -------- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/apps/cli/src/update-checker.ts b/apps/cli/src/update-checker.ts index d0f55376..947ae6dc 100644 --- a/apps/cli/src/update-checker.ts +++ b/apps/cli/src/update-checker.ts @@ -88,35 +88,67 @@ async function fetchLatestVersion(): Promise { function promptUser(question: string, choices: string[]): Promise { return new Promise((resolve) => { + let selected = 0 + + const render = () => { + // Move cursor up to rewrite choices (skip on first draw) + if (rendered) process.stderr.write(`\x1b[${choices.length}A`) + choices.forEach((c, i) => { + process.stderr.write(`\x1b[2K${i === selected ? '› ' : ' '}${i + 1}. ${c}\n`) + }) + } + process.stderr.write(`${question}\n\n`) - choices.forEach((c, i) => { - process.stderr.write(i === 0 ? `› ${i + 1}. ${c}\n` : ` ${i + 1}. ${c}\n`) - }) - process.stderr.write('\n') if (!process.stdin.isTTY || !process.stdin.setRawMode) { resolve(2) return } + let rendered = false + render() + rendered = true + process.stderr.write('\n') + process.stdin.setRawMode(true) process.stdin.resume() + const cleanup = () => { + process.stdin.removeListener('data', onData) + process.stdin.setRawMode!(false) + process.stdin.pause() + } + const onData = (data: Buffer) => { const key = data.toString() if (key === '\x03') { - process.stdin.setRawMode!(false) - process.stdin.pause() + cleanup() process.exit(0) } - // Only accept single-digit keys matching a valid choice; - // ignore arrow keys (\x1b[A/B/C/D), Enter, and other non-digit input. + // Arrow up / k + if (key === '\x1b[A' || key === 'k') { + selected = (selected - 1 + choices.length) % choices.length + render() + return + } + // Arrow down / j + if (key === '\x1b[B' || key === 'j') { + selected = (selected + 1) % choices.length + render() + return + } + // Enter — confirm current selection + if (key === '\r' || key === '\n') { + cleanup() + process.stderr.write('\n') + resolve(selected + 1) + return + } + // Digit key — direct choice if (key.length === 1) { const num = parseInt(key) if (num >= 1 && num <= choices.length) { - process.stdin.removeListener('data', onData) - process.stdin.setRawMode!(false) - process.stdin.pause() + cleanup() process.stderr.write('\n') resolve(num) } diff --git a/src/components/AIChat/ChatExplorer.vue b/src/components/AIChat/ChatExplorer.vue index 3b464eaf..48f37632 100644 --- a/src/components/AIChat/ChatExplorer.vue +++ b/src/components/AIChat/ChatExplorer.vue @@ -10,7 +10,6 @@ import AIThinkingIndicator from './chat/AIThinkingIndicator.vue' import ChatStatusBar from './chat/ChatStatusBar.vue' import { useAIChat } from '@/composables/useAIChat' import { useAIService, useLLMService } from '@/services' -import CaptureButton from '@/components/common/CaptureButton.vue' import AssistantInlineBar from './assistant/AssistantInlineBar.vue' import AssistantConfigModal from './assistant/AssistantConfigModal.vue' import AssistantMarketModal from './assistant/AssistantMarketModal.vue' @@ -137,9 +136,6 @@ const chatInputRef = ref<{ // QA 对 const qaPairs = computed(() => groupMessagesToQAPairs(messages.value)) -// 截屏功能 -const conversationContentRef = ref(null) - // 检查 LLM 配置 async function checkLLMConfig() { isCheckingConfig.value = true @@ -362,7 +358,6 @@ watch( :class="{ 'p-0!': messages.length === 0 && !isAIThinking }" >
0 && !isAIThinking" class="flex justify-end"> - -
-