import { Box, Text, useInput } from "ink"; import { memo, useState } from "react"; import { useTerminalWidth } from "../hooks/useTerminalWidth"; import { colors } from "./colors"; type Props = { onApprove: () => void; onApproveAndAcceptEdits: () => void; onKeepPlanning: (reason: string) => void; isFocused?: boolean; }; /** * StaticPlanApproval - Options-only plan approval component * * This component renders ONLY the approval options (no plan preview). * The plan preview is committed separately to the Static area via the * eager commit pattern, which keeps this component small (~8 lines) * and flicker-free. * * The plan prop was removed because the plan is rendered in the Static * area by ApprovalPreview, not here. */ export const StaticPlanApproval = memo( ({ onApprove, onApproveAndAcceptEdits, onKeepPlanning, isFocused = true, }: Props) => { const [selectedOption, setSelectedOption] = useState(0); const [customReason, setCustomReason] = useState(""); const columns = useTerminalWidth(); const customOptionIndex = 2; const maxOptionIndex = customOptionIndex; const isOnCustomOption = selectedOption === customOptionIndex; const customOptionPlaceholder = "Type here to tell Letta Code what to change"; useInput( (input, key) => { if (!isFocused) return; // CTRL-C: keep planning with cancel message if (key.ctrl && input === "c") { onKeepPlanning("User pressed CTRL-C to cancel"); return; } // Arrow navigation always works if (key.upArrow) { setSelectedOption((prev) => Math.max(0, prev - 1)); return; } if (key.downArrow) { setSelectedOption((prev) => Math.min(maxOptionIndex, prev + 1)); return; } // When on custom input option if (isOnCustomOption) { if (key.return) { if (customReason.trim()) { onKeepPlanning(customReason.trim()); } return; } if (key.escape) { if (customReason) { setCustomReason(""); } else { onKeepPlanning("User cancelled"); } return; } if (key.backspace || key.delete) { setCustomReason((prev) => prev.slice(0, -1)); return; } if (input && !key.ctrl && !key.meta && input.length === 1) { setCustomReason((prev) => prev + input); } return; } // When on regular options if (key.return) { if (selectedOption === 0) { onApproveAndAcceptEdits(); } else if (selectedOption === 1) { onApprove(); } return; } if (key.escape) { onKeepPlanning("User cancelled"); } }, { isActive: isFocused }, ); // Hint text based on state const hintText = isOnCustomOption ? customReason ? "Enter to submit · Esc to clear" : "Type feedback · Esc to cancel" : "Enter to select · Esc to cancel"; return ( {/* Question */} Would you like to proceed? {/* Options */} {/* Option 1: Yes, and auto-accept edits */} {selectedOption === 0 ? "❯" : " "} 1. Yes, and auto-accept edits {/* Option 2: Yes, and manually approve edits */} {selectedOption === 1 ? "❯" : " "} 2. Yes, and manually approve edits {/* Option 3: Custom input */} {isOnCustomOption ? "❯" : " "} 3. {customReason ? ( {customReason} {isOnCustomOption && "█"} ) : ( {customOptionPlaceholder} {isOnCustomOption && "█"} )} {/* Hint */} {hintText} ); }, ); StaticPlanApproval.displayName = "StaticPlanApproval";