From 132fde192ee57b315fbe02b88d5319874e18f21c Mon Sep 17 00:00:00 2001 From: Ashlee Radka Date: Tue, 24 Feb 2026 17:20:39 -0500 Subject: [PATCH] fix: broadcast pairing approval to HTTP/SSE clients When the macOS app uses HTTP transport (localHttpEnabled flag), it connects via SSE instead of the Unix domain socket. Pairing approval requests were only broadcast to IPC socket clients, so HTTP-connected clients never received them. Two changes: 1. RuntimeHttpServer now also publishes pairing events to the AssistantEventHub with assistantId 'self' so SSE subscribers receive them. 2. AssistantEventHub allows events without sessionId (system events) to pass through to all subscribers regardless of their sessionId filter. Co-Authored-By: Claude Opus 4.6 --- assistant/src/runtime/assistant-event-hub.ts | 4 +++- assistant/src/runtime/http-server.ts | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/assistant/src/runtime/assistant-event-hub.ts b/assistant/src/runtime/assistant-event-hub.ts index 5a8c189379d..c6beb31fc10 100644 --- a/assistant/src/runtime/assistant-event-hub.ts +++ b/assistant/src/runtime/assistant-event-hub.ts @@ -123,7 +123,9 @@ export class AssistantEventHub { for (const entry of snapshot) { if (!entry.active) continue; if (entry.filter.assistantId !== event.assistantId) continue; - if (entry.filter.sessionId != null && entry.filter.sessionId !== event.sessionId) continue; + // System events (no sessionId) match all subscribers; scoped events + // must match the subscriber's sessionId filter when present. + if (event.sessionId != null && entry.filter.sessionId != null && entry.filter.sessionId !== event.sessionId) continue; try { await entry.callback(event); } catch (err) { diff --git a/assistant/src/runtime/http-server.ts b/assistant/src/runtime/http-server.ts index 85aa775c219..be689bf8893 100644 --- a/assistant/src/runtime/http-server.ts +++ b/assistant/src/runtime/http-server.ts @@ -78,6 +78,8 @@ import { handleSubscribeAssistantEvents } from './routes/events-routes.js'; import { consumeCallback, consumeCallbackError } from '../security/oauth-callback-registry.js'; import { PairingStore } from '../daemon/pairing-store.js'; import type { ServerMessage } from '../daemon/ipc-contract.js'; +import { assistantEventHub } from './assistant-event-hub.js'; +import { buildAssistantEvent } from './assistant-event.js'; // Middleware import { @@ -183,10 +185,19 @@ export class RuntimeHttpServer { } private get pairingContext(): PairingHandlerContext { + const ipcBroadcast = this.pairingBroadcast; return { pairingStore: this.pairingStore, bearerToken: this.bearerToken, - pairingBroadcast: this.pairingBroadcast, + pairingBroadcast: ipcBroadcast + ? (msg) => { + // Broadcast to IPC socket clients (local Unix socket) + ipcBroadcast(msg); + // Also publish to the event hub so HTTP/SSE clients (e.g. macOS + // app with localHttpEnabled) receive pairing approval requests. + void assistantEventHub.publish(buildAssistantEvent('self', msg)); + } + : undefined, }; }