import type { ChannelAccountRecord, ChannelCapabilityDescriptor, ChannelOperatorActionDescriptor, ChannelRuntimeObservation, ChannelSurface, ChannelToolDescriptor } from './types.js'; import { type TelegramIngressStatus } from './telegram/ingress.js'; import type { BuiltinChannelRuntimeDeps } from './builtin/shared.js'; import type { InboundMailHealthEntry } from '../email/inbound/health.js'; export declare class BuiltinChannelRuntime { private readonly deps; constructor(deps: BuiltinChannelRuntimeDeps); private telegramIngress; private telegramConfigUnsubscribes; private telegramRestartTimer; private inboundMailConfigUnsubscribes; private inboundMailRecheckTimer; private consumerConflictHandler; /** * Register who to tell when Telegram reports that ANOTHER process is already * long-polling this bot token (409, "terminated by other getUpdates"). * * Late-bound on purpose: the composition root builds this runtime before it * builds the thing that decides which node consumes, and the report has to * reach that decision rather than dead-ending in a log line. Set before * startIngress() so the very first poll's conflict is routed. */ setConsumerConflictHandler(handler: (detail: string) => void): void; /** * Arm the inbound paths that surfaces must actively establish. * * Registering an HTTP route is not enough for Telegram: it delivers nothing * until told a webhook URL exists or asked for updates. Called on daemon * start, after the HTTP listener is up so a registered webhook has somewhere * to land. */ /** * The Telegram bot this node can actually read, or null when it cannot read * any, no token resolves, or the host gave no cursor storage to persist a * poll offset in. * * Read before the node contests the Telegram surface in the LAN election: a * node that cannot serve it must never win it, because the loser of that * election stands down and Telegram then goes unread by anybody. */ resolveServableTelegramBotId(): Promise; private buildTelegramIngress; startIngress(): Promise; /** * Re-decide ingress when the surface is reconfigured, so edits apply without * a restart, the same live-reload path an external settings edit takes. * start() stops any running loop first, so a mode change swaps cleanly rather * than leaving both a poll loop and a webhook armed. */ private watchTelegramConfig; /** Tear the inbound paths down; the poll loop must not outlive the daemon. */ stopIngress(): Promise; /** * Current inbound Telegram state, including why it is inactive. * * Read by `observeSurfaceRuntime`, which is what every Telegram status * snapshot is now derived from. It previously had no caller at all while the * reported state was computed from the token's presence, so a bot whose poll * loop had stopped reported healthy, this function knew, and nobody asked. */ telegramIngressStatus(): TelegramIngressStatus | null; /** Arm inbound mail. Says so loudly when a mailbox is wanted and unwatched. */ startInboundMail(): Promise; /** * Re-probe the mailbox when a setting the running source re-reads changes. * * These five keys and no others, because the list is not "everything about * email", it is exactly what `source-factory.ts`'s connection port resolves * again inside every `open()`. A corrected host, port or account is therefore * picked up by the reconnect this triggers, and an owner is told within * seconds whether the correction worked instead of waiting out * `capabilityRecheckMinutes`. Both spellings of host and account are watched * because `readSurfaceEmailSettings` genuinely reads both, and subscribing to * the one the owner did not edit is a subscription that never fires. * * What is deliberately NOT here: `surfaces.email.inbound.accounts`, `.mode`, * `.source` and the mailbox. Those decide which source is BUILT and which * mailbox it opens, so acting on them means a restart, not a re-probe, * `recheckNow()` on a running source cannot change what that source is. Wiring * them here would look like they took effect and they would not, which is the * failure this whole item is about, reproduced one level up. * * The password is not here either, and cannot be: it lives in the secrets * store, which has no change subscription. The reconnect still re-resolves it, * so a rotated password is picked up by any recheck, it just does not cause * one. * * Coalesced the same way the Telegram watcher coalesces its restart: saving a * settings page writes several keys, and one re-probe per key would be four * reconnections against a mail server for one edit. */ private watchInboundMailConfig; /** * Stop reading the mailbox and release its connection. * * Awaited, and it must not resolve early: the ordered cluster handoff tells * the successor node to start only after this promise settles, and two nodes * holding one mailbox both announce every message. */ stopInboundMail(): Promise; /** * Email's health entry, read from the live supervisor. * * Deliberately not a `ChannelStatusSnapshot`: email is not a * `ManagedSurface`, and its state is what the watcher is DOING rather than * whether a credential happens to be present in the config file. */ inboundMailHealth(): InboundMailHealthEntry | null; /** * Which mailbox this node would watch, for the cluster election. * * Read before the node contests the surface: a node that watches no mailbox * must never win the election for one, because the loser stands down and the * mailbox then goes unread by anybody. */ inboundMailIdentity(): { readonly account: string; readonly mailbox: string; } | null; /** * What this node can see of a surface's live path. * * Public because health is worth asking about outside a status sweep, the * health watcher and the doctor report both want the same answer, and two * answers to one question is how the reported state drifted from reality in * the first place. */ observeSurfaceRuntime(surface: ChannelSurface): ChannelRuntimeObservation; registerPlugins(): void; private accountContext; buildAccount(surface: ChannelSurface): Promise; resolveAccount(surface: ChannelSurface, accountId: string): Promise; private contractContext; listCapabilities(surface: ChannelSurface): Promise; listOperatorActions(surface: ChannelSurface): ChannelOperatorActionDescriptor[]; listTools(surface: ChannelSurface): ChannelToolDescriptor[]; runTool(surface: ChannelSurface, toolId: string, input?: Record): Promise; runOperatorAction(surface: ChannelSurface, actionId: string, input?: Record): Promise; private buildContractHooks; private getSetupSchema; private listRepairActions; private getDoctorReport; private getLifecycleState; private resolveAllowlist; private editAllowlist; private buildProductHooks; private renderChannelEvent; private notifyApprovalViaRouter; private listAgentTools; private runAccountAction; private authorizeActorAction; private runProviderApi; private parseExplicitTarget; private inferTargetConversationKind; private resolveTarget; private resolveParentConversationCandidates; private resolveSessionTarget; private providerRuntimeStatus; private lookupDirectory; private lookupRouteDirectory; } //# sourceMappingURL=builtin-runtime.d.ts.map