import { type SessionAttachment } from "../router"; import { ConversationStore } from "./conversation-store"; import { type SlackConversation } from "./slack-conversation"; export type { SlackThreadBindingErrorCode } from "./slack-thread-binding"; export { SlackThreadBindingError } from "./slack-thread-binding"; export declare class SlackEndpointBindingError extends Error { constructor(message?: string); } import type { SlackProvider, SlackSocketEnvelope } from "./slack-provider"; export interface SlackBindingAuthority { sessionId: string; endpointGeneration: number; attachmentAuthorityId?: string; } export interface SlackNotificationDaemonOptions { agentDir: string; repo: string; teamId: string; channelId: string; provider: SlackProvider; botUserId?: string; /** Fail-closed authorization for the paired Slack principal. */ authorizeActor?: (actorId: string) => boolean | Promise; store?: ConversationStore; now?: () => number; randomId?: () => string; /** Stable identity for the process attempting durable provider publication. */ publicationOwnerId?: string; publicationLeaseMs?: number; resolveAttachment: (sessionId: string) => Promise; /** Exact Router proof for adopting an existing root. */ resolveBindingAuthority?: (sessionId: string) => Promise; onCommand?: (sessionId: string, content: string, attachment: SessionAttachment, idempotencyKey: string) => Promise; } /** * Slack Socket Mode notification daemon. Accepted inbound SDK effects are * persisted before acknowledgement, including their replay payload and captured * endpoint generation; endpoint credentials and Socket Mode cursors are never * written to disk. */ export declare class SlackNotificationDaemon { #private; private readonly options; readonly store: ConversationStore; constructor(options: SlackNotificationDaemonOptions); restartBlocked(): boolean; start(): Promise; stop(): Promise; /** Accepted inbound effects are durably claimed before their Socket Mode ACK. */ handleEnvelope(envelope: SlackSocketEnvelope): Promise; postRoot(sessionId: string, body: string, endpointGeneration?: number): Promise; /** * Adopt an operator-supplied root in the configured workspace and channel * without publishing a replacement root. * * The root is verified against the provider before any lock is taken, and the * claim re-proves session authority inside the store lock. When the caller is * the daemon command channel it also supplies `commitAuthority`, which * re-proves the exact daemon owner tuple and takes terminal request * authority in the same fence, so an ownership change or a cancellation * between dispatch and commit leaves the store untouched. The claim targets * the same session key stock publication uses, so a concurrent first * notification observes the adopted root instead of posting a second one. */ bindExistingRoot(sessionId: string, rootTs: string, commitAuthority?: () => Promise): Promise; /** Deliver a notification into the mapped root thread, creating that root once. */ notify(sessionId: string, body: string, actionId?: string, endpointGeneration?: number, publicationId?: string): Promise; /** Posts a safe command outcome to the active mapped root thread. */ postCommandResult(sessionId: string, content: string): Promise; resolveAction(sessionId: string, actionId: string): Promise; close(sessionId: string, marker?: string, endpointGeneration?: number): Promise; recoverCleanup(sessionId: string, endpointGeneration: number): Promise; retireAttachment(sessionId: string, endpointGeneration: number): Promise; resume(sessionId: string, body: string, endpointGeneration?: number, publicationId?: string): Promise; findSession(sessionId: string, includeInactive: boolean): Promise<{ key: string; record: SlackConversation; } | undefined>; }