/** * daemon/core-handlers.ts — Hub-level IPC handlers. * * Registers the core methods that any adapter or MCP client can call * on the hub socket. Transport-specific methods (send, contacts, history) * are NOT registered here — adapters handle those on their own sockets. * * Phase 1 methods: * register_adapter — adapter announces itself to the hub * unregister_adapter * adapter_list — list connected adapters * sessions — list hybrid sessions * switch — switch active session * end_session — end a hybrid session * broadcast_status — push status to all PAILot clients * voice_config — get/set TTS config * status — hub health/connection summary */ import type { IpcServer } from "../ipc/server.js"; import type { AdapterRegistry } from "./adapter-registry.js"; import type { APIBackend } from "../backend/api.js"; import type { HybridSessionManager } from "../core/hybrid.js"; import type { SessionSnapshot } from "../adapters/iterm/core.js"; import type { IpcRequest } from "../types/ipc.js"; /** * Best human-readable identity for whoever made this call, for the audit trail. * * Falls back through raw ids rather than to "unknown": an unattributed action * is the thing the audit log exists to prevent, so a GUID beats a blank. */ /** * The caller's iTerm2 session id, from whichever field carried it. * * Two fields hold the same fact and callers do not agree on which to fill, so * asking only one of them silently loses the identity. That is not theoretical: * a message between sessions arrived labelled * `[Session:w11t0p0:066504E1-…]` because `itermSessionId` was empty and the * resolution never ran — the raw composite id went out where the sender's NAME * belongs. The `w11t0p0:` prefix is the proof, since the normalisation below * strips it and so could never have printed it. * * That label is not cosmetic. It is the receiver's only evidence of who sent a * message, and it is the address they are told to reply to — and a reply tool * that takes a name or an index cannot use a GUID. A relay of the operator's * own instruction arrived unattributable and unanswerable. * * Both forms are accepted and normalised the same way: iTerm2 reports * `wtp:`, and only the uuid identifies the session * across a move between windows. */ export declare function callerItermId(req: IpcRequest): string | undefined; /** * What send_to_session types and whether it deposits to the mailbox, for a * given noReply mode. * * noReply is for automated beats that expect no answer: nothing is queued * (a beat has no value later, and the drain-mailbox reminder would repeat a * demand to reply that the sender can never see), and no `[Session:...]` * prefix is typed (the prefix tells the receiving Claude to route a reply * back to a sender, but a beat's label is not a registered session). * * When a message IS deposited, only a one-line pointer is typed — never the * full body. Typing the full body and pressing Enter submits it as an * ordinary prompt, which fires the target's own `hooks/drain-mailbox.mjs` * UserPromptSubmit hook on that same submission. That hook drains the very * message this call just deposited and re-injects it as a system-reminder — * so the full content showed up twice in one turn: once as the typed prompt, * once again from the mailbox. Reproduced live 2026-09-23 on both an idle and * a busy target — not a busy-only race. A short pointer and the deposited * body are different strings, so the hook's drain is the only place the full * content appears, and a multi-line body is never typed into a live pane at * all — the failure mode where only the last line survived typing cannot * recur here because there is nothing but one line to type. */ export declare function sendToSessionDelivery(message: string, senderLabel: string, noReply: boolean): { typed: string; deposit: boolean; }; /** * The sender's identity for the mailbox "from" field and the `[Session:X]` * prefix — bare, unlike callerLabel()'s `session:`-prefixed audit actor. * * paiName first, then the session's own stable id — never the raw iTerm * name/title, which is the terminal's OWN dynamic display text (a spinner * glyph plus tab title for a busy Claude Code session) and not an identity. * A sender not found in the live snapshot (worker child process, or a bare * CLI call with no pane at all) falls back to whatever id it claimed — for a * worker that id is a fabricated, non-live marker (see ipc/client.ts), so it * naturally fails to match any session and a reply to it is refused rather * than silently reaching the wrong pane. */ export declare function resolveSenderLabel(req: IpcRequest, snapshots: SessionSnapshot[]): string; export declare function registerCoreHandlers(server: IpcServer, registry: AdapterRegistry, _apiBackend: APIBackend, manager: HybridSessionManager): void; //# sourceMappingURL=core-handlers.d.ts.map