v0.49.4 — Cancel stream cleanup guaranteed
Fixes the "Cancelling..." status text lingering after a stream cancellation.
What was broken (issue #299)
cancelStream() set the composer status to "Cancelling..." and then relied on the SSE cancel event handler to clear it. If the SSE connection was already closed when cancel fired, the event never arrived — leaving "Cancelling...", a stuck spinner, and an active stream ID indefinitely. A 3-second setTimeout band-aid was in place.
What changed
cancelStream() now clears all busy state unconditionally after the cancel API request completes, regardless of SSE connection state:
S.activeStreamIdset tonullsetBusy(false)calledsetStatus('')called- Cancel button hidden
The SSE cancel handler in messages.js still fires when the connection is alive and performs additional cleanup (adds "Task cancelled." message, clears live tool cards). All state-clearing operations are idempotent.
Full changelog: CHANGELOG.md