fix(canvas): keep a new card's first message and its caret
A conversation card with no row yet streams under a virtual runtime id derived from its connection key. The first send mints the row and swaps the card, so the message just sent, the reply already answering it, and the `awaiting_persist` that protects both from the next detail fetch were all left behind in the draft's session while the arriving card mounted on an empty one. The live sink follows the inherited connection key, which made that read as a rendering fault rather than a lost message: the agent's answer streamed in and settled normally, under a transcript that said there were no messages yet, with the user's own message the one thing missing. The arriving card now adopts that session in a layout effect, which is the only point where the draft is provably gone — ReactFlow applies a changed `nodes` prop from a passive effect, so the draft card outlives the render that drops it from the board, and moving the session out any earlier empties a card still on screen. A send rejected after the hand-off now rolls back against both ids instead of stranding the failed message on the card that took over. The draft node also carried no `dragHandle`, so every mousedown anywhere in it passed d3-drag's filter, and d3 answers by preventing `selectstart` on the window for the life of the gesture — the same event browsers gate caret placement on. Clicking into the composer focused the textarea without moving the cursor, and no text in the card could be selected. It now drags by its title bar, like the expanded card.
X
xintaofei committed
95456b47ec8c89d3781db76f7fcdb4b055eb38d1
Parent: 86f57fc