// === WebSocket Protocol Types (xterm.js + node-pty) === // Binary frame header for terminal data multiplexing: // [1 byte direction][36 bytes chatId ASCII][...payload] // Direction: 0x01 = PTY output (proxy→backend→frontend) // 0x02 = user input (frontend→backend→proxy) export const DIR_PTY_OUTPUT = 0x01; export const DIR_USER_INPUT = 0x02; export const CHAT_ID_LENGTH = 36; // UUID length export function encodeBinaryFrame(direction: number, chatId: string, data: Buffer): Buffer { const header = Buffer.alloc(1 + CHAT_ID_LENGTH); header[0] = direction; header.write(chatId, 1, CHAT_ID_LENGTH, 'ascii'); return Buffer.concat([header, data]); } export function decodeBinaryFrame(frame: Buffer): { direction: number; chatId: string; data: Buffer } { const direction = frame[0]; const chatId = frame.subarray(1, 1 + CHAT_ID_LENGTH).toString('ascii'); const data = frame.subarray(1 + CHAT_ID_LENGTH); return { direction, chatId, data }; } // JSON control messages export type BackendMessageType = | 'sync_state' | 'create_pty' | 'kill_pty' | 'resize' | 'list_directories' | 'list_sessions'; export type ProxyMessageType = | 'pty_ready' | 'pty_closed' | 'directories' | 'sessions_list' | 'error'; export type WsMessageType = BackendMessageType | ProxyMessageType; export interface WsMessage { type: WsMessageType; requestId?: string; payload: unknown; } // === Payload types === export interface SyncStatePayload { chats: AgentChatInfo[]; } export interface AgentChatInfo { id: string; workDir: string | null; sessionId: string | null; cols?: number; rows?: number; } export interface CreatePtyPayload { chatId: string; dir: string; resumeSessionId?: string; cols: number; rows: number; } export interface KillPtyPayload { chatId: string; } export interface ResizePayload { chatId: string; cols: number; rows: number; } export interface PtyReadyPayload { chatId: string; } export interface PtyClosedPayload { chatId: string; exitCode: number; } export interface ListDirectoriesPayload { path: string; } export interface DirectoryEntry { name: string; isDirectory: boolean; } export interface DirectoriesPayload { requestId: string; entries: DirectoryEntry[]; } export interface ErrorPayload { chatId?: string; message: string; }