@gguf/claw
Version:
Multi-channel AI gateway with extensible messaging integrations
1,063 lines (1,050 loc) โข 2.66 MB
JavaScript
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(/ /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