fix: queue messages during command execution instead of losing them (#11140)

This commit is contained in:
Matt Rubens 2026-01-31 09:47:28 -08:00 • committed by GitHub
parent 8cf82cd3a9
commit ede1d29299
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 81 additions and 3 deletions

View file

@ -612,7 +612,13 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
// - Task is busy (sendingDisabled)
// - API request in progress (isStreaming)
// - Queue has items (preserve message order during drain)
if (sendingDisabled || isStreaming || messageQueue.length > 0) {
// - Command is running (command_output) - user's message should be queued for AI, not sent to terminal
if (
sendingDisabled ||
isStreaming ||
messageQueue.length > 0 ||
clineAskRef.current === "command_output"
) {
try {
console.log("queueMessage", text, images)
vscode.postMessage({ type: "queueMessage", text, images })
@ -645,7 +651,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
case "tool":
case "browser_action_launch":
case "command": // User can provide feedback to a tool or command use.
case "command_output": // User can send input to command stdin.
case "use_mcp_server":
case "completion_result": // If this happens then the user has feedback for the completion result.
case "resume_task":
@ -1496,9 +1501,20 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
useImperativeHandle(ref, () => ({
acceptInput: () => {
const hasInput = inputValue.trim() || selectedImages.length > 0
// Special case: during command_output, queue the message instead of
// triggering the primary button action (which would lose the message)
if (clineAskRef.current === "command_output" && hasInput) {
vscode.postMessage({ type: "queueMessage", text: inputValue.trim(), images: selectedImages })
setInputValue("")
setSelectedImages([])
return
}
if (enableButtons && primaryButtonText) {
handlePrimaryButtonClick(inputValue, selectedImages)
} else if (!sendingDisabled && !isProfileDisabled && (inputValue.trim() || selectedImages.length > 0)) {
} else if (!sendingDisabled && !isProfileDisabled && hasInput) {
handleSendMessage(inputValue, selectedImages)
}
},

View file

@ -1081,6 +1081,68 @@ describe("ChatView - Message Queueing Tests", () => {
}),
)
})
it("queues messages during command_output state instead of losing them", async () => {
const { getByTestId } = renderChatView()
// Hydrate state with command_output ask (Proceed While Running state)
mockPostMessage({
clineMessages: [
{
type: "say",
say: "task",
ts: Date.now() - 2000,
text: "Initial task",
},
{
type: "ask",
ask: "command_output",
ts: Date.now(),
text: "",
partial: false, // Non-partial so buttons are enabled
},
],
})
// Wait for state to be updated - need to allow time for React effects to propagate
// (clineAsk state update -> clineAskRef.current update)
await waitFor(() => {
expect(getByTestId("chat-textarea")).toBeInTheDocument()
})
// Allow React effects to complete (clineAsk -> clineAskRef sync)
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 50))
})
// Clear message calls before simulating user input
vi.mocked(vscode.postMessage).mockClear()
// Simulate user typing and sending a message during command execution
const chatTextArea = getByTestId("chat-textarea")
const input = chatTextArea.querySelector("input")! as HTMLInputElement
await act(async () => {
fireEvent.change(input, { target: { value: "message during command execution" } })
fireEvent.keyDown(input, { key: "Enter", code: "Enter" })
})
// Verify that the message was queued (not lost via terminalOperation)
await waitFor(() => {
expect(vscode.postMessage).toHaveBeenCalledWith({
type: "queueMessage",
text: "message during command execution",
images: [],
})
})
// Verify it was NOT sent as terminalOperation (which would lose the message)
expect(vscode.postMessage).not.toHaveBeenCalledWith(
expect.objectContaining({
type: "terminalOperation",
}),
)
})
})
describe("ChatView - Context Condensing Indicator Tests", () => {