diff --git a/src/components/ai/AiTerminalPanel.tsx b/src/components/ai/AiTerminalPanel.tsx index c96c09a..3dbc19a 100644 --- a/src/components/ai/AiTerminalPanel.tsx +++ b/src/components/ai/AiTerminalPanel.tsx @@ -20,7 +20,6 @@ import { extractBashBlocks, singleLineTerminalInsert, terminalContextLineCount } import { writeClipboardText } from '../../platform/clipboard' import { analyzeAgentOutput } from '../../utils/agentOutput' import { - agentCommandAllowFingerprint, agentCommandNeedsConfirmation, assessAgentCommandRisk, normalizeAgentSafetyMode, @@ -45,8 +44,6 @@ interface AiTerminalPanelProps { connectionId?: string | null targetLabel?: string isLocal?: boolean - /** 将命令文本写入当前焦点终端输入行(不带回车);返回 false 表示当前不可写。 */ - insertToTerminal?: (text: string) => boolean } interface AgentStep { @@ -176,7 +173,6 @@ export default function AiTerminalPanel({ connectionId = null, targetLabel = '当前 SSH 会话', isLocal = false, - insertToTerminal, }: AiTerminalPanelProps) { const { t } = useTranslation('ai') const store = useAiProviderStore() @@ -197,7 +193,7 @@ export default function AiTerminalPanel({ const [copiedId, setCopiedId] = useState('') const runIdRef = useRef(0) const runConnectionIdRef = useRef(null) - const sessionAllowRef = useRef(new Set()) + const sessionAllowRef = useRef(false) const timelineRef = useRef(null) const initialSelectionRef = useRef('') const liveStepsRef = useRef([]) @@ -230,7 +226,7 @@ export default function AiTerminalPanel({ setPrompt('') setQueued(null) setCopiedId('') - sessionAllowRef.current.clear() + sessionAllowRef.current = false initialSelectionRef.current = '' } @@ -334,54 +330,34 @@ export default function AiTerminalPanel({ throw new Error(i18n.t('ai:error.criticalBlocked', { command })) } const proposed: AgentStep = { round, command, risk, status: 'running' } - if (agentCommandNeedsConfirmation(risk, runSafetyMode, runConfirmAll)) { - const fingerprint = agentCommandAllowFingerprint(command, risk) - if (!sessionAllowRef.current.has(fingerprint)) { - const awaiting = { ...proposed, status: 'awaiting' as const } - setLiveSteps([...completedSteps, awaiting]) - const choice = await confirmAgentRisk({ - title: t('step.confirmTitle', { round, risk: t(`risk.${risk}`) }), - message: t('step.confirmMessage', { - target: targetLabel, - mode: t(`safety.${runSafetyMode}.label`), - command, - }), - danger: risk === 'high', - }) - if (runIdRef.current !== runId) return - if (choice === 'insert') { - const inserted = insertToTerminal?.(command) || false - if (!inserted) { - await writeClipboardText(command) - } - setLiveSteps([]) - setMessages((prev) => [ - ...prev, - { - id: messageId(), - role: 'assistant', - content: inserted ? t('step.inserted', { round }) : t('step.insertedClipboard', { round }), - steps: [...completedSteps], - }, - ]) - return - } - if (choice === 'reject') { - setLiveSteps([]) - setMessages((prev) => [ - ...prev, - { - id: messageId(), - role: 'assistant', - content: t('step.rejected', { round }), - steps: [...completedSteps], - }, - ]) - return - } - if (choice === 'always') { - sessionAllowRef.current.add(fingerprint) - } + if (agentCommandNeedsConfirmation(risk, runSafetyMode, runConfirmAll) && !sessionAllowRef.current) { + const awaiting = { ...proposed, status: 'awaiting' as const } + setLiveSteps([...completedSteps, awaiting]) + const choice = await confirmAgentRisk({ + title: t('step.confirmTitle', { round, risk: t(`risk.${risk}`) }), + message: t('step.confirmMessage', { + target: targetLabel, + mode: t(`safety.${runSafetyMode}.label`), + command, + }), + danger: risk === 'high', + }) + if (runIdRef.current !== runId) return + if (choice === 'reject') { + setLiveSteps([]) + setMessages((prev) => [ + ...prev, + { + id: messageId(), + role: 'assistant', + content: t('step.rejected', { round }), + steps: [...completedSteps], + }, + ]) + return + } + if (choice === 'always') { + sessionAllowRef.current = true } } diff --git a/src/components/common/ConfirmDialog.tsx b/src/components/common/ConfirmDialog.tsx index 63a7276..ab35cbc 100644 --- a/src/components/common/ConfirmDialog.tsx +++ b/src/components/common/ConfirmDialog.tsx @@ -31,8 +31,8 @@ export interface ConfirmOptions { cancelText?: string } -/** Agent 高风险确认:Reject / Insert(只插入不执行)/ Once / Always(Always 仅会话内存) */ -export type AgentRiskChoice = 'reject' | 'once' | 'always' | 'insert' +/** Agent 高风险确认:Reject / Once / Always(Always 对本话题后续命令生效,仅内存) */ +export type AgentRiskChoice = 'reject' | 'once' | 'always' export interface AgentRiskConfirmOptions { title: string @@ -173,9 +173,6 @@ export function useConfirmDialog() { -