/** * Core value and message types for the channels layer — the bridge between * external chat platforms (Teams, Mattermost, Slack) and workspace sessions. * * Everything here is transport-neutral: no platform SDK types leak in, and * platform-native payloads only appear as opaque `raw`/`messageRef` slots. */ import type { MessageV2 } from "@skaile/workspaces/types"; /** Chat platforms the channels layer can bridge. */ export declare const CHANNEL_PLATFORMS: readonly ["msteams", "mattermost", "slack"]; /** One of the supported chat platforms (`"msteams" | "mattermost" | "slack"`). */ export type ChannelPlatform = (typeof CHANNEL_PLATFORMS)[number]; /** * Canonical identifier of a place in a chat app: `":"`, * optionally `"…/"`. Never a session id — the Binding is the only * join between the two (spec §5.1). */ export type ConversationKey = string; /** * Builds a {@link ConversationKey} from its parts. * * Invariant: `parseConversationKey(makeConversationKey(p, c, t))` round-trips * exactly, provided `threadRootId` itself contains no `/`. */ export declare function makeConversationKey(platform: ChannelPlatform, conversationId: string, threadRootId?: string): ConversationKey; /** * Splits a {@link ConversationKey} into platform, conversation id, and optional * thread root. Throws on an unknown platform prefix. * * Gotcha: the thread separator is the LAST `/` — conversation ids may * themselves contain slashes (e.g. Mattermost `team/channel`). */ export declare function parseConversationKey(key: ConversationKey): { platform: ChannelPlatform; conversationId: string; threadRootId?: string; }; /** A person (or bot) as the chat platform sees them — pre-IdentityPort resolution. */ export type ChannelActor = { platform: ChannelPlatform; /** Platform-native user id (Teams AAD object id, Slack user id, MM user id). */ externalId: string; displayName: string; /** Teams tenant / MM team / Slack workspace, when known. */ tenantId?: string; /** Identity hint for IdentityPort mapping, when the platform exposes it. */ email?: string; isBot?: boolean; }; /** Reference to a posted platform message. `raw` carries platform-native extras (e.g. Teams serviceUrl). */ export type MessageRef = { platform: ChannelPlatform; conversationKey: ConversationKey; /** Platform-native message id (Teams activity id, Slack ts, MM post id). */ messageId: string; raw?: unknown; }; /** Where to post: a conversation, optionally threaded under an existing message. */ export type ReplyTarget = { conversationKey: ConversationKey; /** Platform-native thread anchor; adapters thread under it where supported. */ threadRef?: MessageRef; }; /** * Declarative surface description consumed by the engine + egress pipeline. * Finalized per spec §13.1 by this plan — the conformance kit asserts adapters * honor `maxMessageLength` and `ackDeadlineMs`. */ export type SurfaceCapabilities = { canEditMessages: boolean; canDeleteMessages: boolean; supportsThreads: boolean; supportsCards: boolean; supportsTyping: boolean; supportsEphemeral: boolean; supportsReactions: boolean; /** Hard cap on a single posted message's text length; egress chunks at this. */ maxMessageLength: number; /** IngressSink.onMessage must resolve within this (Slack ~3000, Teams 15000). */ ackDeadlineMs: number; /** Minimum interval between successive edits of one message (egress throttle). */ editThrottleMs: number; /** Outbound text dialect the adapter expects from the format layer. */ textFormat: "markdown" | "mrkdwn" | "adaptive-card"; }; /** Per-binding egress policy (spec §7.2.4). */ export type MirrorMode = "agent-only" | "full" | "chat-initiated"; /** * The conversationKey ↔ sessionId join, persisted by the host's BindingStore. * Deliberately not 1:1 (spec §5.1). Session ids never leak into chat payloads. */ export type Binding = { conversationKey: ConversationKey; sessionId: string; platform: ChannelPlatform; tenantId?: string; mirrorMode: MirrorMode; enabled: boolean; /** Host user id that created the binding (audit; authority stays with the host). */ createdBy: string; /** ISO 8601. */ createdAt: string; }; /** * The one genuinely new meta type (spec §5) — rides on MessageMeta's extension * slot; hosts persist it untouched via the round-trip preservation contract. */ export type ChannelMetaExtensions = { channel?: { platform: ChannelPlatform; conversationKey: ConversationKey; /** Platform event id — the inbound dedupe key. */ eventId: string; tenantId?: string; /** Pre-IdentityPort resolution attribution. */ actor?: { externalId: string; displayName: string; }; /** Opaque platform-native ref of the source message. */ messageRef?: unknown; }; }; /** A workspace message envelope whose meta block carries {@link ChannelMetaExtensions}. */ export type ChannelMessage = MessageV2; /** What the engine hands an adapter to post. Format conversion is the adapter's job. */ export type OutboundMessage = { /** Markdown source; adapters convert via the format layer per their textFormat. */ markdown: string; /** Rendering intent. Default "text". */ kind?: "text" | "question" | "status" | "error"; /** Options rendered as buttons where supportsCards; appended as a list otherwise. */ options?: string[]; }; /** Fast-ack result of IngressSink.onMessage (spec §7.1.3). */ export type IngressAck = { status: "accepted" | "duplicate" | "ignored" | "rejected"; reason?: string; }; /** Inbound reaction event. Engine behavior deferred this milestone (Decision 7). */ export type InboundReaction = { conversationKey: ConversationKey; messageRef: MessageRef; emoji: string; actor: ChannelActor; action: "added" | "removed"; eventId: string; }; /** Non-message conversation lifecycle signals adapters may surface. */ export type ConversationEvent = { conversationKey: ConversationKey; kind: "member_joined" | "member_left" | "conversation_renamed" | "conversation_deleted"; eventId: string; raw?: unknown; }; /** Query for ChannelAdapter.lookupActor — backs the mentions-as-a-tool helper. */ export type ActorQuery = { externalId?: string; email?: string; /** Display-name substring match, platform semantics. */ name?: string; }; /** Result of verifyConversation — actionable problems, forge-tui preflight pattern. */ export type ConversationHealth = { ok: boolean; /** Human-actionable problem descriptions ("bot is not a member of #x — invite it"). */ problems: string[]; }; //# sourceMappingURL=types.d.ts.map