mirror of
https://github.com/openai/codex.git
synced 2026-10-30 19:18:49 +00:00
# Shell Command Explanation Option ## Description This PR adds an option to explain shell commands when the user is prompted to approve them (Fixes #110). When reviewing a shell command, users can now select "Explain this command" to get a detailed explanation of what the command does before deciding whether to approve or reject it. ## Changes - Added a new "EXPLAIN" option to the `ReviewDecision` enum - Updated the command review UI to include an "Explain this command (x)" option - Implemented the logic to send the command to the LLM for explanation using the same model as the agent - Added a display for the explanation in the command review UI - Updated all relevant components to pass the explanation through the component tree ## Benefits - Improves user understanding of shell commands before approving them - Reduces the risk of approving potentially harmful commands - Enhances the educational aspect of the tool, helping users learn about shell commands - Maintains the same workflow with minimal UI changes ## Testing - Manually tested the explanation feature with various shell commands - Verified that the explanation is displayed correctly in the UI - Confirmed that the user can still approve or reject the command after viewing the explanation ## Screenshots  ## Additional Notes The explanation is generated using the same model as the agent, ensuring consistency in the quality and style of explanations. --------- Signed-off-by: crazywolf132 <crazywolf132@gmail.com>
69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
// use-confirmation.ts
|
|
import type { ReviewDecision } from "../utils/agent/review";
|
|
import type React from "react";
|
|
|
|
import { useState, useCallback, useRef } from "react";
|
|
|
|
type ConfirmationResult = {
|
|
decision: ReviewDecision;
|
|
customDenyMessage?: string;
|
|
};
|
|
|
|
type ConfirmationItem = {
|
|
prompt: React.ReactNode;
|
|
resolve: (result: ConfirmationResult) => void;
|
|
explanation?: string;
|
|
};
|
|
|
|
export function useConfirmation(): {
|
|
submitConfirmation: (result: ConfirmationResult) => void;
|
|
requestConfirmation: (
|
|
prompt: React.ReactNode,
|
|
explanation?: string,
|
|
) => Promise<ConfirmationResult>;
|
|
confirmationPrompt: React.ReactNode | null;
|
|
explanation?: string;
|
|
} {
|
|
// The current prompt is just the head of the queue
|
|
const [current, setCurrent] = useState<ConfirmationItem | null>(null);
|
|
// The entire queue is stored in a ref to avoid re-renders
|
|
const queueRef = useRef<Array<ConfirmationItem>>([]);
|
|
|
|
// Move queue forward to the next prompt
|
|
const advanceQueue = useCallback(() => {
|
|
const next = queueRef.current.shift() ?? null;
|
|
setCurrent(next);
|
|
}, []);
|
|
|
|
// Called whenever someone wants a confirmation
|
|
const requestConfirmation = useCallback(
|
|
(prompt: React.ReactNode, explanation?: string) => {
|
|
return new Promise<ConfirmationResult>((resolve) => {
|
|
const wasEmpty = queueRef.current.length === 0;
|
|
queueRef.current.push({ prompt, resolve, explanation });
|
|
|
|
// If the queue was empty, we need to kick off the first prompt
|
|
if (wasEmpty) {
|
|
advanceQueue();
|
|
}
|
|
});
|
|
},
|
|
[advanceQueue],
|
|
);
|
|
|
|
// Called whenever user picks Yes / No
|
|
const submitConfirmation = (result: ConfirmationResult) => {
|
|
if (current) {
|
|
current.resolve(result);
|
|
advanceQueue();
|
|
}
|
|
};
|
|
|
|
return {
|
|
confirmationPrompt: current?.prompt, // the prompt to render now
|
|
explanation: current?.explanation, // the explanation to render if available
|
|
requestConfirmation,
|
|
submitConfirmation,
|
|
};
|
|
}
|