diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index af5f9925c35..af4b15a09bb 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -1694,7 +1694,12 @@ export const webviewMessageHandler = async ( if (result.success && result.enhancedText) { // Capture telemetry for prompt enhancement MessageEnhancer.captureTelemetry(currentCline?.taskId, includeTaskHistoryInEnhance) - await provider.postMessageToWebview({ type: "enhancedPrompt", text: result.enhancedText }) + // Include the context from the original request in the response + await provider.postMessageToWebview({ + type: "enhancedPrompt", + text: result.enhancedText, + context: message.context, + }) } else { throw new Error(result.error || "Unknown error") } @@ -1704,7 +1709,11 @@ export const webviewMessageHandler = async ( ) vscode.window.showErrorMessage(t("common:errors.enhance_prompt")) - await provider.postMessageToWebview({ type: "enhancedPrompt" }) + // Include context even in error response + await provider.postMessageToWebview({ + type: "enhancedPrompt", + context: message.context, + }) } } break diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index c7813372fa7..df04ef935bb 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -124,28 +124,33 @@ export const ChatTextArea = forwardRef( const message = event.data if (message.type === "enhancedPrompt") { - if (message.text && textAreaRef.current) { - try { - // Use execCommand to replace text while preserving undo history - if (document.execCommand) { - // Use native browser methods to preserve undo stack - const textarea = textAreaRef.current - - // Focus the textarea to ensure it's the active element - textarea.focus() - - // Select all text first - textarea.select() - document.execCommand("insertText", false, message.text) - } else { + // Only handle the enhanced prompt if it's for this specific textarea instance + // Edit mode textareas have context "edit", main textarea has context "main" + const expectedContext = isEditMode ? "edit" : "main" + if (message.context === expectedContext) { + if (message.text && textAreaRef.current) { + try { + // Use execCommand to replace text while preserving undo history + if (document.execCommand) { + // Use native browser methods to preserve undo stack + const textarea = textAreaRef.current + + // Focus the textarea to ensure it's the active element + textarea.focus() + + // Select all text first + textarea.select() + document.execCommand("insertText", false, message.text) + } else { + setInputValue(message.text) + } + } catch { setInputValue(message.text) } - } catch { - setInputValue(message.text) } - } - setIsEnhancingPrompt(false) + setIsEnhancingPrompt(false) + } } else if (message.type === "insertTextIntoTextarea") { if (message.text && textAreaRef.current) { // Insert the command text at the current cursor position @@ -196,7 +201,7 @@ export const ChatTextArea = forwardRef( window.addEventListener("message", messageHandler) return () => window.removeEventListener("message", messageHandler) - }, [setInputValue, searchRequestId, inputValue]) + }, [setInputValue, searchRequestId, inputValue, isEditMode]) const [isDraggingOver, setIsDraggingOver] = useState(false) const [textAreaBaseHeight, setTextAreaBaseHeight] = useState(undefined) @@ -239,11 +244,13 @@ export const ChatTextArea = forwardRef( if (trimmedInput) { setIsEnhancingPrompt(true) - vscode.postMessage({ type: "enhancePrompt" as const, text: trimmedInput }) + // Include context to identify which textarea is requesting enhancement + const context = isEditMode ? "edit" : "main" + vscode.postMessage({ type: "enhancePrompt" as const, text: trimmedInput, context }) } else { setInputValue(t("chat:enhancePromptDescription")) } - }, [inputValue, setInputValue, t]) + }, [inputValue, setInputValue, t, isEditMode]) const allModes = useMemo(() => getAllModes(customModes), [customModes]) diff --git a/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx index af7704aa1b7..d49ea19308d 100644 --- a/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx @@ -112,6 +112,7 @@ describe("ChatTextArea", () => { expect(mockPostMessage).toHaveBeenCalledWith({ type: "enhancePrompt", text: "Test prompt", + context: "main", }) }) @@ -183,7 +184,7 @@ describe("ChatTextArea", () => { }) describe("enhanced prompt response", () => { - it("should update input value using native browser methods when receiving enhanced prompt", () => { + it("should update input value using native browser methods when receiving enhanced prompt with matching context", () => { const setInputValue = vi.fn() // Mock document.execCommand @@ -205,12 +206,13 @@ describe("ChatTextArea", () => { textarea.select = mockSelect textarea.focus = mockFocus - // Simulate receiving enhanced prompt message + // Simulate receiving enhanced prompt message with matching context window.dispatchEvent( new MessageEvent("message", { data: { type: "enhancedPrompt", text: "Enhanced test prompt", + context: "main", }, }), ) @@ -221,6 +223,90 @@ describe("ChatTextArea", () => { expect(mockExecCommand).toHaveBeenCalledWith("insertText", false, "Enhanced test prompt") }) + it("should ignore enhanced prompt with non-matching context", () => { + const setInputValue = vi.fn() + + // Mock document.execCommand + const mockExecCommand = vi.fn().mockReturnValue(true) + Object.defineProperty(document, "execCommand", { + value: mockExecCommand, + writable: true, + }) + + const { container } = render( + , + ) + + const textarea = container.querySelector("textarea")! + + // Mock textarea methods + const mockSelect = vi.fn() + const mockFocus = vi.fn() + textarea.select = mockSelect + textarea.focus = mockFocus + + // Simulate receiving enhanced prompt message with non-matching context (edit instead of main) + window.dispatchEvent( + new MessageEvent("message", { + data: { + type: "enhancedPrompt", + text: "Enhanced test prompt", + context: "edit", + }, + }), + ) + + // Verify native browser methods were NOT called + expect(mockFocus).not.toHaveBeenCalled() + expect(mockSelect).not.toHaveBeenCalled() + expect(mockExecCommand).not.toHaveBeenCalled() + expect(setInputValue).not.toHaveBeenCalled() + }) + + it("should handle enhanced prompt for edit mode", () => { + const setInputValue = vi.fn() + + // Mock document.execCommand + const mockExecCommand = vi.fn().mockReturnValue(true) + Object.defineProperty(document, "execCommand", { + value: mockExecCommand, + writable: true, + }) + + const { container } = render( + , + ) + + const textarea = container.querySelector("textarea")! + + // Mock textarea methods + const mockSelect = vi.fn() + const mockFocus = vi.fn() + textarea.select = mockSelect + textarea.focus = mockFocus + + // Simulate receiving enhanced prompt message with edit context + window.dispatchEvent( + new MessageEvent("message", { + data: { + type: "enhancedPrompt", + text: "Enhanced test prompt", + context: "edit", + }, + }), + ) + + // Verify native browser methods were called for edit mode + expect(mockFocus).toHaveBeenCalled() + expect(mockSelect).toHaveBeenCalled() + expect(mockExecCommand).toHaveBeenCalledWith("insertText", false, "Enhanced test prompt") + }) + it("should fallback to setInputValue when execCommand is not available", () => { const setInputValue = vi.fn() @@ -238,6 +324,7 @@ describe("ChatTextArea", () => { data: { type: "enhancedPrompt", text: "Enhanced test prompt", + context: "main", }, }), ) @@ -258,6 +345,7 @@ describe("ChatTextArea", () => { data: { type: "enhancedPrompt", text: "Enhanced test prompt", + context: "main", }, }), )