import ClawdbotProtocol import Foundation import Observation struct ProvidersStatusSnapshot: Codable { struct WhatsAppSelf: Codable { let e164: String? let jid: String? } struct WhatsAppDisconnect: Codable { let at: Double let status: Int? let error: String? let loggedOut: Bool? } struct WhatsAppStatus: Codable { let configured: Bool let linked: Bool let authAgeMs: Double? let `self`: WhatsAppSelf? let running: Bool let connected: Bool let lastConnectedAt: Double? let lastDisconnect: WhatsAppDisconnect? let reconnectAttempts: Int let lastMessageAt: Double? let lastEventAt: Double? let lastError: String? } struct TelegramBot: Codable { let id: Int? let username: String? } struct TelegramWebhook: Codable { let url: String? let hasCustomCert: Bool? } struct TelegramProbe: Codable { let ok: Bool let status: Int? let error: String? let elapsedMs: Double? let bot: TelegramBot? let webhook: TelegramWebhook? } struct TelegramStatus: Codable { let configured: Bool let tokenSource: String? let running: Bool let mode: String? let lastStartAt: Double? let lastStopAt: Double? let lastError: String? let probe: TelegramProbe? let lastProbeAt: Double? } struct DiscordBot: Codable { let id: String? let username: String? } struct DiscordProbe: Codable { let ok: Bool let status: Int? let error: String? let elapsedMs: Double? let bot: DiscordBot? } struct DiscordStatus: Codable { let configured: Bool let tokenSource: String? let running: Bool let lastStartAt: Double? let lastStopAt: Double? let lastError: String? let probe: DiscordProbe? let lastProbeAt: Double? } struct SignalProbe: Codable { let ok: Bool let status: Int? let error: String? let elapsedMs: Double? let version: String? } struct SignalStatus: Codable { let configured: Bool let baseUrl: String let running: Bool let lastStartAt: Double? let lastStopAt: Double? let lastError: String? let probe: SignalProbe? let lastProbeAt: Double? } struct IMessageProbe: Codable { let ok: Bool let error: String? } struct IMessageStatus: Codable { let configured: Bool let running: Bool let lastStartAt: Double? let lastStopAt: Double? let lastError: String? let cliPath: String? let dbPath: String? let probe: IMessageProbe? let lastProbeAt: Double? } let ts: Double let whatsapp: WhatsAppStatus let telegram: TelegramStatus let discord: DiscordStatus? let signal: SignalStatus? let imessage: IMessageStatus? } struct ConfigSnapshot: Codable { struct Issue: Codable { let path: String let message: String } let path: String? let exists: Bool? let raw: String? let parsed: AnyCodable? let valid: Bool? let config: [String: AnyCodable]? let issues: [Issue]? } struct DiscordGuildChannelForm: Identifiable { let id = UUID() var key: String var allow: Bool var requireMention: Bool init(key: String = "", allow: Bool = true, requireMention: Bool = false) { self.key = key self.allow = allow self.requireMention = requireMention } } struct DiscordGuildForm: Identifiable { let id = UUID() var key: String var slug: String var requireMention: Bool var reactionNotifications: String var users: String var channels: [DiscordGuildChannelForm] init( key: String = "", slug: String = "", requireMention: Bool = false, reactionNotifications: String = "own", users: String = "", channels: [DiscordGuildChannelForm] = []) { self.key = key self.slug = slug self.requireMention = requireMention self.reactionNotifications = reactionNotifications self.users = users self.channels = channels } } @MainActor @Observable final class ConnectionsStore { static let shared = ConnectionsStore() var snapshot: ProvidersStatusSnapshot? var lastError: String? var lastSuccess: Date? var isRefreshing = false var whatsappLoginMessage: String? var whatsappLoginQrDataUrl: String? var whatsappLoginConnected: Bool? var whatsappBusy = false var telegramToken: String = "" var telegramRequireMention = true var telegramAllowFrom: String = "" var telegramProxy: String = "" var telegramWebhookUrl: String = "" var telegramWebhookSecret: String = "" var telegramWebhookPath: String = "" var telegramBusy = false var discordEnabled = true var discordToken: String = "" var discordDmEnabled = true var discordAllowFrom: String = "" var discordGroupEnabled = false var discordGroupChannels: String = "" var discordMediaMaxMb: String = "" var discordHistoryLimit: String = "" var discordTextChunkLimit: String = "" var discordReplyToMode: String = "off" var discordGuilds: [DiscordGuildForm] = [] var discordActionReactions = true var discordActionStickers = true var discordActionPolls = true var discordActionPermissions = true var discordActionMessages = true var discordActionThreads = true var discordActionPins = true var discordActionSearch = true var discordActionMemberInfo = true var discordActionRoleInfo = true var discordActionChannelInfo = true var discordActionVoiceStatus = true var discordActionEvents = true var discordActionRoles = false var discordActionModeration = false var discordSlashEnabled = false var discordSlashName: String = "" var discordSlashSessionPrefix: String = "" var discordSlashEphemeral = true var signalEnabled = true var signalAccount: String = "" var signalHttpUrl: String = "" var signalHttpHost: String = "" var signalHttpPort: String = "" var signalCliPath: String = "" var signalAutoStart = true var signalReceiveMode: String = "" var signalIgnoreAttachments = false var signalIgnoreStories = false var signalSendReadReceipts = false var signalAllowFrom: String = "" var signalMediaMaxMb: String = "" var imessageEnabled = true var imessageCliPath: String = "" var imessageDbPath: String = "" var imessageService: String = "auto" var imessageRegion: String = "" var imessageAllowFrom: String = "" var imessageIncludeAttachments = false var imessageMediaMaxMb: String = "" var configStatus: String? var isSavingConfig = false let interval: TimeInterval = 45 let isPreview: Bool var pollTask: Task? var configRoot: [String: Any] = [:] var configLoaded = false init(isPreview: Bool = ProcessInfo.processInfo.isPreview) { self.isPreview = isPreview } }