import type { MessageRef, MessageContent, ActionElement, ModalDefinition, ModalFieldValue } from '../types.js'; export declare const PROTOCOL_VERSION = 1; export declare const HANDSHAKE_HELLO = "handshake.hello"; export declare const HANDSHAKE_ACK = "handshake.ack"; export declare const SESSION_SWITCH = "session.switch"; export declare const SESSION_SWITCHED = "session.switched"; export declare const PING = "ping"; export declare const PONG = "pong"; export declare const CLOSE = "close"; export declare const CHAT_POST = "chat.post"; export declare const CHAT_UPDATE = "chat.update"; export declare const CHAT_DELETE = "chat.delete"; export declare const CHAT_MARK_QUEUED = "chat.markQueued"; export declare const MSG_USER = "msg.user"; export declare const MSG_EDIT = "msg.edit"; export declare const STREAM_TEXT = "stream.text"; export declare const STREAM_MUTABLE_OPEN = "stream.mutableOpen"; export declare const STREAM_MUTABLE_UPDATE = "stream.mutableUpdate"; export declare const STREAM_FLUSH = "stream.flush"; export declare const INTERACTIVE_POST = "interactive.post"; export declare const MODAL_OPEN = "modal.open"; export declare const MODAL_ACK = "modal.ack"; export declare const ACTION_CLICK = "action.click"; export declare const MODAL_SUBMIT = "modal.submit"; export declare const TRANSCRIPT_REPLAY = "transcript.replay"; export declare const NOTIFICATION = "notification"; export declare const UI_QUERY = "ui.query"; export declare const UI_QUERY_RESULT = "ui.queryResult"; export declare const UI_MUTATE = "ui.mutate"; export declare const UI_MUTATE_RESULT = "ui.mutateResult"; export declare const UI_SUBSCRIBE = "ui.subscribe"; export declare const UI_EVENT = "ui.event"; export declare const UI_UNSUBSCRIBE = "ui.unsubscribe"; export declare const ERROR = "error"; /** @direction client→server (first frame after WS open) */ export interface HandshakeHello { type: typeof HANDSHAKE_HELLO; protocolVersion: number; clientName: string; clientVersion: string; resume?: { sessionId: string; } | null; project?: string | null; } /** @direction server→client (response to handshake.hello) */ export interface HandshakeAck { type: typeof HANDSHAKE_ACK; protocolVersion: number; serverVersion: string; conduitId: string; defaultProjectId: string; seq: number; } /** @direction client→server (switch active session — fresh or attach existing) */ export interface SessionSwitch { type: typeof SESSION_SWITCH; id: string; projectId: string; /** null = create fresh session in projectId */ sessionId?: string | null; } /** @direction server→client (result of session.switch — id echoes request) */ export interface SessionSwitched { type: typeof SESSION_SWITCHED; id: string; projectId: string; sessionId: string; sessionName: string; isFresh: boolean; seq: number; } /** @direction both (keepalive) */ export interface Ping { type: typeof PING; ts: number; } /** @direction both (keepalive — no seq; out-of-band) */ export interface Pong { type: typeof PONG; ts: number; } /** @direction client→server (explicit close; also fires implicitly on WS close) */ export interface Close { type: typeof CLOSE; reason?: string; } /** @direction server→client (post a new message into the conduit's transcript) */ export interface ChatPost { type: typeof CHAT_POST; ref: MessageRef; content: MessageContent; threadAnchorId?: string | null; seq: number; } /** @direction server→client (update an existing message by ref) */ export interface ChatUpdate { type: typeof CHAT_UPDATE; ref: MessageRef; content: MessageContent; seq: number; } /** @direction server→client (delete a message by ref) */ export interface ChatDelete { type: typeof CHAT_DELETE; ref: MessageRef; seq: number; } /** @direction server→client (inline backpressure marker — replaces Slack's hourglass) */ export interface ChatMarkQueued { type: typeof CHAT_MARK_QUEUED; ref: MessageRef; seq: number; } /** @direction client→server (user submits a message in the active session) */ export interface MsgUser { type: typeof MSG_USER; id: string; text: string; threadAnchorId?: string | null; attachments?: Array<{ path: string; mimeType: string; name: string; }>; } /** @direction client→server (rare: user edits a previously sent message) */ export interface MsgEdit { type: typeof MSG_EDIT; id: string; ref: MessageRef; newText: string; } /** @direction server→client (commit a text segment to a stream) */ export interface StreamText { type: typeof STREAM_TEXT; streamId: string; text: string; seq: number; } /** @direction server→client (open a fresh mutable region inside a stream) */ export interface StreamMutableOpen { type: typeof STREAM_MUTABLE_OPEN; streamId: string; regionId: string; text: string; seq: number; } /** @direction server→client (replace a mutable region's content) */ export interface StreamMutableUpdate { type: typeof STREAM_MUTABLE_UPDATE; streamId: string; regionId: string; text: string; seq: number; } /** @direction server→client (optional flush marker — used by tests for ordering) */ export interface StreamFlush { type: typeof STREAM_FLUSH; streamId: string; seq: number; } /** @direction server→client (post a message with action buttons) */ export interface InteractivePost { type: typeof INTERACTIVE_POST; ref: MessageRef; content: MessageContent; actions: ActionElement[]; threadAnchorId?: string | null; seq: number; } /** @direction server→client (ask client to open a modal — AskUserQuestion / plan feedback) */ export interface ModalOpen { type: typeof MODAL_OPEN; triggerId: string; modal: ModalDefinition; seq: number; } /** @direction server→client (ack a modal submission; id echoes modal.submit) */ export interface ModalAck { type: typeof MODAL_ACK; id: string; errors?: Record; seq: number; } /** @direction client→server (user clicked an action button) */ export interface ActionClick { type: typeof ACTION_CLICK; id: string; actionId: string; value: string; triggerId: string; messageRef?: MessageRef; userId: string; } /** @direction client→server (user submitted a modal — values match ModalSubmitContext.values) */ export interface ModalSubmit { type: typeof MODAL_SUBMIT; id: string; callbackId: string; privateMetadata: string; values: Record>; userId: string; } /** * @direction server→client (replay prior messages on session attach) * * Items are wire frames the client renders identically to live frames; * they share the same seq space but are flagged via `isCatchUp` so the * client suppresses notification side effects. * * Outer envelope carries no own `seq` — clients should use `seqEnd` as * the high-water mark and expect the next live frame at `seqEnd + 1`. */ export interface TranscriptReplay { type: typeof TRANSCRIPT_REPLAY; sessionId: string; items: Array; seqStart: number; seqEnd: number; isCatchUp: boolean; } /** * @direction server→client * * Routed when a project-report / scheduled-report / thread-report destination * lands on a TUI conduit whose active session ≠ the originating session. * Renders as a corner badge, not inserted into the active chat. */ export interface Notification { type: typeof NOTIFICATION; kind: 'project-report' | 'system-notice' | 'thread-report'; projectId: string; sessionId?: string | null; title: string; body: string; ref?: MessageRef; seq: number; } /** @direction client→server (read-only query into UiService) */ export interface UiQuery { type: typeof UI_QUERY; id: string; scope: string; params?: Record; } /** @direction server→client (result of ui.query — id echoes request) */ export type UiQueryResult = { type: typeof UI_QUERY_RESULT; id: string; ok: true; data: unknown; } | { type: typeof UI_QUERY_RESULT; id: string; ok: false; error: { code: string; message: string; }; }; /** @direction client→server (audited write into UiService) */ export interface UiMutate { type: typeof UI_MUTATE; id: string; op: string; args: Record; } /** @direction server→client (result of ui.mutate — id echoes request) */ export type UiMutateResult = { type: typeof UI_MUTATE_RESULT; id: string; ok: true; data?: unknown; } | { type: typeof UI_MUTATE_RESULT; id: string; ok: false; error: { code: string; message: string; }; }; /** @direction client→server (open an event subscription) */ export interface UiSubscribe { type: typeof UI_SUBSCRIBE; id: string; filter: { events: string[]; projectId?: string | null; }; } /** @direction server→client (streamed event for a subscription — id echoes subscribe) */ export interface UiEvent { type: typeof UI_EVENT; id: string; event: { type: string; ts: string; payload: unknown; }; seq: number; } /** @direction client→server (close a subscription — id matches subscribe) */ export interface UiUnsubscribe { type: typeof UI_UNSUBSCRIBE; id: string; } /** @direction server→client */ export interface ErrorFrame { type: typeof ERROR; code: number; message: string; /** id of the client→server frame that caused this error, if applicable */ refId?: string; closeAfter?: boolean; } export type TuiFrame = HandshakeHello | HandshakeAck | SessionSwitch | SessionSwitched | Ping | Pong | Close | ChatPost | ChatUpdate | ChatDelete | ChatMarkQueued | MsgUser | MsgEdit | StreamText | StreamMutableOpen | StreamMutableUpdate | StreamFlush | InteractivePost | ModalOpen | ModalAck | ActionClick | ModalSubmit | TranscriptReplay | Notification | UiQuery | UiQueryResult | UiMutate | UiMutateResult | UiSubscribe | UiEvent | UiUnsubscribe | ErrorFrame; export declare function isHandshakeHello(f: TuiFrame): f is HandshakeHello; export declare function isHandshakeAck(f: TuiFrame): f is HandshakeAck; export declare function isSessionSwitch(f: TuiFrame): f is SessionSwitch; export declare function isSessionSwitched(f: TuiFrame): f is SessionSwitched; export declare function isPing(f: TuiFrame): f is Ping; export declare function isPong(f: TuiFrame): f is Pong; export declare function isClose(f: TuiFrame): f is Close; export declare function isChatPost(f: TuiFrame): f is ChatPost; export declare function isChatUpdate(f: TuiFrame): f is ChatUpdate; export declare function isChatDelete(f: TuiFrame): f is ChatDelete; export declare function isChatMarkQueued(f: TuiFrame): f is ChatMarkQueued; export declare function isMsgUser(f: TuiFrame): f is MsgUser; export declare function isMsgEdit(f: TuiFrame): f is MsgEdit; export declare function isStreamText(f: TuiFrame): f is StreamText; export declare function isStreamMutableOpen(f: TuiFrame): f is StreamMutableOpen; export declare function isStreamMutableUpdate(f: TuiFrame): f is StreamMutableUpdate; export declare function isStreamFlush(f: TuiFrame): f is StreamFlush; export declare function isInteractivePost(f: TuiFrame): f is InteractivePost; export declare function isModalOpen(f: TuiFrame): f is ModalOpen; export declare function isModalAck(f: TuiFrame): f is ModalAck; export declare function isActionClick(f: TuiFrame): f is ActionClick; export declare function isModalSubmit(f: TuiFrame): f is ModalSubmit; export declare function isTranscriptReplay(f: TuiFrame): f is TranscriptReplay; export declare function isNotification(f: TuiFrame): f is Notification; export declare function isUiQuery(f: TuiFrame): f is UiQuery; export declare function isUiQueryResult(f: TuiFrame): f is UiQueryResult; export declare function isUiMutate(f: TuiFrame): f is UiMutate; export declare function isUiMutateResult(f: TuiFrame): f is UiMutateResult; export declare function isUiSubscribe(f: TuiFrame): f is UiSubscribe; export declare function isUiEvent(f: TuiFrame): f is UiEvent; export declare function isUiUnsubscribe(f: TuiFrame): f is UiUnsubscribe; export declare function isErrorFrame(f: TuiFrame): f is ErrorFrame; export declare const ALL_FRAME_TYPES: readonly string[]; export declare const GUARD_BY_TYPE: Record boolean>; export declare function parseFrame(raw: string): TuiFrame | null; export declare function encodeFrame(f: TuiFrame): string; export type { MessageRef, MessageContent, RichBlock, ActionElement, ModalDefinition, ModalField, ModalFieldValue, } from '../types.js';