UNPKG

@gguf/claw

Version:

Multi-channel AI gateway with extensible messaging integrations

1,063 lines (1,050 loc) โ€ข 2.66 MB
import { t as __exportAll } from "./rolldown-runtime-Cbj13DAv.js"; import { c as expandHomePrefix, i as resolveGatewayPort, n as resolveConfigPath, s as resolveStateDir, t as STATE_DIR, u as resolveRequiredHomeDir } from "./paths-CyR9Pa1R.js"; import { _ as isSubagentSessionKey, c as normalizeAccountId$3, d as resolveAgentIdFromSessionKey, f as resolveThreadSessionKeys, g as isCronSessionKey, h as isAcpSessionKey, i as buildAgentMainSessionKey, l as normalizeAgentId, m as getSubagentDepth, n as DEFAULT_AGENT_ID, p as sanitizeAgentId, s as classifySessionKeyShape, t as DEFAULT_ACCOUNT_ID$1, u as normalizeMainKey, v as parseAgentSessionKey, y as resolveThreadParentSessionKey } from "./session-key-CgcjHuX_.js"; import { $ as warn, B as sleep$1, D as escapeRegExp, E as ensureDir$3, G as danger, I as resolveUserPath, J as logVerbose, M as normalizeE164, O as formatTerminalLink, R as shortenHomeInString, S as CONFIG_DIR, U as truncateUtf16Safe, V as sliceUtf16Safe, W as isPlainObject, X as setVerbose, Z as shouldLogVerbose, _ as matchPluginCommand, a as normalizeAnyChannelId, d as createPluginRegistry, dt as resolvePreferredOpenClawTmpDir, et as colorize, f as normalizePluginHttpPath, g as listPluginCommands, h as getPluginCommandSpecs, k as isRecord$1, l as requireActivePluginRegistry, lt as normalizeLogLevel, m as executePluginCommand, n as CHAT_CHANNEL_ORDER, nt as theme, o as normalizeChannelId, p as clearPluginCommands, r as DEFAULT_CHAT_CHANNEL, rt as getChildLogger, tt as isRich, u as setActivePluginRegistry, v as createInternalHookEvent, w as clampInt, x as triggerInternalHook, z as shortenHomePath } from "./registry-BmY4gNy6.js"; import { a as resolveAgentModelPrimary, c as resolveDefaultAgentId, d as resolveSessionAgentIds, i as resolveAgentModelFallbacksOverride, l as resolveEffectiveModelFallbacks, n as resolveAgentConfig, o as resolveAgentSkillsFilter, r as resolveAgentDir, s as resolveAgentWorkspaceDir, t as listAgentIds, u as resolveSessionAgentId } from "./agent-scope-BLYwrEEA.js"; import { a as registerActiveProgressLine, i as clearActiveProgressLine, n as createNonExitingRuntime, o as unregisterActiveProgressLine, r as defaultRuntime, t as createSubsystemLogger } from "./subsystem-B5g771Td.js"; import { S as logWarn, _ as runExec, b as logError, f as loadWorkspaceBootstrapFiles, g as runCommandWithTimeout, l as ensureAgentWorkspace, m as resolveOpenClawPackageRoot, n as DEFAULT_AGENT_WORKSPACE_DIR, r as DEFAULT_BOOTSTRAP_FILENAME, u as filterBootstrapFilesForSession, v as spawnWithFallback, x as logInfo, y as logDebug } from "./workspace-D9IzNnST.js"; import { n as SILENT_REPLY_TOKEN, r as isSilentReplyText, t as HEARTBEAT_TOKEN } from "./tokens-BRx7o_ZS.js"; import { a as listTelegramAccountIds, c as resolveSlackAccount, d as resolveSlackBotToken, f as createDiscordActionGate, h as normalizeDiscordToken, i as listEnabledTelegramAccounts, m as resolveDiscordAccount, n as normalizeWhatsAppTarget, o as resolveTelegramAccount, p as listEnabledDiscordAccounts, r as createTelegramActionGate, s as resolveTelegramToken, t as isWhatsAppGroupJid, u as resolveSlackAppToken } from "./normalize-DZvZ0Eiv.js"; import { a as logoutWeb, i as logWebSelfId, l as readWebSelfId, p as webAuthExists, r as getWebAuthAgeMs, t as resolveWhatsAppAccount } from "./accounts-D7irbKbS.js"; import { t as normalizeChatType } from "./chat-type-C_KiWNAH.js"; import { t as parseBooleanValue$1 } from "./boolean-B8-BqKGQ.js"; import { n as resolveCliName, r as isTruthyEnvValue, t as formatCliCommand } from "./command-format-Ck2WauwF.js"; import { a as resolveSlackWebClientOptions, c as buildSlackBlocksFallbackText, i as createSlackWebClient, l as parseSlackTarget, o as parseSlackBlocksInput, s as validateSlackBlocksArray, t as sendMessageSlack, u as resolveSlackChannelId } from "./send-CbPQXDCf.js"; import { n as listChannelPlugins, r as normalizeChannelId$1, t as getChannelPlugin } from "./plugins-CJYXNO4s.js"; import { $ as hasAnyGuildPermissionDiscord, A as addRoleDiscord, B as removeRoleDiscord, C as fetchMessageDiscord, Ct as applyChannelMatchMeta, D as readMessagesDiscord, E as pinMessageDiscord, Et as resolveChannelEntryMatchWithFallback, F as fetchRoleInfoDiscord, G as createChannelDiscord, H as listGuildEmojisDiscord, I as fetchVoiceStatusDiscord, J as moveChannelDiscord, K as deleteChannelDiscord, L as kickMemberDiscord, M as createScheduledEventDiscord, N as fetchChannelInfoDiscord, O as searchMessagesDiscord, P as fetchMemberInfoDiscord, Q as fetchChannelPermissionsDiscord, R as listGuildChannelsDiscord, S as editMessageDiscord, St as fetchDiscord, T as listThreadsDiscord, Tt as normalizeChannelSlug, U as uploadEmojiDiscord, V as timeoutMemberDiscord, W as uploadStickerDiscord, X as setChannelPermissionDiscord, Y as removeChannelPermissionDiscord, Z as stripUndefinedFields, _ as sendPollDiscord, _t as shouldEmitDiscordReactionNotification, a as removeReactionDiscord, at as listDiscordDirectoryPeersLive, b as createThreadDiscord, bt as resolveDiscordSystemLocation, c as formatDiscordComponentEventText, ct as normalizeDiscordAllowList, d as parseDiscordModalCustomId, dt as resolveDiscordChannelConfigWithFallback, et as createDiscordClient, f as parseDiscordModalCustomIdForCarbon, ft as resolveDiscordGuildEntry, g as sendMessageDiscord, gt as resolveGroupDmAllow, h as resolveDiscordModalEntry, ht as resolveDiscordShouldRequireMention, i as removeOwnReactionsDiscord, it as listDiscordDirectoryGroupsLive, j as banMemberDiscord, k as unpinMessageDiscord, l as parseDiscordComponentCustomId, lt as normalizeDiscordSlug, m as resolveDiscordComponentEntry, mt as resolveDiscordOwnerAllowFrom, n as fetchReactionsDiscord, nt as parseDiscordTarget, o as sendDiscordComponentMessage, ot as allowListMatches$1, p as readDiscordComponentSpec, pt as resolveDiscordMemberAccessState, q as editChannelDiscord, r as reactMessageDiscord, rt as resolveDiscordChannelId, s as createDiscordFormModal, st as isDiscordGroupAllowedByPolicy, tt as chunkDiscordTextWithMode, u as parseDiscordComponentCustomIdForCarbon, ut as resolveDiscordAllowListMatch, v as sendStickerDiscord, vt as formatDiscordReactionEmoji, w as listPinsDiscord, wt as buildChannelKeyCandidates, x as deleteMessageDiscord, xt as resolveTimestampMs, y as sendVoiceMessageDiscord, yt as formatDiscordUserTag, z as listScheduledEventsDiscord } from "./send-VMzh7zM1.js"; import { C as getGlobalHookRunner, S as parseInlineDirectives$1, _ as normalizeTargetForProvider, a as normalizeOutboundPayloadsForJson, b as MEDIA_TOKEN_RE, c as applyReplyThreading, d as isRenderablePayload, f as shouldSuppressMessagingToolReplies, g as normalizeChannelTargetInput, h as buildTargetResolverSignature, i as normalizeOutboundPayloads, l as filterMessagingToolDuplicates, m as resolveReplyToMode, o as normalizeReplyPayloadsForDelivery, p as createReplyToModeFilterForChannel, r as formatOutboundPayloadLog, s as applyReplyTagsToPayload, t as deliverOutboundPayloads, u as filterMessagingToolMediaDuplicates, v as throwIfAborted, w as initializeGlobalHookRunner, x as splitMediaFromOutput, y as parseReplyDirectives } from "./deliver-C5sD6Dv0.js"; import { a as logMessageProcessed, c as logWebhookError, d as startDiagnosticHeartbeat, f as stopDiagnosticHeartbeat, i as logLaneEnqueue, l as logWebhookProcessed, m as isDiagnosticsEnabled, o as logMessageQueued, p as emitDiagnosticEvent, r as logLaneDequeue, s as logSessionStateChange, t as diag, u as logWebhookReceived } from "./diagnostic-CoT2YQH4.js"; import { r as getDiagnosticSessionState } from "./diagnostic-session-state-DmrztgHU.js"; import { n as resolveSignalAccount, t as listEnabledSignalAccounts } from "./accounts-DSVHyeYh.js"; import { $ as isVoiceCompatibleAudio, A as extractTelegramLocation, B as normalizeAllowFromWithStore$1, C as buildTelegramGroupFrom, D as buildTypingThreadParams, E as buildTelegramThreadParams, F as resolveTelegramMediaPlaceholder, G as formatLocationText, H as firstDefined$1, I as resolveTelegramReplyId, J as readChannelAllowFromStore, K as toLocationContext, L as resolveTelegramStreamMode, M as normalizeForwardedContext, N as resolveTelegramForumThreadId, O as describeReplyTarget, P as resolveTelegramGroupAllowFromContext, Q as listPairingChannels, R as resolveTelegramThreadSpec, S as buildSenderName, T as buildTelegramParentPeer, U as isSenderIdAllowed, V as resolveSenderAllowMatch, W as mergeAllowFromSources, X as upsertChannelPairingRequest, Y as removeChannelAllowFromStoreEntry, Z as getPairingAdapter, _ as resolveTelegramFetch, a as reactMessageTelegram, b as buildGroupLabel, c as sendStickerTelegram, d as wasSentByBot, et as parseTelegramTarget, f as isRecoverableTelegramNetworkError, g as wrapFileReferencesInHtml, h as renderTelegramHtmlText, i as editMessageTelegram, j as hasBotMention, k as expandTextLinks, m as markdownToTelegramHtml, n as createForumTopicTelegram, o as sendMessageTelegram, p as markdownToTelegramChunks, q as addChannelAllowFromStoreEntry, r as deleteMessageTelegram, s as sendPollTelegram, t as buildInlineKeyboard, tt as resolveTelegramTargetChatType, u as resolveTelegramVoiceSend, v as splitTelegramCaption, w as buildTelegramGroupPeerId, x as buildSenderLabel, y as withTelegramApiErrorLogging, z as isSenderAllowed$1 } from "./send-xJGV2Pmu.js"; import { d as detectMime, f as extensionForMime, g as isGifMedia, h as isAudioFileName, m as imageMimeFromFormat, s as getImageMetadata, u as resizeToJpeg, x as mediaKindFromMime, y as MAX_IMAGE_BYTES } from "./fs-safe-B8-WkEXM.js"; import { A as normalizeProviderId, C as buildAllowedModelSet, D as isCliProvider, E as findNormalizedProviderValue, F as resolveSubagentSpawnModelSelection, G as DEFAULT_MODEL, H as OLLAMA_NATIVE_BASE_URL, I as resolveThinkingDefault, J as normalizeSecretInput, K as DEFAULT_PROVIDER, M as resolveConfiguredModelRef, N as resolveDefaultModelForAgent, O as modelKey, P as resolveModelRefFromString, T as buildModelAliasIndex, U as createOllamaStreamFn, W as DEFAULT_CONTEXT_TOKENS, Y as getShellPathFromLoginShell, Z as resolveShellEnvFallbackTimeoutMs, _ as ensureAuthProfileStore, a as resolveEnvApiKey, b as withFileLock, c as resolveAuthProfileOrder, d as markAuthProfileFailure, f as markAuthProfileUsed, g as markAuthProfileGood, h as listProfilesForProvider, i as resolveApiKeyForProvider, k as normalizeModelRef$2, l as getSoonestCooldownExpiry, m as dedupeProfileIds, n as getCustomProviderApiKey, o as resolveModelAuthMode, p as resolveApiKeyForProfile, q as resolveAuthProfileDisplayLabel, r as requireApiKey, t as getApiKeyForModel, u as isProfileInCooldown, v as resolveAuthStorePathForDisplay, w as buildConfiguredAllowlistKeys, y as resolveOpenClawAgentDir } from "./model-auth-BPNt9bHS.js"; import { a as saveJsonFile, i as loadJsonFile } from "./github-copilot-token-BQ98eazZ.js"; import { n as discoverModels, t as discoverAuthStorage } from "./pi-model-discovery-C-yOXpma.js"; import { a as isMarkdownCapableMessageChannel, c as resolveGatewayMessageChannel, d as GATEWAY_CLIENT_MODES, f as GATEWAY_CLIENT_NAMES, i as isInternalMessageChannel, l as resolveMessageChannel, n as isDeliverableMessageChannel, o as listDeliverableMessageChannels, r as isGatewayMessageChannel, s as normalizeMessageChannel, t as INTERNAL_MESSAGE_CHANNEL, u as GATEWAY_CLIENT_IDS } from "./message-channel-BDlvrUZF.js"; import { $ as normalizeAccountId$4, A as isTransientHttpError, At as getBridgeAuthForPort, B as loadSessionStore, Bt as normalizeToolName, C as isContextOverflowError, Ct as resolveSessionLockMaxHoldFromTimeout, D as isRateLimitAssistantError, Dt as resolveProfile, E as isLikelyContextOverflowError, Et as resolveBrowserConfig, F as resolveSandboxContext, Ft as buildPluginToolGroups, G as updateSessionStoreEntry, Gt as buildBootstrapContextFiles, H as recordSessionMetaFromInbound, Ht as stripPluginOnlyAllowlist, I as resolveSandboxRuntimeStatus, It as collectExplicitAllowlist, J as deliveryContextFromSession, Jt as resolveBootstrapTotalMaxChars, K as isCacheEnabled, Kt as ensureSessionHeader, L as extractDeliveryInfo, Lt as expandPolicyWithPluginGroups, M as parseImageSizeError, Mt as resolveBrowserControlAuth, N as sanitizeUserFacingText, Nt as resolveSandboxConfigForAgent, O as isRawApiErrorPayload, Ot as DEFAULT_UPLOAD_DIR, P as ensureSandboxWorkspaceForSession, Pt as applyOwnerOnlyToolPolicy, Q as normalizeSessionDeliveryFields, R as appendAssistantMessageToSessionTranscript, Rt as expandToolGroups, S as isCompactionFailureError, St as acquireSessionWriteLock, T as isFailoverErrorMessage, Tt as registerBrowserRoutes, U as updateLastRoute, Ut as compileGlobPatterns, V as readSessionUpdatedAt, Vt as resolveToolProfilePolicy, W as updateSessionStore, Wt as matchesAnyGlobPattern, X as mergeDeliveryContext, Y as deliveryContextKey, Yt as sanitizeGoogleTurnOrdering, Z as normalizeDeliveryContext, _ as formatRawAssistantErrorForUi, a as isMessagingToolDuplicateNormalized, at as applyInputProvenanceToUserMessage, b as isBillingAssistantError, bt as deriveSessionMetaPatch, c as extractToolCallsFromAssistant, ct as resolveSessionKey, d as isAntigravityClaude, dt as resolveSessionResetPolicy, et as archiveSessionTranscripts, f as isGoogleModelApi, ft as resolveSessionResetType, g as formatBillingErrorMessage, gt as canonicalizeMainSessionAlias, h as formatAssistantErrorText, ht as resolveFreshSessionTotalTokens, it as INPUT_PROVENANCE_KIND_VALUES, j as parseImageDimensionError, jt as ensureBrowserControlAuth, k as isTimeoutErrorMessage, kt as resolveExistingPathsWithinRoot, l as extractToolResultId, lt as evaluateSessionFreshness, m as classifyFailoverReason, mt as DEFAULT_RESET_TRIGGERS, n as validateGeminiTurns, nt as countToolResults, o as normalizeTextForComparison, ot as hasInterSessionUserProvenance, p as BILLING_ERROR_USER_MESSAGE, pt as resolveThreadFlag, q as resolveCacheTtlMs$1, qt as resolveBootstrapMaxChars, r as pickFallbackThinkingLevel, rt as extractToolCallNames, s as sanitizeSessionMessagesImages, st as normalizeInputProvenance, t as validateAnthropicTurns, tt as capArrayByJsonBytes, u as downgradeOpenAIReasoningBlocks, ut as resolveChannelResetConfig, v as getApiErrorPayloadFingerprint, vt as resolveExplicitAgentSessionKey, w as isFailoverAssistantError, wt as createBrowserRouteContext, x as isCloudCodeAssistFormatError, xt as resolveGroupSessionKey, y as isAuthAssistantError, yt as resolveMainSessionKey, zt as mergeAlsoAllowPolicy } from "./pi-embedded-helpers-BfjCe8vu.js"; import { C as getConfigValueAtPath, D as isSafeExecutableValue, E as unsetConfigValueAtPath, O as resolveAgentMaxConcurrent, S as unsetConfigOverride, T as setConfigValueAtPath, _ as parseDurationMs, a as writeConfigFile, b as resetConfigOverrides, c as TELEGRAM_COMMAND_NAME_PATTERN, f as isInboundPathAllowed, g as normalizeScpRemoteHost, h as resolveIMessageRemoteAttachmentRoots, i as resolveConfigSnapshotHash, k as VERSION, l as normalizeTelegramCommandName, m as resolveIMessageAttachmentRoots, n as loadConfig, o as validateConfigObjectWithPlugins, r as readConfigFileSnapshot, u as resolveTelegramCustomCommands, v as validateJsonSchemaValue, w as parseConfigPath, x as setConfigOverride, y as getConfigOverrides } from "./config-C0k_b9gg.js"; import { a as applyTestPluginDefaults, c as resolveMemorySlotDecision, i as safeStatSync, n as discoverOpenClawPlugins, o as normalizePluginsConfig, r as isPathInside, s as resolveEnableState, t as loadPluginManifestRegistry, u as isPathInsideWithRealpath } from "./manifest-registry-Dovhiqzt.js"; import { a as parseAvailableTags, c as readStringArrayParam, h as resolveImageSanitizationLimits, i as jsonResult, l as readStringOrNumberParam, m as sanitizeToolResultImages, n as imageResult, o as readNumberParam, p as sanitizeImageBlocks, r as imageResultFromFile, s as readReactionParams, t as createActionGate, u as readStringParam } from "./common-y9ALHdVZ.js"; import { C as rawDataToString, O as DEFAULT_AI_SNAPSHOT_MAX_CHARS, T as isSecureWebSocketUrl, x as ensureChromeExtensionRelayServer } from "./chrome-DVeI6N8j.js"; import { c as assertSandboxPath, d as resolveSandboxedMediaSource, f as applySkillEnvOverrides, i as resolveSkillsPromptForRun, l as resolveSandboxInputPath, n as buildWorkspaceSkillSnapshot, p as applySkillEnvOverridesFromSnapshot, r as loadWorkspaceSkillEntries, s as assertMediaNotDataUrl } from "./skills-Ci_2Mah4.js"; import { n as formatErrorMessage, r as formatUncaughtError } from "./errors-3KjSwJLH.js"; import { i as isBlockedHostnameOrIp, o as normalizeHostname, t as SsrFBlockedError } from "./ssrf-B8OrDkCk.js"; import { n as getMediaDir, r as saveMediaBuffer } from "./store-Be0QxLPZ.js"; import { _ as normalizeAtHashSlug, a as normalizeReasoningLevel, b as normalizeStringEntriesLower, c as normalizeVerboseLevel, d as getChannelDock, f as listChannelDocks, g as resolveChannelGroupToolsPolicy, h as resolveChannelGroupRequireMention, i as normalizeElevatedLevel, l as resolveResponseUsageMode, m as resolveChannelGroupPolicy, n as formatXHighModelHint, o as normalizeThinkLevel, p as normalizeSignalMessagingTarget, s as normalizeUsageDisplay, t as formatThinkingLevels, u as supportsXHighThinking, v as normalizeHyphenSlug, y as normalizeStringEntries } from "./thinking-Bfk6_7EU.js"; import { n as resolveConversationLabel } from "./conversation-label-BeLJTciU.js"; import { t as resolveIMessageAccount } from "./accounts-C5646aU0.js"; import { i as resolveSessionTranscriptPath, n as resolveSessionFilePath, o as resolveSessionTranscriptsDirForAgent, r as resolveSessionFilePathOptions, s as resolveStorePath, t as resolveDefaultSessionStorePath } from "./paths-gnW-md4M.js"; import { t as emitSessionTranscriptUpdate } from "./transcript-events-CZ8CG4ht.js"; import { S as ensureOpenClawModelsJson, _ as stripMinimaxToolCallXml, a as decodeDataUrl, b as stripReasoningTagsFromText, c as extractAssistantText$1, d as extractThinkingFromTaggedText, f as formatReasoningMessage, g as stripDowngradedToolCallText, h as promoteThinkingTagsToBlocks, i as coerceImageModelConfig, l as extractAssistantThinking, m as isAssistantMessage, o as resolveProviderVisionModelFromConfig, p as inferToolMetaFromArgs, r as coerceImageAssistantText, s as minimaxUnderstandImage, u as extractThinkingFromTaggedStream, v as stripThinkingTagsFromText, x as extractTextFromChatContent, y as resolveToolDisplay } from "./image-Do9rxbj3.js"; import { a as resolveEffectiveMessagesConfig, i as resolveAckReaction, o as resolveHumanDelayConfig, r as resolveResponsePrefixTemplate, t as createReplyPrefixOptions } from "./reply-prefix-BaCBHwi7.js"; import { n as resolveMemorySearchConfig } from "./manager-D7zJM2Ly.js"; import { d as listMemoryFiles, f as normalizeExtraMemoryPaths, g as runTasksWithConcurrency } from "./sqlite-DJh2xLr6.js"; import { n as retryAsync } from "./retry-BxB_D6Pn.js"; import { a as chunkText, c as resolveChunkMode, d as isSafeFenceBreak, f as parseFenceSpans, i as chunkMarkdownTextWithMode, l as resolveTextChunkLimit, o as chunkTextWithMode, r as chunkMarkdownText, t as chunkByNewline, u as findFenceSpanAt } from "./chunk-TRVny4T1.js"; import { n as resolveMarkdownTableMode } from "./markdown-tables-DO9qAEKa.js"; import { n as fetchWithTimeout, t as bindAbortRelay } from "./fetch-timeout-DL3f_O53.js"; import { a as readResponseWithLimit, i as fetchRemoteMedia, n as getDefaultMediaLocalRoots, o as fetchWithSsrFGuard, t as getAgentScopedMediaLocalRoots } from "./local-roots-tMzVEQD2.js"; import { a as loadWebMedia, i as getDefaultLocalRoots } from "./ir-CRTCIHIG.js"; import { a as listChatCommandsForConfig, c as normalizeCommandBody, d as resolveCommandArgMenu, f as serializeCommandArgs, i as listChatCommands, l as parseCommandArgs, o as listNativeCommandSpecs, p as shouldHandleTextCommands, r as findCommandByNativeName, s as listNativeCommandSpecsForConfig, t as buildCommandTextFromArgs, u as resolveCommandArgChoices } from "./commands-registry-DqNdrksb.js"; import { c as getSkillsSnapshotVersion, d as createAsyncLock, f as readJsonFile, i as resolveSkillCommandInvocation, l as pruneExpiredPending, n as listSkillCommandsForAgents, o as getRemoteSkillEligibility, p as writeJsonAtomic, r as listSkillCommandsForWorkspace, s as ensureSkillsWatcher, t as listReservedChatSlashCommandNames, u as resolvePairingPaths } from "./skill-commands-pI2wkJrZ.js"; import { r as normalizeInboundTextNewlines, t as finalizeInboundContext } from "./inbound-context-CzKsDFGL.js"; import { _ as resolveMediaUnderstandingScope, a as resolveMediaAttachmentLocalRoots, c as loadModelCatalog, d as resolveAttachmentKind, f as buildRandomTempFilePath, g as normalizeMediaUnderstandingChatType, h as resolveTimeoutMs$1, i as resolveAutoImageModel, l as modelSupportsVision, m as resolveConcurrency, n as createMediaAttachmentCache, o as runCapability, p as registerUnhandledRejectionHandler, r as normalizeMediaAttachments, s as findModelInCatalog, t as buildProviderRegistry, v as CLI_OUTPUT_MAX_BUFFER, y as applyTemplate } from "./runner-CLSBcNny.js"; import { n as wrapFetchWithAbortSignal, t as resolveFetch } from "./fetch-DtI0mtzx.js"; import { n as recordCommandPoll, r as resetCommandPollCount } from "./command-poll-backoff-Bup9wS1y.js"; import { n as normalizePollInput } from "./polls-BX3wB_EC.js"; import { a as resolveSignalRpcContext, c as streamSignalEvents, n as sendReadReceiptSignal, o as signalCheck, r as sendTypingSignal, s as signalRpcRequest, t as sendMessageSignal } from "./send-hD-4IHpX.js"; import { a as formatIMessageChatTarget, c as parseIMessageTarget, i as DEFAULT_IMESSAGE_PROBE_TIMEOUT_MS, o as isAllowedIMessageSender, r as createIMessageRpcClient, s as normalizeIMessageHandle, t as sendMessageIMessage } from "./send-Cm_4TZEY.js"; import { n as resolveAgentRoute, t as buildAgentSessionKey } from "./resolve-route-ClURVRZM.js"; import { n as recordChannelActivity, r as createDiscordRetryRunner, t as getChannelActivity } from "./channel-activity-LT3oBvO7.js"; import { t as convertMarkdownTables } from "./tables-xDr7OSBa.js"; import { t as makeProxyFetch } from "./proxy-CBJ1upuz.js"; import { a as createReplyReferencePlanner, i as resolveSlackThreadTs, n as deliverReplies$3, t as createSlackReplyDeliveryPlan } from "./replies-BMmKlXtC.js"; import { t as getActiveWebListener } from "./active-listener-DgvMdw4N.js"; import { createRequire } from "node:module"; import * as fs$2 from "node:fs/promises"; import fs from "node:fs/promises"; import os, { homedir } from "node:os"; import * as path$1 from "node:path"; import path from "node:path"; import fs$1, { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs"; import JSON5 from "json5"; import { execFile, execFileSync, spawn, spawnSync } from "node:child_process"; import { inspect, promisify } from "node:util"; import { fileURLToPath } from "node:url"; import { CURRENT_SESSION_VERSION, DefaultResourceLoader, SessionManager, SettingsManager, codingTools, createAgentSession, createEditTool, createReadTool, createWriteTool, estimateTokens, generateSummary, readTool } from "@mariozechner/pi-coding-agent"; import crypto, { X509Certificate, randomBytes, randomUUID } from "node:crypto"; import { complete, completeSimple, streamSimple } from "@mariozechner/pi-ai"; import { EdgeTTS } from "node-edge-tts"; import AjvPkg from "ajv"; import { createServer } from "node:http"; import { ProxyAgent, fetch as fetch$1 } from "undici"; import WebSocket$1, { WebSocket } from "ws"; import { Buffer as Buffer$1 } from "node:buffer"; import { createJiti } from "jiti"; import { Type } from "@sinclair/typebox"; import readline from "node:readline"; import { Button, ChannelSelectMenu, ChannelType, Client, Command, CommandWithSubcommands, Container, MentionableSelectMenu, MessageCreateListener, MessageReactionAddListener, MessageReactionRemoveListener, MessageType, Modal, PresenceUpdateListener, ReadyListener, RoleSelectMenu, Row, Separator, StringSelectMenu, TextDisplay, UserSelectMenu, serializePayload } from "@buape/carbon"; import { ApplicationCommandOptionType, ButtonStyle, ChannelType as ChannelType$1, PermissionFlagsBits, Routes, StickerFormatType } from "discord-api-types/v10"; import { API_CONSTANTS, Bot, GrammyError, InputFile, webhookCallback } from "grammy"; import { spinner } from "@clack/prompts"; import { createOscProgressController, supportsOscProgress } from "osc-progress"; import { GatewayCloseCodes, GatewayIntents, GatewayPlugin } from "@buape/carbon/gateway"; import { VoicePlugin } from "@buape/carbon/voice"; import { AudioPlayerStatus, EndBehaviorType, VoiceConnectionStatus, createAudioPlayer, createAudioResource, entersState, joinVoiceChannel } from "@discordjs/voice"; import { HttpsProxyAgent } from "https-proxy-agent"; import { setTimeout as setTimeout$1 } from "node:timers/promises"; import { messagingApi } from "@line/bot-sdk"; import SlackBolt from "@slack/bolt"; import { run, sequentialize } from "@grammyjs/runner"; import { apiThrottler } from "@grammyjs/transformer-throttler"; import { EventEmitter } from "node:events"; //#region src/auto-reply/heartbeat.ts const HEARTBEAT_PROMPT = "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK."; const DEFAULT_HEARTBEAT_ACK_MAX_CHARS = 300; function resolveHeartbeatPrompt(raw) { return (typeof raw === "string" ? raw.trim() : "") || HEARTBEAT_PROMPT; } function stripTokenAtEdges(raw) { let text = raw.trim(); if (!text) return { text: "", didStrip: false }; const token = HEARTBEAT_TOKEN; const tokenAtEndWithOptionalTrailingPunctuation = new RegExp(`${escapeRegExp(token)}[^\\w]{0,4}$`); if (!text.includes(token)) return { text, didStrip: false }; let didStrip = false; let changed = true; while (changed) { changed = false; const next = text.trim(); if (next.startsWith(token)) { text = next.slice(token.length).trimStart(); didStrip = true; changed = true; continue; } if (tokenAtEndWithOptionalTrailingPunctuation.test(next)) { const idx = next.lastIndexOf(token); const before = next.slice(0, idx).trimEnd(); if (!before) text = ""; else text = `${before}${next.slice(idx + token.length).trimStart()}`.trimEnd(); didStrip = true; changed = true; } } return { text: text.replace(/\s+/g, " ").trim(), didStrip }; } function stripHeartbeatToken(raw, opts = {}) { if (!raw) return { shouldSkip: true, text: "", didStrip: false }; const trimmed = raw.trim(); if (!trimmed) return { shouldSkip: true, text: "", didStrip: false }; const mode = opts.mode ?? "message"; const maxAckCharsRaw = opts.maxAckChars; const parsedAckChars = typeof maxAckCharsRaw === "string" ? Number(maxAckCharsRaw) : maxAckCharsRaw; const maxAckChars = Math.max(0, typeof parsedAckChars === "number" && Number.isFinite(parsedAckChars) ? parsedAckChars : DEFAULT_HEARTBEAT_ACK_MAX_CHARS); const stripMarkup = (text) => text.replace(/<[^>]*>/g, " ").replace(/&nbsp;/gi, " ").replace(/^[*`~_]+/, "").replace(/[*`~_]+$/, ""); const trimmedNormalized = stripMarkup(trimmed); if (!(trimmed.includes(HEARTBEAT_TOKEN) || trimmedNormalized.includes(HEARTBEAT_TOKEN))) return { shouldSkip: false, text: trimmed, didStrip: false }; const strippedOriginal = stripTokenAtEdges(trimmed); const strippedNormalized = stripTokenAtEdges(trimmedNormalized); const picked = strippedOriginal.didStrip && strippedOriginal.text ? strippedOriginal : strippedNormalized; if (!picked.didStrip) return { shouldSkip: false, text: trimmed, didStrip: false }; if (!picked.text) return { shouldSkip: true, text: "", didStrip: true }; const rest = picked.text.trim(); if (mode === "heartbeat") { if (rest.length <= maxAckChars) return { shouldSkip: true, text: "", didStrip: true }; } return { shouldSkip: false, text: rest, didStrip: true }; } //#endregion //#region src/channels/allowlist-match.ts function formatAllowlistMatchMeta(match) { return `matchKey=${match?.matchKey ?? "none"} matchSource=${match?.matchSource ?? "none"}`; } //#endregion //#region src/config/channel-capabilities.ts const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string"); function normalizeCapabilities(capabilities) { if (!isStringArray(capabilities)) return; const normalized = capabilities.map((entry) => entry.trim()).filter(Boolean); return normalized.length > 0 ? normalized : void 0; } function resolveAccountCapabilities(params) { const cfg = params.cfg; if (!cfg) return; const normalizedAccountId = normalizeAccountId$3(params.accountId); const accounts = cfg.accounts; if (accounts && typeof accounts === "object") { const direct = accounts[normalizedAccountId]; if (direct) return normalizeCapabilities(direct.capabilities) ?? normalizeCapabilities(cfg.capabilities); const matchKey = Object.keys(accounts).find((key) => key.toLowerCase() === normalizedAccountId.toLowerCase()); const match = matchKey ? accounts[matchKey] : void 0; if (match) return normalizeCapabilities(match.capabilities) ?? normalizeCapabilities(cfg.capabilities); } return normalizeCapabilities(cfg.capabilities); } function resolveChannelCapabilities(params) { const cfg = params.cfg; const channel = normalizeChannelId$1(params.channel); if (!cfg || !channel) return; return resolveAccountCapabilities({ cfg: cfg.channels?.[channel] ?? cfg[channel], accountId: params.accountId }); } //#endregion //#region src/infra/machine-name.ts const execFileAsync$1 = promisify(execFile); let cachedPromise = null; async function tryScutil(key) { try { const { stdout } = await execFileAsync$1("/usr/sbin/scutil", ["--get", key], { timeout: 1e3, windowsHide: true }); const value = String(stdout ?? "").trim(); return value.length > 0 ? value : null; } catch { return null; } } function fallbackHostName() { return os.hostname().replace(/\.local$/i, "").trim() || "openclaw"; } async function getMachineDisplayName() { if (cachedPromise) return cachedPromise; cachedPromise = (async () => { if (process.env.VITEST || false) return fallbackHostName(); if (process.platform === "darwin") { const computerName = await tryScutil("ComputerName"); if (computerName) return computerName; const localHostName = await tryScutil("LocalHostName"); if (localHostName) return localHostName; } return fallbackHostName(); })(); return cachedPromise; } //#endregion //#region src/process/lanes.ts let CommandLane = /* @__PURE__ */ function(CommandLane) { CommandLane["Main"] = "main"; CommandLane["Cron"] = "cron"; CommandLane["Subagent"] = "subagent"; CommandLane["Nested"] = "nested"; return CommandLane; }({}); //#endregion //#region src/process/command-queue.ts /** * Dedicated error type thrown when a queued command is rejected because * its lane was cleared. Callers that fire-and-forget enqueued tasks can * catch (or ignore) this specific type to avoid unhandled-rejection noise. */ var CommandLaneClearedError = class extends Error { constructor(lane) { super(lane ? `Command lane "${lane}" cleared` : "Command lane cleared"); this.name = "CommandLaneClearedError"; } }; const lanes = /* @__PURE__ */ new Map(); let nextTaskId = 1; function getLaneState(lane) { const existing = lanes.get(lane); if (existing) return existing; const created = { lane, queue: [], activeTaskIds: /* @__PURE__ */ new Set(), maxConcurrent: 1, draining: false, generation: 0 }; lanes.set(lane, created); return created; } function completeTask(state, taskId, taskGeneration) { if (taskGeneration !== state.generation) return false; state.activeTaskIds.delete(taskId); return true; } function drainLane(lane) { const state = getLaneState(lane); if (state.draining) return; state.draining = true; const pump = () => { while (state.activeTaskIds.size < state.maxConcurrent && state.queue.length > 0) { const entry = state.queue.shift(); const waitedMs = Date.now() - entry.enqueuedAt; if (waitedMs >= entry.warnAfterMs) { entry.onWait?.(waitedMs, state.queue.length); diag.warn(`lane wait exceeded: lane=${lane} waitedMs=${waitedMs} queueAhead=${state.queue.length}`); } logLaneDequeue(lane, waitedMs, state.queue.length); const taskId = nextTaskId++; const taskGeneration = state.generation; state.activeTaskIds.add(taskId); (async () => { const startTime = Date.now(); try { const result = await entry.task(); if (completeTask(state, taskId, taskGeneration)) { diag.debug(`lane task done: lane=${lane} durationMs=${Date.now() - startTime} active=${state.activeTaskIds.size} queued=${state.queue.length}`); pump(); } entry.resolve(result); } catch (err) { const completedCurrentGeneration = completeTask(state, taskId, taskGeneration); if (!(lane.startsWith("auth-probe:") || lane.startsWith("session:probe-"))) diag.error(`lane task error: lane=${lane} durationMs=${Date.now() - startTime} error="${String(err)}"`); if (completedCurrentGeneration) pump(); entry.reject(err); } })(); } state.draining = false; }; pump(); } function enqueueCommandInLane(lane, task, opts) { const cleaned = lane.trim() || CommandLane.Main; const warnAfterMs = opts?.warnAfterMs ?? 2e3; const state = getLaneState(cleaned); return new Promise((resolve, reject) => { state.queue.push({ task: () => task(), resolve: (value) => resolve(value), reject, enqueuedAt: Date.now(), warnAfterMs, onWait: opts?.onWait }); logLaneEnqueue(cleaned, state.queue.length + state.activeTaskIds.size); drainLane(cleaned); }); } function getQueueSize(lane = CommandLane.Main) { const resolved = lane.trim() || CommandLane.Main; const state = lanes.get(resolved); if (!state) return 0; return state.queue.length + state.activeTaskIds.size; } function clearCommandLane(lane = CommandLane.Main) { const cleaned = lane.trim() || CommandLane.Main; const state = lanes.get(cleaned); if (!state) return 0; const removed = state.queue.length; const pending = state.queue.splice(0); for (const entry of pending) entry.reject(new CommandLaneClearedError(cleaned)); return removed; } //#endregion //#region src/utils/reaction-level.ts const LEVELS = new Set([ "off", "ack", "minimal", "extensive" ]); function parseLevel(value) { if (value === void 0 || value === null) return { kind: "missing" }; if (typeof value !== "string") return { kind: "invalid" }; const trimmed = value.trim(); if (!trimmed) return { kind: "missing" }; if (LEVELS.has(trimmed)) return { kind: "ok", value: trimmed }; return { kind: "invalid" }; } function resolveReactionLevel(params) { const parsed = parseLevel(params.value); switch (parsed.kind === "ok" ? parsed.value : parsed.kind === "missing" ? params.defaultLevel : params.invalidFallback) { case "off": return { level: "off", ackEnabled: false, agentReactionsEnabled: false }; case "ack": return { level: "ack", ackEnabled: true, agentReactionsEnabled: false }; case "minimal": return { level: "minimal", ackEnabled: false, agentReactionsEnabled: true, agentReactionGuidance: "minimal" }; case "extensive": return { level: "extensive", ackEnabled: false, agentReactionsEnabled: true, agentReactionGuidance: "extensive" }; default: return { level: "minimal", ackEnabled: false, agentReactionsEnabled: true, agentReactionGuidance: "minimal" }; } } //#endregion //#region src/signal/reaction-level.ts /** * Resolve the effective reaction level and its implications for Signal. * * Levels: * - "off": No reactions at all * - "ack": Only automatic ack reactions (๐Ÿ‘€ when processing), no agent reactions * - "minimal": Agent can react, but sparingly (default) * - "extensive": Agent can react liberally */ function resolveSignalReactionLevel(params) { return resolveReactionLevel({ value: resolveSignalAccount({ cfg: params.cfg, accountId: params.accountId }).config.reactionLevel, defaultLevel: "minimal", invalidFallback: "minimal" }); } //#endregion //#region src/telegram/inline-buttons.ts const DEFAULT_INLINE_BUTTONS_SCOPE = "allowlist"; function normalizeInlineButtonsScope(value) { if (typeof value !== "string") return; const trimmed = value.trim().toLowerCase(); if (trimmed === "off" || trimmed === "dm" || trimmed === "group" || trimmed === "all" || trimmed === "allowlist") return trimmed; } function resolveInlineButtonsScopeFromCapabilities(capabilities) { if (!capabilities) return DEFAULT_INLINE_BUTTONS_SCOPE; if (Array.isArray(capabilities)) return capabilities.some((entry) => String(entry).trim().toLowerCase() === "inlinebuttons") ? "all" : "off"; if (typeof capabilities === "object") { const inlineButtons = capabilities.inlineButtons; return normalizeInlineButtonsScope(inlineButtons) ?? DEFAULT_INLINE_BUTTONS_SCOPE; } return DEFAULT_INLINE_BUTTONS_SCOPE; } function resolveTelegramInlineButtonsScope(params) { return resolveInlineButtonsScopeFromCapabilities(resolveTelegramAccount({ cfg: params.cfg, accountId: params.accountId }).config.capabilities); } function isTelegramInlineButtonsEnabled(params) { if (params.accountId) return resolveTelegramInlineButtonsScope(params) !== "off"; const accountIds = listTelegramAccountIds(params.cfg); if (accountIds.length === 0) return resolveTelegramInlineButtonsScope(params) !== "off"; return accountIds.some((accountId) => resolveTelegramInlineButtonsScope({ cfg: params.cfg, accountId }) !== "off"); } //#endregion //#region src/telegram/reaction-level.ts /** * Resolve the effective reaction level and its implications. */ function resolveTelegramReactionLevel(params) { return resolveReactionLevel({ value: resolveTelegramAccount({ cfg: params.cfg, accountId: params.accountId }).config.reactionLevel, defaultLevel: "minimal", invalidFallback: "ack" }); } //#endregion //#region src/line/flex-templates/common.ts function attachFooterText(bubble, footer) { bubble.footer = { type: "box", layout: "vertical", contents: [{ type: "text", text: footer, size: "xs", color: "#AAAAAA", wrap: true, align: "center" }], paddingAll: "lg", backgroundColor: "#FAFAFA" }; } //#endregion //#region src/line/flex-templates/schedule-cards.ts function buildTitleSubtitleHeader(params) { const { title, subtitle } = params; const headerContents = [{ type: "text", text: title, weight: "bold", size: "xl", color: "#111111", wrap: true }]; if (subtitle) headerContents.push({ type: "text", text: subtitle, size: "sm", color: "#888888", margin: "sm", wrap: true }); return headerContents; } function buildCardHeaderSections(headerContents) { return [{ type: "box", layout: "vertical", contents: headerContents, paddingBottom: "lg" }, { type: "separator", color: "#EEEEEE" }]; } function createMegaBubbleWithFooter(params) { const bubble = { type: "bubble", size: "mega", body: { type: "box", layout: "vertical", contents: params.bodyContents, paddingAll: "xl", backgroundColor: "#FFFFFF" } }; if (params.footer) attachFooterText(bubble, params.footer); return bubble; } /** * Create a receipt/summary card (for orders, transactions, data tables) * * Editorial design: Clean table layout with alternating row backgrounds, * prominent total section, and clear visual hierarchy. */ function createReceiptCard(params) { const { title, subtitle, items, total, footer } = params; const itemRows = items.slice(0, 12).map((item, index) => ({ type: "box", layout: "horizontal", contents: [{ type: "text", text: item.name, size: "sm", color: item.highlight ? "#111111" : "#666666", weight: item.highlight ? "bold" : "regular", flex: 3, wrap: true }, { type: "text", text: item.value, size: "sm", color: item.highlight ? "#06C755" : "#333333", weight: item.highlight ? "bold" : "regular", flex: 2, align: "end", wrap: true }], paddingAll: "md", backgroundColor: index % 2 === 0 ? "#FFFFFF" : "#FAFAFA" })); const bodyContents = [...buildCardHeaderSections(buildTitleSubtitleHeader({ title, subtitle })), { type: "box", layout: "vertical", contents: itemRows, margin: "md", cornerRadius: "md", borderWidth: "light", borderColor: "#EEEEEE" }]; if (total) bodyContents.push({ type: "box", layout: "horizontal", contents: [{ type: "text", text: total.label, size: "lg", weight: "bold", color: "#111111", flex: 2 }, { type: "text", text: total.value, size: "xl", weight: "bold", color: "#06C755", flex: 2, align: "end" }], margin: "xl", paddingAll: "lg", backgroundColor: "#F0FDF4", cornerRadius: "lg" }); return createMegaBubbleWithFooter({ bodyContents, footer }); } /** * Create a calendar event card (for meetings, appointments, reminders) * * Editorial design: Date as hero, strong typographic hierarchy, * color-blocked zones, full text wrapping for readability. */ function createEventCard(params) { const { title, date, time, location, description, calendar, isAllDay, action } = params; const dateBlock = { type: "box", layout: "vertical", contents: [{ type: "text", text: date.toUpperCase(), size: "sm", weight: "bold", color: "#06C755", wrap: true }, { type: "text", text: isAllDay ? "ALL DAY" : time ?? "", size: "xxl", weight: "bold", color: "#111111", wrap: true, margin: "xs" }], paddingBottom: "lg", borderWidth: "none" }; if (!time && !isAllDay) dateBlock.contents = [{ type: "text", text: date, size: "xl", weight: "bold", color: "#111111", wrap: true }]; const bodyContents = [dateBlock, { type: "box", layout: "horizontal", contents: [{ type: "box", layout: "vertical", contents: [], width: "4px", backgroundColor: "#06C755", cornerRadius: "2px" }, { type: "box", layout: "vertical", contents: [{ type: "text", text: title, size: "lg", weight: "bold", color: "#1a1a1a", wrap: true }, ...calendar ? [{ type: "text", text: calendar, size: "xs", color: "#888888", margin: "sm", wrap: true }] : []], flex: 1, paddingStart: "lg" }], paddingTop: "lg", paddingBottom: "lg", borderWidth: "light", borderColor: "#EEEEEE" }]; if (location || description) { const detailItems = []; if (location) detailItems.push({ type: "box", layout: "horizontal", contents: [{ type: "text", text: "๐Ÿ“", size: "sm", flex: 0 }, { type: "text", text: location, size: "sm", color: "#444444", margin: "md", flex: 1, wrap: true }], alignItems: "flex-start" }); if (description) detailItems.push({ type: "text", text: description, size: "sm", color: "#666666", wrap: true, margin: location ? "lg" : "none" }); bodyContents.push({ type: "box", layout: "vertical", contents: detailItems, margin: "lg", paddingAll: "lg", backgroundColor: "#F8F9FA", cornerRadius: "lg" }); } return { type: "bubble", size: "mega", body: { type: "box", layout: "vertical", contents: bodyContents, paddingAll: "xl", backgroundColor: "#FFFFFF", action } }; } /** * Create a calendar agenda card showing multiple events * * Editorial timeline design: Time-focused left column with event details * on the right. Visual accent bars indicate event priority/recency. */ function createAgendaCard(params) { const { title, subtitle, events, footer } = params; const headerContents = buildTitleSubtitleHeader({ title, subtitle }); const eventItems = events.slice(0, 6).map((event, index) => { const isActive = event.isNow || index === 0; const accentColor = isActive ? "#06C755" : "#E5E5E5"; const timeColumn = { type: "box", layout: "vertical", contents: [{ type: "text", text: event.time ?? "โ€”", size: "sm", weight: isActive ? "bold" : "regular", color: isActive ? "#06C755" : "#666666", align: "end", wrap: true }], width: "65px", justifyContent: "flex-start" }; const dotColumn = { type: "box", layout: "vertical", contents: [{ type: "box", layout: "vertical", contents: [], width: "10px", height: "10px", backgroundColor: accentColor, cornerRadius: "5px" }], width: "24px", alignItems: "center", justifyContent: "flex-start", paddingTop: "xs" }; const detailContents = [{ type: "text", text: event.title, size: "md", weight: "bold", color: "#1a1a1a", wrap: true }]; const secondaryParts = []; if (event.location) secondaryParts.push(event.location); if (event.calendar) secondaryParts.push(event.calendar); if (secondaryParts.length > 0) detailContents.push({ type: "text", text: secondaryParts.join(" ยท "), size: "xs", color: "#888888", wrap: true, margin: "xs" }); return { type: "box", layout: "horizontal", contents: [ timeColumn, dotColumn, { type: "box", layout: "vertical", contents: detailContents, flex: 1 } ], margin: index > 0 ? "xl" : void 0, alignItems: "flex-start" }; }); return createMegaBubbleWithFooter({ bodyContents: [...buildCardHeaderSections(headerContents), { type: "box", layout: "vertical", contents: eventItems, paddingTop: "xl" }], footer }); } //#endregion //#region src/line/flex-templates/media-control-cards.ts /** * Create a media player card for Sonos, Spotify, Apple Music, etc. * * Editorial design: Album art hero with gradient overlay for text, * prominent now-playing indicator, refined playback controls. */ function createMediaPlayerCard(params) { const { title, subtitle, source, imageUrl, isPlaying, progress, controls, extraActions } = params; const trackInfo = [{ type: "text", text: title, weight: "bold", size: "xl", color: "#111111", wrap: true }]; if (subtitle) trackInfo.push({ type: "text", text: subtitle, size: "md", color: "#666666", wrap: true, margin: "sm" }); const statusItems = []; if (isPlaying !== void 0) statusItems.push({ type: "box", layout: "horizontal", contents: [{ type: "box", layout: "vertical", contents: [], width: "8px", height: "8px", backgroundColor: isPlaying ? "#06C755" : "#CCCCCC", cornerRadius: "4px" }, { type: "text", text: isPlaying ? "Now Playing" : "Paused", size: "xs", color: isPlaying ? "#06C755" : "#888888", weight: "bold", margin: "sm" }], alignItems: "center" }); if (source) statusItems.push({ type: "text", text: source, size: "xs", color: "#AAAAAA", margin: statusItems.length > 0 ? "lg" : void 0 }); if (progress) statusItems.push({ type: "text", text: progress, size: "xs", color: "#888888", align: "end", flex: 1 }); const bodyContents = [{ type: "box", layout: "vertical", contents: trackInfo }]; if (statusItems.length > 0) bodyContents.push({ type: "box", layout: "horizontal", contents: statusItems, margin: "lg", alignItems: "center" }); const bubble = { type: "bubble", size: "mega", body: { type: "box", layout: "vertical", contents: bodyContents, paddingAll: "xl", backgroundColor: "#FFFFFF" } }; if (imageUrl) bubble.hero = { type: "image", url: imageUrl, size: "full", aspectRatio: "1:1", aspectMode: "cover" }; if (controls || extraActions?.length) { const footerContents = []; if (controls) { const controlButtons = []; if (controls.previous) controlButtons.push({ type: "button", action: { type: "postback", label: "โฎ", data: controls.previous.data }, style: "secondary", flex: 1, height: "sm" }); if (controls.play) controlButtons.push({ type: "button", action: { type: "postback", label: "โ–ถ", data: controls.play.data }, style: isPlaying ? "secondary" : "primary", flex: 1, height: "sm", margin: controls.previous ? "md" : void 0 }); if (controls.pause) controlButtons.push({ type: "button", action: { type: "postback", label: "โธ", data: controls.pause.data }, style: isPlaying ? "primary" : "secondary", flex: 1, height: "sm", margin: controlButtons.length > 0 ? "md" : void 0 }); if (controls.next) controlButtons.push({ type: "button", action: { type: "postback", label: "โญ", data: controls.next.data }, style: "secondary", flex: 1, height: "sm", margin: controlButtons.length > 0 ? "md" : void 0 }); if (controlButtons.length > 0) footerContents.push({ type: "box", layout: "horizontal", contents: controlButtons }); } if (extraActions?.length) footerContents.push({ type: "box", layout: "horizontal", contents: extraActions.slice(0, 2).map((action, index) => ({ type: "button", action: { type: "postback", label: action.label.slice(0, 15), data: action.data }, style: "secondary", flex: 1, height: "sm", margin: index > 0 ? "md" : void 0 })), margin: "md" }); if (footerContents.length > 0) bubble.footer = { type: "box", layout: "vertical", contents: footerContents, paddingAll: "lg", backgroundColor: "#FAFAFA" }; } return bubble; } /** * Create an Apple TV remote card with a D-pad and control rows. */ function createAppleTvRemoteCard(params) { const { deviceName, status, actionData } = params; const headerContents = [{ type: "text", text: deviceName, weight: "bold", size: "xl", color: "#111111", wrap: true }]; if (status) headerContents.push({ type: "text", text: status, size: "sm", colo