/** * adapters/pailot/gateway.ts — Gateway for PAILot app connections (MQTT + legacy WS). * * Runs alongside any transport's watcher (Whazaa, Telex, etc.). When the * PAILot iOS app connects via MQTT, incoming messages are routed through * the same handleMessage() path as the transport's native messages. Outbound * messages from Claude are broadcast to all connected clients. * * The gateway also supports structured commands (sessions, screenshot, * navigation keys) so the app can interact with the watcher without * going through text-based slash commands. * * Messages are persisted to disk via message-queue.ts so they survive daemon * restarts. The app requests catch_up with its lastSeq on reconnect. */ /** * Make a catch-up batch a phone can actually receive. * * THE FAILURE THIS PREVENTS IS SELF-SUSTAINING, which is what makes it worth a * shared function rather than a check at each call site. The client asks from * its last sequence; if the reply is too big to take, the socket dies partway; * the client reconnects and asks from the SAME sequence, because it never * finished; and it is handed the identical payload again. Observed as a loop of * connect, 172 KB reply, ECONNRESET three seconds later, repeat — for as long * as the phone was on the network. * * Both transports go through here. The cap used to live only on the WebSocket * path, which was the one being retired; the MQTT path that replaced it had * none, so the protection stayed with the transport nobody used any more. A * limit that lives on one of two paths is a limit that will be discovered by * the path it is missing from. * * Trimming takes the newest first: if not everything fits, the recent end is * what keeps a conversation coherent. */ export declare function buildCatchUp(missed: Array<{ payload: Record; }>): { messages: Record[]; bytes: number; withheld: number; lightened: number; }; /** * Provide the screenshot handler so ws-gateway can trigger screenshots * for navigation commands without a circular import. */ export declare function setScreenshotHandler(handler: (source?: "whatsapp" | "pailot", sessionId?: string) => Promise): void; /** Set the voice batch session from external callers (MQTT path). */ export declare function setVoiceBatchSession(sessionId: string): void; export declare function transcribeAndRoute(audioBase64: string, onMessage: (text: string, timestamp: number) => void | Promise, messageId?: string): Promise; /** * Start the WebSocket gateway. * @param onMessage — the same handleMessage(text, timestamp) used by the transport */ export declare function startWsGateway(onMessage: (text: string, timestamp: number) => void | Promise): void; export declare function broadcastText(text: string, sessionId?: string, direct?: boolean): void; /** * Broadcast a voice note to all connected PAILot clients. * Converts OGG Opus to M4A (AAC) since iOS can't play OGG natively. * @param sessionId — iTerm session ID of the originating Claude session */ export declare function broadcastVoice(audioBuffer: Buffer, transcript: string, sessionId?: string, direct?: boolean, chunkMeta?: { groupId: string; chunkIndex: number; totalChunks: number; }): Promise; /** * Broadcast a screenshot/image to all connected PAILot clients. * @param sessionId — iTerm session ID of the originating Claude session */ export declare function broadcastImage(imageBuffer: Buffer, caption?: string, sessionId?: string, direct?: boolean, mimeType?: string): void; /** * Broadcast a status change to all connected PAILot clients. * Used to signal compaction, reconnection, etc. */ export declare function broadcastStatus(status: string): void; /** * Returns true if any PAILot clients are connected, by EITHER transport. * * Counting only the WebSocket set was right when that was the only way in, and * became wrong without changing: the app moved to MQTT, so a phone sitting * connected registers in `connectedClients` over there and not in `clients` * here. The failure mode is quiet in the worst way — a caller asking "is anyone * listening" is told no, and correctly declines to send, so what goes missing is * a message nobody ever sees not being sent. * * App clients only. The hub holds a loopback client on its own broker, so the * raw MQTT count is never zero and using it here would answer yes forever — * turning a gate into a piece of scenery. */ export declare function hasPailotClients(): boolean; /** * Stop the WebSocket gateway. */ export declare function stopWsGateway(): void; /** * Handle a command from MQTT (no WebSocket needed). * Replicates the WS command dispatcher for MQTT-only clients. */ export declare function handleMqttCommand(command: string, args?: Record): void; //# sourceMappingURL=gateway.d.ts.map