// ── Central DB entities ── export interface AgentGroup { id: string; name: string; folder: string; agent_provider: string | null; created_at: string; } export type UnknownSenderPolicy = 'strict' | 'request_approval' | 'public'; export interface MessagingGroup { id: string; channel_type: string; platform_id: string; name: string | null; is_group: number; // 0 | 1 unknown_sender_policy: UnknownSenderPolicy; created_at: string; } // ── Identity & privilege ── /** * User = a messaging-platform identifier. Namespaced so distinct channels * with numeric IDs don't collide: "phone:+1555...", "tg:123", "discord:456", * "email:a@x.com". A single human with a phone AND a telegram handle has * two separate users — no cross-channel linking (yet). */ export interface User { id: string; kind: string; // 'phone' | 'email' | 'discord' | 'telegram' | 'matrix' | ... display_name: string | null; created_at: string; } export type UserRoleKind = 'owner' | 'admin'; /** * Role grant. Owner is always global. Admin is either global * (agent_group_id = null) or scoped to a specific agent group. * Admin @ A implicitly makes the user a member of A — we do not require * a separate agent_group_members row for admins. */ export interface UserRole { user_id: string; role: UserRoleKind; agent_group_id: string | null; granted_by: string | null; granted_at: string; } /** "Known" membership in an agent group — required for unprivileged users. */ export interface AgentGroupMember { user_id: string; agent_group_id: string; added_by: string | null; added_at: string; } /** Cached DM channel for a user on a specific channel_type. */ export interface UserDm { user_id: string; channel_type: string; messaging_group_id: string; resolved_at: string; } export interface MessagingGroupAgent { id: string; messaging_group_id: string; agent_group_id: string; trigger_rules: string | null; // JSON: { pattern, mentionOnly, excludeSenders, includeSenders } response_scope: 'all' | 'triggered' | 'allowlisted'; session_mode: 'shared' | 'per-thread' | 'agent-shared'; priority: number; created_at: string; } export interface Session { id: string; agent_group_id: string; messaging_group_id: string | null; thread_id: string | null; agent_provider: string | null; status: 'active' | 'closed'; container_status: 'running' | 'idle' | 'stopped'; last_active: string | null; created_at: string; } // ── Session DB entities ── export type MessageInKind = 'chat' | 'chat-sdk' | 'task' | 'webhook' | 'system'; export type MessageInStatus = 'pending' | 'processing' | 'completed' | 'failed'; export interface MessageIn { id: string; kind: MessageInKind; timestamp: string; status: MessageInStatus; status_changed: string | null; process_after: string | null; recurrence: string | null; tries: number; platform_id: string | null; channel_type: string | null; thread_id: string | null; content: string; // JSON blob } export interface MessageOut { id: string; in_reply_to: string | null; timestamp: string; delivered: number; // 0 | 1 deliver_after: string | null; recurrence: string | null; kind: string; platform_id: string | null; channel_type: string | null; thread_id: string | null; content: string; // JSON blob } // ── Pending questions (central DB) ── export interface PendingQuestion { question_id: string; session_id: string; message_out_id: string; platform_id: string | null; channel_type: string | null; thread_id: string | null; title: string; options: import('./channels/ask-question.js').NormalizedOption[]; created_at: string; } // ── Pending approvals (central DB) ── export interface PendingApproval { approval_id: string; session_id: string | null; request_id: string; action: string; payload: string; // JSON created_at: string; agent_group_id: string | null; channel_type: string | null; platform_id: string | null; platform_message_id: string | null; expires_at: string | null; status: 'pending' | 'approved' | 'rejected' | 'expired'; title: string; options_json: string; } // ── Pending credentials (central DB) ── export type PendingCredentialStatus = 'pending' | 'submitted' | 'saved' | 'rejected' | 'failed'; export interface PendingCredential { id: string; agent_group_id: string; session_id: string | null; name: string; type: 'generic' | 'anthropic'; host_pattern: string; path_pattern: string | null; header_name: string | null; value_format: string | null; description: string | null; channel_type: string; platform_id: string; platform_message_id: string | null; status: PendingCredentialStatus; created_at: string; } // ── Pending swaps (central DB, builder-agent feature) ── /** Classification of a swap's diff — drives approval routing + warning UX. */ export type SwapClassification = 'group' | 'host' | 'combined'; /** * Swap lifecycle status. Transitions: * pending_approval → awaiting_confirmation → (finalized | rolled_back | rejected) * `rejected` is also reachable directly from pending_approval. */ export type SwapStatus = 'pending_approval' | 'awaiting_confirmation' | 'finalized' | 'rolled_back' | 'rejected'; /** * Deadman handshake state — only meaningful while status = awaiting_confirmation. * pending_restart — swap applied, container/host restarting, message 1 not yet sent. * message1_sent — handshake prompt delivered, waiting for user confirm/rollback. */ export type SwapHandshakeState = 'pending_restart' | 'message1_sent'; export interface PendingSwap { request_id: string; dev_agent_id: string; originating_group_id: string; dev_branch: string; commit_sha: string; classification: SwapClassification; status: SwapStatus; summary_json: string; pre_swap_sha: string | null; db_snapshot_path: string | null; deadman_started_at: string | null; deadman_expires_at: string | null; handshake_state: SwapHandshakeState | null; created_at: string; } // ── Agent destinations (central DB) ── export interface AgentDestination { agent_group_id: string; local_name: string; target_type: 'channel' | 'agent'; target_id: string; created_at: string; }