mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
fix(ai,cli): remove top capture button from AI chat and support arrow key selection in CLI update prompt
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
40a4357ff7
commit
e6d67afdad
2 files changed
+43
-27
No files matched your search
@@ -88,35 +88,67 @@ async function fetchLatestVersion(): Promise<string | null> {
|
||||
|
||||
function promptUser(question: string, choices: string[]): Promise<number> {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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<HTMLElement | null>(null)
|
||||
|
||||
// 检查 LLM 配置
|
||||
async function checkLLMConfig() {
|
||||
isCheckingConfig.value = true
|
||||
@@ -362,7 +358,6 @@ watch(
|
||||
:class="{ 'p-0!': messages.length === 0 && !isAIThinking }"
|
||||
>
|
||||
<div
|
||||
ref="conversationContentRef"
|
||||
class="mx-auto max-w-3xl space-y-6"
|
||||
:class="{
|
||||
'flex min-h-full flex-col justify-center px-4 pb-32 pt-4 space-y-0!':
|
||||
@@ -416,17 +411,6 @@ watch(
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 对话截屏按钮 -->
|
||||
<div v-if="qaPairs.length > 0 && !isAIThinking" class="flex justify-end">
|
||||
<CaptureButton
|
||||
:label="t('ai.chat.capture')"
|
||||
size="xs"
|
||||
type="element"
|
||||
:target-element="conversationContentRef"
|
||||
markdown-fix
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- QA 对渲染 -->
|
||||
<template v-for="pair in qaPairs" :key="pair.id">
|
||||
<!-- 独立消息(summary 等非 user/assistant) -->
|
||||
|
||||
Reference in new issue
Block a user