import { ReviewDecision } from "../../utils/agent/review"; // TODO: figure out why `cli-spinners` fails on Node v20.9.0 // which is why we have to do this in the first place // // @ts-expect-error select.js is JavaScript and has no types import { Select } from "../vendor/ink-select/select"; import TextInput from "../vendor/ink-text-input"; import { Box, Text, useInput } from "ink"; import React from "react"; // default deny‑reason: const DEFAULT_DENY_MESSAGE = "Don't do that, but keep trying to fix the problem"; export function TerminalChatCommandReview({ confirmationPrompt, onReviewCommand, }: { confirmationPrompt: React.ReactNode; onReviewCommand: (decision: ReviewDecision, customMessage?: string) => void; }): React.ReactElement { const [mode, setMode] = React.useState<"select" | "input">("select"); const [msg, setMsg] = React.useState(""); // ------------------------------------------------------------------------- // Determine whether the "always approve" option should be displayed. We // only hide it for the special `apply_patch` command since approving those // permanently would bypass the user's review of future file modifications. // The information is embedded in the `confirmationPrompt` React element – // we inspect the `commandForDisplay` prop exposed by // to extract the base command. // ------------------------------------------------------------------------- const showAlwaysApprove = React.useMemo(() => { if ( React.isValidElement(confirmationPrompt) && // eslint-disable-next-line @typescript-eslint/no-explicit-any typeof (confirmationPrompt as any).props?.commandForDisplay === "string" ) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const command: string = (confirmationPrompt as any).props .commandForDisplay; // Grab the first token of the first line – that corresponds to the base // command even when the string contains embedded newlines (e.g. diffs). const baseCmd = command.split("\n")[0]?.trim().split(/\s+/)[0] ?? ""; return baseCmd !== "apply_patch"; } // Default to showing the option when we cannot reliably detect the base // command. return true; }, [confirmationPrompt]); // Memoize the list of selectable options to avoid recreating the array on // every render. This keeps { if (value === "edit") { setMode("input"); } else { onReviewCommand(value); } }} options={approvalOptions} /> ) : ( <> Give the model feedback (↵ to submit): {msg.trim() === "" && ( default:  {DEFAULT_DENY_MESSAGE} )} )} ); }