diff --git a/src/providers/SidebarProvider.ts b/src/providers/SidebarProvider.ts index 81de7f3..7cbc7f4 100644 --- a/src/providers/SidebarProvider.ts +++ b/src/providers/SidebarProvider.ts @@ -196,7 +196,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider { case "askResponse": this.claudeDev?.handleWebviewAskResponse(message.askResponse!, message.text) break - case "abortTask": + case "clearTask": await this.clearTask() await this.postStateToWebview() break diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 126e1bc..9b291a9 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -1,7 +1,7 @@ export interface WebviewMessage { - type: "apiKey" | "maxRequestsPerTask" | "webviewDidLaunch" | "newTask" | "askResponse" | "abortTask" + type: "apiKey" | "maxRequestsPerTask" | "webviewDidLaunch" | "newTask" | "askResponse" | "clearTask" text?: string askResponse?: ClaudeAskResponse } -export type ClaudeAskResponse = "newTaskButtonTapped" | "yesButtonTapped" | "noButtonTapped" | "textResponse" \ No newline at end of file +export type ClaudeAskResponse = "yesButtonTapped" | "noButtonTapped" | "textResponse" \ No newline at end of file diff --git a/webview-ui/src/components/ChatRow.tsx b/webview-ui/src/components/ChatRow.tsx index 8d974d1..8452e3b 100644 --- a/webview-ui/src/components/ChatRow.tsx +++ b/webview-ui/src/components/ChatRow.tsx @@ -244,7 +244,7 @@ const ChatRow: React.FC = ({ message }) => { {title}
-

Claude Dev wants to execute the following command:

+

Claude Dev wants to execute the following terminal command. Would you like to proceed?

{command}

{output && ( <> diff --git a/webview-ui/src/components/ChatView.tsx b/webview-ui/src/components/ChatView.tsx index 79b663c..ab1bfb8 100644 --- a/webview-ui/src/components/ChatView.tsx +++ b/webview-ui/src/components/ChatView.tsx @@ -26,6 +26,7 @@ const ChatView = ({ messages }: ChatViewProps) => { const [textAreaHeight, setTextAreaHeight] = useState(undefined) const [textAreaDisabled, setTextAreaDisabled] = useState(false) + // we need to hold on to the ask because useEffect > lastMessage will always let us know when an ask comes in and handle it, but by the time handleMessage is called, the last message might not be the ask anymore (it could be a say that followed) const [claudeAsk, setClaudeAsk] = useState(undefined) const [primaryButtonText, setPrimaryButtonText] = useState(undefined) @@ -40,19 +41,6 @@ const ChatView = ({ messages }: ChatViewProps) => { }) } - const handlePrimaryButtonClick = () => { - //vscode.postMessage({ type: "askResponse", askResponse: "primaryButton" }) - setPrimaryButtonText(undefined) - setSecondaryButtonText(undefined) - } - - // New function to handle secondary button click - const handleSecondaryButtonClick = () => { - //vscode.postMessage({ type: "askResponse", askResponse: "secondaryButton" }) - setPrimaryButtonText(undefined) - setSecondaryButtonText(undefined) - } - // scroll to bottom when new message is added const visibleMessages = useMemo( () => @@ -73,50 +61,125 @@ const ChatView = ({ messages }: ChatViewProps) => { const lastMessage = messages.at(-1) if (lastMessage) { - if (lastMessage.type === "ask") { - //setTextAreaDisabled(false) // should enable for certain asks - setClaudeAsk(lastMessage.ask) - // Set button texts based on the ask - // setPrimaryButtonText(lastMessage.ask === "command" ? "Yes" : "Continue") - // setSecondaryButtonText(lastMessage.ask === "yesno" ? "No" : undefined) - setPrimaryButtonText("Yes") - setSecondaryButtonText("No") - } else { - //setTextAreaDisabled(true) - setClaudeAsk(undefined) - // setPrimaryButtonText(undefined) - // setSecondaryButtonText(undefined) - setPrimaryButtonText("Yes") - setSecondaryButtonText("No") + switch (lastMessage.type) { + case "ask": + switch (lastMessage.ask) { + case "request_limit_reached": + setTextAreaDisabled(true) + setClaudeAsk("request_limit_reached") + setPrimaryButtonText("Proceed") + setSecondaryButtonText("Start New Task") + break + case "followup": + setTextAreaDisabled(false) + setClaudeAsk("followup") + setPrimaryButtonText(undefined) + setSecondaryButtonText(undefined) + break + case "command": + setTextAreaDisabled(true) + setClaudeAsk("command") + setPrimaryButtonText("Yes") + setSecondaryButtonText("No") + break + case "completion_result": + // extension waiting for feedback. but we can just present a new task button + setTextAreaDisabled(false) + setClaudeAsk("completion_result") + setPrimaryButtonText("Start New Task") + setSecondaryButtonText(undefined) + break + } + break + case "say": + // don't want to reset since there could be a "say" after an "ask" while ask is waiting for response + switch (lastMessage.say) { + case "task": + break + case "error": + break + case "api_req_started": + break + case "api_req_finished": + break + case "text": + break + case "tool": + break + case "command_output": + break + case "completion_result": + break + } + break } + } else { + // No messages, so user has to submit a task + setTextAreaDisabled(false) + setClaudeAsk(undefined) + setPrimaryButtonText(undefined) + setSecondaryButtonText(undefined) } }, [messages]) const handleSendMessage = () => { const text = inputValue.trim() if (text) { - setInputValue("") if (messages.length === 0) { vscode.postMessage({ type: "newTask", text }) } else if (claudeAsk) { switch (claudeAsk) { case "followup": + case "completion_result": // if this happens then the user has feedback for the completion result vscode.postMessage({ type: "askResponse", askResponse: "textResponse", text }) break - // case "completion_result": - // vscode.postMessage({ type: "askResponse", text }) - // break - default: - // for now we'll type the askResponses - vscode.postMessage({ type: "askResponse", askResponse: text as ClaudeAskResponse }) - break + // there is no other case that a textfield should be enabled } } + setInputValue("") + setTextAreaDisabled(true) + setClaudeAsk(undefined) + setPrimaryButtonText(undefined) + setSecondaryButtonText(undefined) } } - // handle ask buttons - // be sure to setInputValue("") + /* + This logic depends on the useEffect[messages] above to set claudeAsk, after which buttons are shown and we then send an askResponse to the extension. + */ + const handlePrimaryButtonClick = () => { + switch (claudeAsk) { + case "request_limit_reached": + vscode.postMessage({ type: "askResponse", askResponse: "yesButtonTapped" }) + break + case "command": + vscode.postMessage({ type: "askResponse", askResponse: "yesButtonTapped" }) + break + case "completion_result": + // extension waiting for feedback. but we can just present a new task button + startNewTask() + break + } + setTextAreaDisabled(true) + setClaudeAsk(undefined) + setPrimaryButtonText(undefined) + setSecondaryButtonText(undefined) + } + + const handleSecondaryButtonClick = () => { + switch (claudeAsk) { + case "request_limit_reached": + startNewTask() + break + case "command": + vscode.postMessage({ type: "askResponse", askResponse: "noButtonTapped" }) + break + } + setTextAreaDisabled(true) + setClaudeAsk(undefined) + setPrimaryButtonText(undefined) + setSecondaryButtonText(undefined) + } const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Enter" && !event.shiftKey) { @@ -126,7 +189,11 @@ const ChatView = ({ messages }: ChatViewProps) => { } const handleTaskCloseButtonClick = () => { - vscode.postMessage({ type: "abortTask" }) + startNewTask() + } + + const startNewTask = () => { + vscode.postMessage({ type: "clearTask" }) } useEffect(() => { @@ -172,13 +239,15 @@ const ChatView = ({ messages }: ChatViewProps) => { flexDirection: "column", overflow: "hidden", }}> - + {task && ( + + )}
{ display: "flex", alignItems: "center", }}> - +