Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit 39360eb

Browse files
committed
fix: queue messages during command_output state (Issue #10675)
When a command is running (command_output state), user messages were being sent as askResponse and getting lost/ignored. This is because during command_output: sendingDisabled=false, isStreaming=false, and messageQueue.length=0, so messages bypassed the queue. The fix adds clineAsk === "command_output" to the queue condition in handleSendMessage. Now messages sent during command execution are queued and will be processed once the command completes, fixing the disappearing message bug. Added test case to verify the fix.
1 parent b514996 commit 39360eb

2 files changed

Lines changed: 98 additions & 2 deletions

File tree

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
585585
// - Task is busy (sendingDisabled)
586586
// - API request in progress (isStreaming)
587587
// - Queue has items (preserve message order during drain)
588-
if (sendingDisabled || isStreaming || messageQueue.length > 0) {
588+
// - Command is running (message should be queued until command completes) (#10675)
589+
if (sendingDisabled || isStreaming || messageQueue.length > 0 || clineAsk === "command_output") {
589590
try {
590591
console.log("queueMessage", text, images)
591592
vscode.postMessage({ type: "queueMessage", text, images })
@@ -641,7 +642,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
641642
handleChatReset()
642643
}
643644
},
644-
[handleChatReset, markFollowUpAsAnswered, sendingDisabled, isStreaming, messageQueue.length], // messagesRef and clineAskRef are stable
645+
[handleChatReset, markFollowUpAsAnswered, sendingDisabled, isStreaming, messageQueue.length, clineAsk], // messagesRef and clineAskRef are stable
645646
)
646647

647648
const handleSetChatBoxMessage = useCallback(

webview-ui/src/components/chat/__tests__/ChatView.spec.tsx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,101 @@ describe("ChatView - Message Queueing Tests", () => {
10811081
}),
10821082
)
10831083
})
1084+
1085+
it("queues messages when command is running (command_output state) - Issue #10675", async () => {
1086+
const { getByTestId, getByText } = renderChatView()
1087+
1088+
// First hydrate state with initial task
1089+
mockPostMessage({
1090+
clineMessages: [
1091+
{
1092+
type: "say",
1093+
say: "task",
1094+
ts: Date.now() - 2000,
1095+
text: "Initial task",
1096+
},
1097+
],
1098+
})
1099+
1100+
// Wait for component to render
1101+
await waitFor(() => {
1102+
expect(getByTestId("chat-textarea")).toBeInTheDocument()
1103+
})
1104+
1105+
// Clear any initial calls
1106+
vi.mocked(vscode.postMessage).mockClear()
1107+
1108+
// Add command_output ask (command is running, waiting for user input)
1109+
// During command_output: sendingDisabled=false, enableButtons=true, isStreaming=false
1110+
// Without the fix, messages would be sent directly (not queued) and could get lost
1111+
mockPostMessage({
1112+
clineMessages: [
1113+
{
1114+
type: "say",
1115+
say: "task",
1116+
ts: Date.now() - 2000,
1117+
text: "Initial task",
1118+
},
1119+
{
1120+
type: "ask",
1121+
ask: "command_output",
1122+
ts: Date.now(),
1123+
text: "",
1124+
partial: false, // Not partial - command is running
1125+
},
1126+
],
1127+
})
1128+
1129+
// Wait for the command_output state to be fully processed
1130+
// The button text "proceedWhileRunning.title" indicates clineAsk is set to "command_output"
1131+
// AND the button should NOT be disabled (enableButtons = true)
1132+
await waitFor(
1133+
() => {
1134+
const proceedButton = getByText("chat:proceedWhileRunning.title")
1135+
// Button should be enabled (not disabled) for command_output state
1136+
expect(proceedButton).not.toBeDisabled()
1137+
},
1138+
{ timeout: 2000 },
1139+
)
1140+
1141+
// Allow extra time for React to recreate the handleSendMessage callback with updated clineAsk
1142+
await act(async () => {
1143+
await new Promise((resolve) => setTimeout(resolve, 100))
1144+
})
1145+
1146+
// Clear message calls before simulating user input
1147+
vi.mocked(vscode.postMessage).mockClear()
1148+
1149+
// Simulate user sending a message while command is running
1150+
const chatTextArea = getByTestId("chat-textarea")
1151+
const input = chatTextArea.querySelector("input")! as HTMLInputElement
1152+
1153+
await act(async () => {
1154+
// Use fireEvent to properly trigger React's onChange handler
1155+
fireEvent.change(input, { target: { value: "user feedback during command execution" } })
1156+
1157+
// Simulate pressing Enter to send
1158+
fireEvent.keyDown(input, { key: "Enter", code: "Enter" })
1159+
})
1160+
1161+
// Verify that the message was queued, not sent as direct askResponse
1162+
// This is the fix for Issue #10675 - messages should be queued during command_output
1163+
await waitFor(() => {
1164+
expect(vscode.postMessage).toHaveBeenCalledWith({
1165+
type: "queueMessage",
1166+
text: "user feedback during command execution",
1167+
images: [],
1168+
})
1169+
})
1170+
1171+
// Verify it was NOT sent as a direct askResponse (which would cause the message to "disappear")
1172+
expect(vscode.postMessage).not.toHaveBeenCalledWith(
1173+
expect.objectContaining({
1174+
type: "askResponse",
1175+
askResponse: "messageResponse",
1176+
}),
1177+
)
1178+
})
10841179
})
10851180

10861181
describe("ChatView - Context Condensing Indicator Tests", () => {

0 commit comments

Comments
 (0)