bc13450fad728a1a992e277311bbc53736da2bc0
Re-appliesbcb3d6d, which the tabs/panes revert (0a4ff54) took out as collateral: the fix lived in useChatWebSocket.ts, so reverting the panes work reverted it too. It was never panes-specific — the mechanism is React remounting a subtree, which happens on this screen with one conversation just as it did in a pane. The cleanup closed the socket while it was still CONNECTING, and the replacement was closed in turn, so the view churned and sat on Disconnected forever. The close is now deferred a tick and cancelled if the effect re-runs: a remount reclaims the live socket, a real unmount has nobody to cancel it. Diagnosed from the browser this time rather than guessed. A raw socket opened by hand from the console on the same origin, with the same token, reports RAW OPEN and stays open: new WebSocket(`wss://${location.host}/api/chat/ws?token=${localStorage.getItem('BEARER_TOKEN')}`) so transport, auth, the tailnet proxy and the server are all fine and the app was closing its own socket. Two earlier theories are dead and worth naming: the token resolution mismatch (52d5678) does not apply — the token IS in localStorage.BEARER_TOKEN where the old code looks — and StrictMode's double-invoke is not the trigger here, since pm2 runs `bun start` with NODE_ENV=production where React does not double-invoke. Some other remount is. Not verified in a browser yet: whether this alone clears Disconnected. If it does not, the remaining suspect is a continuous remount rather than a single one, which a WebSocket-constructor counter in the console will show as a rising count. Typecheck clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Description
No description provided
42 MiB
Languages
TypeScript
90.9%
Shell
4.7%
JavaScript
4.1%
CSS
0.2%
HTML
0.1%