diff --git a/src/workspaces/hooks/src/useChatWebSocket.ts b/src/workspaces/hooks/src/useChatWebSocket.ts index d2dc620a..ccbd1bc1 100644 --- a/src/workspaces/hooks/src/useChatWebSocket.ts +++ b/src/workspaces/hooks/src/useChatWebSocket.ts @@ -43,10 +43,19 @@ export const useChatWebSocket = ({ url, onMessage, onOpen }: UseChatWebSocketPar const socket = new WebSocket(url); socketRef.current = socket; + // Temporary, and deliberately loud. A pane connected and then sat silent, and reasoning from this + // hook's source three times running did not explain it — the console says a socket closed, never who + // closed it or whether the message went out. `window.__officerWs = false` turns it off. + const host = new URL(url).host; + const log = (what: string, extra?: unknown) => + (window as any).__officerWs !== false && console.log(`[ws ${host}] ${what}`, extra ?? ''); + log('creating'); + socket.addEventListener('open', () => { if (socketRef.current !== socket) return; setIsConnected(true); retryRef.current = 0; + log('OPEN'); // BEFORE onOpen, deliberately: onOpen sends the resume/attach handshake, and anything the user // typed while connecting belongs after that, not in front of it. const queued = pendingRef.current; @@ -57,6 +66,7 @@ export const useChatWebSocket = ({ url, onMessage, onOpen }: UseChatWebSocketPar socket.addEventListener('message', (ev) => { try { + log('recv', String(ev.data).slice(0, 120)); const data = JSON.parse(typeof ev.data === 'string' ? ev.data : new TextDecoder().decode(ev.data)); onMessageRef.current(data); } catch { @@ -64,7 +74,13 @@ export const useChatWebSocket = ({ url, onMessage, onOpen }: UseChatWebSocketPar } }); - socket.addEventListener('close', () => { + socket.addEventListener('close', (ev) => { + log('close', { + code: ev.code, + reason: ev.reason, + stale: socketRef.current !== socket, + tearingDown: isCleaningUpRef.current, + }); if (isCleaningUpRef.current) return; if (socketRef.current !== socket) return; setIsConnected(false); @@ -123,9 +139,12 @@ export const useChatWebSocket = ({ url, onMessage, onOpen }: UseChatWebSocketPar const socket = socketRef.current; const message = JSON.stringify(data); if (socket && socket.readyState === WebSocket.OPEN) { + if ((window as any).__officerWs !== false) console.log(`[ws ${new URL(url).host}] send`, message.slice(0, 120)); socket.send(message); return; } + if ((window as any).__officerWs !== false) + console.log(`[ws ${new URL(url).host}] QUEUED (socket ${socket?.readyState ?? 'none'})`, message.slice(0, 80)); // Not open yet, or reconnecting. Hold it rather than dropping it — see `pendingRef`. Bounded so a // socket that never comes back cannot grow this without limit; the oldest go first, because the // newest message is the one the user is still waiting on. diff --git a/src/workspaces/officerdev/src/MusicPlayer/MusicPlayerHost.tsx b/src/workspaces/officerdev/src/MusicPlayer/MusicPlayerHost.tsx index 5f042c9e..0c6a14cf 100644 --- a/src/workspaces/officerdev/src/MusicPlayer/MusicPlayerHost.tsx +++ b/src/workspaces/officerdev/src/MusicPlayer/MusicPlayerHost.tsx @@ -119,7 +119,16 @@ export const MusicPlayerHost = () => { // Restore the saved "currently playing" on first load — paused, at its position — so a reload/return // lands back on the track. Skipped when a queue already exists (an in-app nav kept player state). + // + // DISABLED on the web (Andre, 2026-08-10). The music sidecar is not running on every machine that + // serves this app, so every page load fired `/music/now-playing` and logged a 503 in the console of a + // browser that was not there for music at all. Restoring a paused track is a nicety; a permanent error + // on every load of every screen is not worth it. The player itself is untouched — play something and + // it works; it simply no longer asks what WAS playing. + const RESTORE_NOW_PLAYING = false; + useEffect(() => { + if (!RESTORE_NOW_PLAYING) return; if (restoredRef.current) return; restoredRef.current = true; if (queue.length) return;