import * as React from 'react'; import { Box, Text } from '@anthropic/ink'; import { useKeybindings } from '../../keybindings/useKeybinding.js'; import { type EffortValue, getDisplayedEffortLevel, getEffortEnvOverride } from '../../utils/effort.js'; import { type PanelPosition, CANCEL_MESSAGE, computeConfirmOutcome, getInitialCursor, moveLeft, moveRight, PANEL_POSITIONS, } from './effortPanelState.js'; import { executeEffort } from '../../commands/effort/effort.js'; import { useMainLoopModel } from '../../hooks/useMainLoopModel.js'; import { useSetAppState } from '../../state/AppState.js'; // 每档固定宽度,Ink Box 自动对齐。PANEL_WIDTH = SEGMENT * 6。 const SEGMENT = 12; const PANEL_WIDTH = SEGMENT * PANEL_POSITIONS.length; const SUBLABEL_ULTRACODE = 'xhigh + workflows'; type Props = { appStateEffort: EffortValue | undefined; onDone: (message: string) => void; }; export function EffortPanel({ appStateEffort, onDone }: Props): React.ReactNode { const setAppState = useSetAppState(); const model = useMainLoopModel(); const envOverride = getEffortEnvOverride(); const displayed = getDisplayedEffortLevel(model, appStateEffort); const initialCursor = getInitialCursor({ envOverride, appStateEffort, displayed }); const [cursor, setCursor] = React.useState(initialCursor); const [done, setDone] = React.useState(false); const handleConfirm = React.useCallback(() => { if (done) return; setDone(true); const outcome = computeConfirmOutcome(cursor, executeEffort); if (outcome.kind === 'apply' && outcome.effortUpdate) { setAppState(prev => ({ ...prev, effortValue: outcome.effortUpdate!.value, })); } onDone(outcome.message); }, [cursor, done, onDone, setAppState]); const handleCancel = React.useCallback(() => { if (done) return; setDone(true); onDone(CANCEL_MESSAGE); }, [done, onDone]); useKeybindings( { 'effortPanel:decrease': () => setCursor(c => moveLeft(c)), 'effortPanel:increase': () => setCursor(c => moveRight(c)), 'effortPanel:home': () => setCursor('low'), 'effortPanel:end': () => setCursor('ultracode'), 'effortPanel:confirm': handleConfirm, 'effortPanel:cancel': handleCancel, }, { context: 'EffortPanel' }, ); const envActive = envOverride !== null && envOverride !== undefined; const envRaw = process.env.CLAUDE_CODE_EFFORT_LEVEL; return ( Effort {envActive && {`⚠ CLAUDE_CODE_EFFORT_LEVEL=${envRaw} overrides this session`}} Faster Smarter {/* 分隔线 */} {'─'.repeat(PANEL_WIDTH)} {/* ▲ 行:每段独立居中,与下方档位文字严格对齐 */} {PANEL_POSITIONS.map(p => ( {cursor === p ? '▲' : ' '} ))} {/* 档位名:选中 suggestion + bold,未选中 subtle */} {PANEL_POSITIONS.map(p => ( {p} ))} {/* ultracode 副标签:右对齐到最末段 */} {SUBLABEL_ULTRACODE} ←/→ adjust · Enter confirm · Esc cancel ); }