"use strict";Object.defineProperty(exports, "__esModule", { value: true });Object.defineProperty(exports, "ACP_ERROR_CODES", { enumerable: true, get: function () {return _dispatchF_Zbttj.fn;} });Object.defineProperty(exports, "AcpRuntimeError", { enumerable: true, get: function () {return _dispatchF_Zbttj.pn;} });exports.AllowFromEntrySchema = void 0;Object.defineProperty(exports, "BLUEBUBBLES_ACTIONS", { enumerable: true, get: function () {return _dispatchF_Zbttj.bn;} });Object.defineProperty(exports, "BLUEBUBBLES_ACTION_NAMES", { enumerable: true, get: function () {return _dispatchF_Zbttj.xn;} });Object.defineProperty(exports, "BLUEBUBBLES_GROUP_ACTIONS", { enumerable: true, get: function () {return _dispatchF_Zbttj.Sn;} });Object.defineProperty(exports, "BlockStreamingCoalesceSchema", { enumerable: true, get: function () {return _configDiiPndBn.A;} });Object.defineProperty(exports, "CHANNEL_MESSAGE_ACTION_NAMES", { enumerable: true, get: function () {return _dispatchF_Zbttj.Cn;} });Object.defineProperty(exports, "DEFAULT_ACCOUNT_ID", { enumerable: true, get: function () {return _runWithConcurrency2ga3CMk.lt;} });Object.defineProperty(exports, "DEFAULT_GROUP_HISTORY_LIMIT", { enumerable: true, get: function () {return _dispatchF_Zbttj.F;} });Object.defineProperty(exports, "DEFAULT_WEBHOOK_BODY_TIMEOUT_MS", { enumerable: true, get: function () {return _dispatchF_Zbttj.Xt;} });Object.defineProperty(exports, "DEFAULT_WEBHOOK_MAX_BODY_BYTES", { enumerable: true, get: function () {return _dispatchF_Zbttj.Zt;} });Object.defineProperty(exports, "DM_GROUP_ACCESS_REASON", { enumerable: true, get: function () {return _dispatchF_Zbttj.Bt;} });Object.defineProperty(exports, "DiscordConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.f;} });Object.defineProperty(exports, "DmConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.j;} });Object.defineProperty(exports, "DmPolicySchema", { enumerable: true, get: function () {return _configDiiPndBn.M;} });Object.defineProperty(exports, "GROUP_POLICY_BLOCKED_LABEL", { enumerable: true, get: function () {return _sendDPZOoQ.At;} });Object.defineProperty(exports, "GoogleChatConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.p;} });Object.defineProperty(exports, "GroupPolicySchema", { enumerable: true, get: function () {return _configDiiPndBn.N;} });Object.defineProperty(exports, "IMessageConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.m;} });Object.defineProperty(exports, "KeyedAsyncQueue", { enumerable: true, get: function () {return _dispatchF_Zbttj.in;} });exports.LineConfigSchema = void 0;Object.defineProperty(exports, "MSTeamsConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.h;} });Object.defineProperty(exports, "MarkdownConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.P;} });Object.defineProperty(exports, "MarkdownTableModeSchema", { enumerable: true, get: function () {return _configDiiPndBn.F;} });exports.PAIRING_APPROVED_MESSAGE = void 0;Object.defineProperty(exports, "ReplyRuntimeConfigSchemaShape", { enumerable: true, get: function () {return _configDiiPndBn.I;} });Object.defineProperty(exports, "RequestBodyLimitError", { enumerable: true, get: function () {return _dispatchF_Zbttj.Qt;} });Object.defineProperty(exports, "SILENT_REPLY_TOKEN", { enumerable: true, get: function () {return _tokensCgeKcoW.n;} });Object.defineProperty(exports, "SecretInputSchema", { enumerable: true, get: function () {return _configDiiPndBn.L;} });Object.defineProperty(exports, "SignalConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.g;} });Object.defineProperty(exports, "SlackConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn._;} });Object.defineProperty(exports, "SsrFBlockedError", { enumerable: true, get: function () {return _ssrfD6FSPiLK.t;} });Object.defineProperty(exports, "TelegramConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.v;} });Object.defineProperty(exports, "ToolPolicySchema", { enumerable: true, get: function () {return _configDiiPndBn.k;} });Object.defineProperty(exports, "TtsAutoSchema", { enumerable: true, get: function () {return _configDiiPndBn.R;} });Object.defineProperty(exports, "TtsConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.z;} });Object.defineProperty(exports, "TtsModeSchema", { enumerable: true, get: function () {return _configDiiPndBn.B;} });Object.defineProperty(exports, "TtsProviderSchema", { enumerable: true, get: function () {return _configDiiPndBn.V;} });exports.WEBHOOK_RATE_LIMIT_DEFAULTS = exports.WEBHOOK_IN_FLIGHT_DEFAULTS = exports.WEBHOOK_BODY_READ_DEFAULTS = exports.WEBHOOK_ANOMALY_STATUS_CODES = exports.WEBHOOK_ANOMALY_COUNTER_DEFAULTS = void 0;Object.defineProperty(exports, "WhatsAppConfigSchema", { enumerable: true, get: function () {return _configDiiPndBn.d;} });Object.defineProperty(exports, "acquireFileLock", { enumerable: true, get: function () {return _configDiiPndBn.Fr;} });exports.addWildcardAllowFrom = addWildcardAllowFrom;exports.applyAccountNameToChannelSection = applyAccountNameToChannelSection;exports.applyBasicWebhookRequestGuards = applyBasicWebhookRequestGuards;Object.defineProperty(exports, "applyWindowsSpawnProgramPolicy", { enumerable: true, get: function () {return _windowsSpawnCpTF7CWy.t;} });Object.defineProperty(exports, "approveDevicePairing", { enumerable: true, get: function () {return _dispatchF_Zbttj.yt;} });Object.defineProperty(exports, "assertSecretInputResolved", { enumerable: true, get: function () {return _configDiiPndBn.Gr;} });Object.defineProperty(exports, "autoBindSpawnedDiscordSubagent", { enumerable: true, get: function () {return _dispatchF_Zbttj.mn;} });exports.beginWebhookRequestPipelineOrReject = beginWebhookRequestPipelineOrReject;exports.buildAccountScopedDmSecurityPolicy = buildAccountScopedDmSecurityPolicy;exports.buildAgentMediaPayload = buildAgentMediaPayload;exports.buildBaseAccountStatusSnapshot = buildBaseAccountStatusSnapshot;exports.buildBaseChannelStatusSummary = buildBaseChannelStatusSummary;exports.buildCatchallMultiAccountChannelSchema = buildCatchallMultiAccountChannelSchema;exports.buildChannelConfigSchema = buildChannelConfigSchema;Object.defineProperty(exports, "buildChannelKeyCandidates", { enumerable: true, get: function () {return _sendDPZOoQ.Bt;} });exports.buildChannelSendResult = buildChannelSendResult;exports.buildComputedAccountStatusSnapshot = buildComputedAccountStatusSnapshot;exports.buildDiscordSendMediaOptions = buildDiscordSendMediaOptions;exports.buildDiscordSendOptions = buildDiscordSendOptions;exports.buildHostnameAllowlistPolicyFromSuffixAllowlist = buildHostnameAllowlistPolicyFromSuffixAllowlist;exports.buildInboundReplyDispatchBase = buildInboundReplyDispatchBase;Object.defineProperty(exports, "buildMediaPayload", { enumerable: true, get: function () {return _dispatchF_Zbttj.U;} });exports.buildOauthProviderAuthResult = buildOauthProviderAuthResult;exports.buildOpenGroupPolicyConfigureRouteAllowlistWarning = buildOpenGroupPolicyConfigureRouteAllowlistWarning;exports.buildOpenGroupPolicyNoRouteAllowlistWarning = buildOpenGroupPolicyNoRouteAllowlistWarning;exports.buildOpenGroupPolicyRestrictSendersWarning = buildOpenGroupPolicyRestrictSendersWarning;exports.buildOpenGroupPolicyWarning = buildOpenGroupPolicyWarning;Object.defineProperty(exports, "buildPendingHistoryContextFromMap", { enumerable: true, get: function () {return _dispatchF_Zbttj.L;} });exports.buildProbeChannelStatusSummary = buildProbeChannelStatusSummary;Object.defineProperty(exports, "buildRandomTempFilePath", { enumerable: true, get: function () {return _audioTranscriptionRunnerC72KQQVh.d;} });exports.buildRuntimeAccountStatusSnapshot = buildRuntimeAccountStatusSnapshot;Object.defineProperty(exports, "buildSlackThreadingToolContext", { enumerable: true, get: function () {return _thinkingCfIPyoMg.N;} });exports.buildTokenChannelStatusSummary = buildTokenChannelStatusSummary;exports.chunkTextForOutbound = chunkTextForOutbound;Object.defineProperty(exports, "clamp", { enumerable: true, get: function () {return _loggerU3s76KST.m;} });Object.defineProperty(exports, "clearAccountEntryFields", { enumerable: true, get: function () {return _pluginsBhm3N6Y.ot;} });Object.defineProperty(exports, "clearHistoryEntries", { enumerable: true, get: function () {return _dispatchF_Zbttj.R;} });Object.defineProperty(exports, "clearHistoryEntriesIfEnabled", { enumerable: true, get: function () {return _dispatchF_Zbttj.z;} });exports.collectAllowlistProviderGroupPolicyWarnings = collectAllowlistProviderGroupPolicyWarnings;exports.collectAllowlistProviderRestrictSendersWarnings = collectAllowlistProviderRestrictSendersWarnings;exports.collectBlueBubblesStatusIssues = collectBlueBubblesStatusIssues;Object.defineProperty(exports, "collectDiscordAuditChannelIds", { enumerable: true, get: function () {return _dispatchF_Zbttj.W;} });exports.collectDiscordStatusIssues = collectDiscordStatusIssues;exports.collectOpenGroupPolicyConfiguredRouteWarnings = collectOpenGroupPolicyConfiguredRouteWarnings;exports.collectOpenGroupPolicyRestrictSendersWarnings = collectOpenGroupPolicyRestrictSendersWarnings;exports.collectOpenGroupPolicyRouteAllowlistWarnings = collectOpenGroupPolicyRouteAllowlistWarnings;exports.collectOpenProviderGroupPolicyWarnings = collectOpenProviderGroupPolicyWarnings;exports.collectStatusIssuesFromLastError = collectStatusIssuesFromLastError;exports.collectTelegramStatusIssues = collectTelegramStatusIssues;exports.collectWhatsAppStatusIssues = collectWhatsAppStatusIssues;Object.defineProperty(exports, "createAccountListHelpers", { enumerable: true, get: function () {return _accountsBFBjizxh.b;} });exports.createActionCard = createActionCard;Object.defineProperty(exports, "createActionGate", { enumerable: true, get: function () {return _targetErrorsByT48YHg.o;} });Object.defineProperty(exports, "createAllowedChatSenderMatcher", { enumerable: true, get: function () {return _sendBlv_6HQ.c;} });exports.createBoundedCounter = createBoundedCounter;Object.defineProperty(exports, "createDedupeCache", { enumerable: true, get: function () {return _dispatchF_Zbttj.ot;} });exports.createDefaultChannelRuntimeState = createDefaultChannelRuntimeState;exports.createFixedWindowRateLimiter = createFixedWindowRateLimiter;exports.createImageCard = createImageCard;exports.createInboundEnvelopeBuilder = createInboundEnvelopeBuilder;exports.createInfoCard = createInfoCard;exports.createListCard = createListCard;exports.createLoggerBackedRuntime = createLoggerBackedRuntime;exports.createNormalizedOutboundDeliverer = createNormalizedOutboundDeliverer;exports.createPersistentDedupe = createPersistentDedupe;exports.createPluginRuntimeStore = createPluginRuntimeStore;Object.defineProperty(exports, "createReceiptCard", { enumerable: true, get: function () {return _dispatchF_Zbttj.At;} });Object.defineProperty(exports, "createReplyPrefixContext", { enumerable: true, get: function () {return _dispatchF_Zbttj.A;} });Object.defineProperty(exports, "createReplyPrefixOptions", { enumerable: true, get: function () {return _dispatchF_Zbttj.j;} });Object.defineProperty(exports, "createScopedAccountConfigAccessors", { enumerable: true, get: function () {return _pluginsBhm3N6Y.B;} });Object.defineProperty(exports, "createScopedChannelConfigBase", { enumerable: true, get: function () {return _pluginsBhm3N6Y.V;} });exports.createScopedPairingAccess = createScopedPairingAccess;Object.defineProperty(exports, "createTypingCallbacks", { enumerable: true, get: function () {return _dispatchF_Zbttj.k;} });exports.createWebhookAnomalyTracker = createWebhookAnomalyTracker;exports.createWebhookInFlightLimiter = createWebhookInFlightLimiter;Object.defineProperty(exports, "deleteAccountFromConfigSection", { enumerable: true, get: function () {return _pluginsBhm3N6Y.st;} });Object.defineProperty(exports, "detectMime", { enumerable: true, get: function () {return _imageOpsZjRT9yvG.c;} });exports.discordOnboardingAdapter = void 0;exports.dispatchInboundReplyWithBase = dispatchInboundReplyWithBase;exports.dispatchReplyFromConfigWithSettledDispatcher = dispatchReplyFromConfigWithSettledDispatcher;Object.defineProperty(exports, "emitDiagnosticEvent", { enumerable: true, get: function () {return _diagnosticCKfPvpU.m;} });exports.emptyPluginConfigSchema = emptyPluginConfigSchema;Object.defineProperty(exports, "enqueueKeyedTask", { enumerable: true, get: function () {return _dispatchF_Zbttj.an;} });Object.defineProperty(exports, "escapeRegExp", { enumerable: true, get: function () {return _loggerU3s76KST.v;} });Object.defineProperty(exports, "evaluateGroupRouteAccessForPolicy", { enumerable: true, get: function () {return _sendDPZOoQ.Tt;} });Object.defineProperty(exports, "evaluateMatchedGroupAccessForPolicy", { enumerable: true, get: function () {return _sendDPZOoQ.Et;} });Object.defineProperty(exports, "evaluateSenderGroupAccess", { enumerable: true, get: function () {return _sendDPZOoQ.Dt;} });Object.defineProperty(exports, "evaluateSenderGroupAccessForPolicy", { enumerable: true, get: function () {return _sendDPZOoQ.Ot;} });Object.defineProperty(exports, "evictOldHistoryKeys", { enumerable: true, get: function () {return _dispatchF_Zbttj.B;} });Object.defineProperty(exports, "extensionForMime", { enumerable: true, get: function () {return _imageOpsZjRT9yvG.l;} });Object.defineProperty(exports, "extractOriginalFilename", { enumerable: true, get: function () {return _storeBfiJnRiX.r;} });exports.extractSlackToolSend = extractSlackToolSend;Object.defineProperty(exports, "extractToolSend", { enumerable: true, get: function () {return _dispatchF_Zbttj.Mt;} });exports.fetchWithBearerAuthScopeFallback = fetchWithBearerAuthScopeFallback;Object.defineProperty(exports, "fetchWithSsrFGuard", { enumerable: true, get: function () {return _fetchGuardBMQY_BjF.t;} });Object.defineProperty(exports, "formatAllowFromLowercase", { enumerable: true, get: function () {return _allowFromCfbQs9EO.t;} });Object.defineProperty(exports, "formatAllowlistMatchMeta", { enumerable: true, get: function () {return _dispatchF_Zbttj._n;} });Object.defineProperty(exports, "formatDocsLink", { enumerable: true, get: function () {return _dispatchF_Zbttj.f;} });Object.defineProperty(exports, "formatErrorMessage", { enumerable: true, get: function () {return _errorsDR1SiaHP.r;} });Object.defineProperty(exports, "formatInboundFromLabel", { enumerable: true, get: function () {return _dispatchF_Zbttj.It;} });Object.defineProperty(exports, "formatLocationText", { enumerable: true, get: function () {return _sendXbYokfdQ.Y;} });Object.defineProperty(exports, "formatNormalizedAllowFromEntries", { enumerable: true, get: function () {return _allowFromCfbQs9EO.n;} });exports.formatPairingApproveHint = formatPairingApproveHint;exports.formatResolvedUnresolvedNote = formatResolvedUnresolvedNote;exports.formatTextWithAttachmentLinks = formatTextWithAttachmentLinks;Object.defineProperty(exports, "formatTrimmedAllowFromEntries", { enumerable: true, get: function () {return _pluginsBhm3N6Y.H;} });Object.defineProperty(exports, "formatUtcTimestamp", { enumerable: true, get: function () {return _dispatchF_Zbttj.Lt;} });Object.defineProperty(exports, "formatWhatsAppConfigAllowFromEntries", { enumerable: true, get: function () {return _pluginsBhm3N6Y.U;} });Object.defineProperty(exports, "formatZonedTimestamp", { enumerable: true, get: function () {return _dispatchF_Zbttj.Rt;} });exports.generatePkceVerifierChallenge = generatePkceVerifierChallenge;Object.defineProperty(exports, "getAcpRuntimeBackend", { enumerable: true, get: function () {return _dispatchF_Zbttj.cn;} });Object.defineProperty(exports, "getChatChannelMeta", { enumerable: true, get: function () {return _configDiiPndBn.St;} });Object.defineProperty(exports, "getFileExtension", { enumerable: true, get: function () {return _imageOpsZjRT9yvG.u;} });exports.handleSlackMessageAction = handleSlackMessageAction;Object.defineProperty(exports, "hasConfiguredSecretInput", { enumerable: true, get: function () {return _configDiiPndBn.qr;} });Object.defineProperty(exports, "hasMarkdownToConvert", { enumerable: true, get: function () {return _dispatchF_Zbttj.Dt;} });exports.imessageOnboardingAdapter = void 0;Object.defineProperty(exports, "inspectDiscordAccount", { enumerable: true, get: function () {return _pluginsBhm3N6Y.lt;} });Object.defineProperty(exports, "inspectSlackAccount", { enumerable: true, get: function () {return _pluginsBhm3N6Y.M;} });Object.defineProperty(exports, "inspectTelegramAccount", { enumerable: true, get: function () {return _pluginsBhm3N6Y.y;} });Object.defineProperty(exports, "installRequestBodyLimitGuard", { enumerable: true, get: function () {return _dispatchF_Zbttj.$t;} });Object.defineProperty(exports, "isAllowedParsedChatSender", { enumerable: true, get: function () {return _allowFromCfbQs9EO.r;} });Object.defineProperty(exports, "isBlockedHostname", { enumerable: true, get: function () {return _ssrfD6FSPiLK.i;} });Object.defineProperty(exports, "isBlockedHostnameOrIp", { enumerable: true, get: function () {return _ssrfD6FSPiLK.a;} });Object.defineProperty(exports, "isDangerousNameMatchingEnabled", { enumerable: true, get: function () {return _dispatchF_Zbttj.on;} });Object.defineProperty(exports, "isDiagnosticsEnabled", { enumerable: true, get: function () {return _diagnosticCKfPvpU.h;} });exports.isHttpsUrlAllowedByHostnameSuffixAllowlist = isHttpsUrlAllowedByHostnameSuffixAllowlist;exports.isJsonContentType = isJsonContentType;Object.defineProperty(exports, "isNormalizedSenderAllowed", { enumerable: true, get: function () {return _allowFromCfbQs9EO.i;} });exports.isNumericTargetId = isNumericTargetId;Object.defineProperty(exports, "isPrivateIpAddress", { enumerable: true, get: function () {return _ssrfD6FSPiLK.o;} });Object.defineProperty(exports, "isRequestBodyLimitError", { enumerable: true, get: function () {return _dispatchF_Zbttj.en;} });Object.defineProperty(exports, "isSecretRef", { enumerable: true, get: function () {return _configDiiPndBn.Jr;} });Object.defineProperty(exports, "isSilentReplyText", { enumerable: true, get: function () {return _tokensCgeKcoW.i;} });Object.defineProperty(exports, "isTruthyEnvValue", { enumerable: true, get: function () {return _configDiiPndBn.si;} });Object.defineProperty(exports, "isWSL2Sync", { enumerable: true, get: function () {return _sendXbYokfdQ.y;} });Object.defineProperty(exports, "isWSLEnv", { enumerable: true, get: function () {return _sendXbYokfdQ.b;} });Object.defineProperty(exports, "isWSLSync", { enumerable: true, get: function () {return _sendXbYokfdQ.x;} });Object.defineProperty(exports, "isWhatsAppGroupJid", { enumerable: true, get: function () {return _pluginsBhm3N6Y.it;} });Object.defineProperty(exports, "issuePairingChallenge", { enumerable: true, get: function () {return _dispatchF_Zbttj.Nt;} });Object.defineProperty(exports, "jsonResult", { enumerable: true, get: function () {return _targetErrorsByT48YHg.l;} });exports.keepHttpServerTaskAlive = keepHttpServerTaskAlive;Object.defineProperty(exports, "listConfiguredAccountIds", { enumerable: true, get: function () {return _pluginsBhm3N6Y.A;} });Object.defineProperty(exports, "listDevicePairing", { enumerable: true, get: function () {return _dispatchF_Zbttj.bt;} });exports.listDirectoryGroupEntriesFromMapKeys = listDirectoryGroupEntriesFromMapKeys;exports.listDirectoryGroupEntriesFromMapKeysAndAllowFrom = listDirectoryGroupEntriesFromMapKeysAndAllowFrom;exports.listDirectoryUserEntriesFromAllowFrom = listDirectoryUserEntriesFromAllowFrom;exports.listDirectoryUserEntriesFromAllowFromAndMapKeys = listDirectoryUserEntriesFromAllowFromAndMapKeys;Object.defineProperty(exports, "listDiscordAccountIds", { enumerable: true, get: function () {return _pluginsBhm3N6Y.dt;} });Object.defineProperty(exports, "listDiscordDirectoryGroupsFromConfig", { enumerable: true, get: function () {return _pluginsBhm3N6Y.i;} });Object.defineProperty(exports, "listDiscordDirectoryPeersFromConfig", { enumerable: true, get: function () {return _pluginsBhm3N6Y.a;} });Object.defineProperty(exports, "listEnabledSlackAccounts", { enumerable: true, get: function () {return _pluginsBhm3N6Y.N;} });Object.defineProperty(exports, "listIMessageAccountIds", { enumerable: true, get: function () {return _pluginsBhm3N6Y.X;} });Object.defineProperty(exports, "listLineAccountIds", { enumerable: true, get: function () {return _dispatchF_Zbttj._;} });Object.defineProperty(exports, "listSignalAccountIds", { enumerable: true, get: function () {return _accountsCx0R0Kpq.n;} });Object.defineProperty(exports, "listSkillCommandsForAgents", { enumerable: true, get: function () {return _skillCommandsD9AhwcyN.n;} });Object.defineProperty(exports, "listSlackAccountIds", { enumerable: true, get: function () {return _pluginsBhm3N6Y.P;} });Object.defineProperty(exports, "listSlackDirectoryGroupsFromConfig", { enumerable: true, get: function () {return _pluginsBhm3N6Y.o;} });Object.defineProperty(exports, "listSlackDirectoryPeersFromConfig", { enumerable: true, get: function () {return _pluginsBhm3N6Y.s;} });exports.listSlackMessageActions = listSlackMessageActions;Object.defineProperty(exports, "listTelegramAccountIds", { enumerable: true, get: function () {return _pluginsBhm3N6Y.S;} });Object.defineProperty(exports, "listTelegramDirectoryGroupsFromConfig", { enumerable: true, get: function () {return _pluginsBhm3N6Y.c;} });Object.defineProperty(exports, "listTelegramDirectoryPeersFromConfig", { enumerable: true, get: function () {return _pluginsBhm3N6Y.l;} });Object.defineProperty(exports, "listThreadBindingsBySessionKey", { enumerable: true, get: function () {return _dispatchF_Zbttj.hn;} });Object.defineProperty(exports, "listWhatsAppAccountIds", { enumerable: true, get: function () {return _accountsBFBjizxh.n;} });Object.defineProperty(exports, "listWhatsAppDirectoryGroupsFromConfig", { enumerable: true, get: function () {return _pluginsBhm3N6Y.u;} });Object.defineProperty(exports, "listWhatsAppDirectoryPeersFromConfig", { enumerable: true, get: function () {return _pluginsBhm3N6Y.d;} });exports.loadOutboundMediaFromUrl = loadOutboundMediaFromUrl;Object.defineProperty(exports, "loadWebMedia", { enumerable: true, get: function () {return _irKp5uANes.v;} });Object.defineProperty(exports, "logAckFailure", { enumerable: true, get: function () {return _dispatchF_Zbttj.M;} });Object.defineProperty(exports, "logInboundDrop", { enumerable: true, get: function () {return _dispatchF_Zbttj.N;} });Object.defineProperty(exports, "logTypingFailure", { enumerable: true, get: function () {return _dispatchF_Zbttj.P;} });exports.looksLikeDiscordTargetId = looksLikeDiscordTargetId;exports.looksLikeIMessageTargetId = looksLikeIMessageTargetId;Object.defineProperty(exports, "looksLikeSignalTargetId", { enumerable: true, get: function () {return _thinkingCfIPyoMg.h;} });Object.defineProperty(exports, "looksLikeSlackTargetId", { enumerable: true, get: function () {return _pluginsBhm3N6Y.f;} });exports.looksLikeTelegramTargetId = looksLikeTelegramTargetId;Object.defineProperty(exports, "looksLikeWhatsAppTargetId", { enumerable: true, get: function () {return _pluginsBhm3N6Y.$;} });Object.defineProperty(exports, "mapAllowFromEntries", { enumerable: true, get: function () {return _pluginsBhm3N6Y.W;} });exports.mapAllowlistResolutionInputs = mapAllowlistResolutionInputs;exports.mapBasicAllowlistResolutionEntries = mapBasicAllowlistResolutionEntries;Object.defineProperty(exports, "materializeWindowsSpawnProgram", { enumerable: true, get: function () {return _windowsSpawnCpTF7CWy.n;} });exports.mergeAllowFromEntries = mergeAllowFromEntries;Object.defineProperty(exports, "mergeAllowlist", { enumerable: true, get: function () {return _dispatchF_Zbttj.w;} });exports.migrateBaseNameToDefaultAccount = migrateBaseNameToDefaultAccount;Object.defineProperty(exports, "missingTargetError", { enumerable: true, get: function () {return _targetErrorsByT48YHg.n;} });Object.defineProperty(exports, "normalizeAccountId", { enumerable: true, get: function () {return _runWithConcurrency2ga3CMk.ut;} });Object.defineProperty(exports, "normalizeAgentId", { enumerable: true, get: function () {return _runWithConcurrency2ga3CMk.rt;} });Object.defineProperty(exports, "normalizeAllowFrom", { enumerable: true, get: function () {return _configDiiPndBn.H;} });Object.defineProperty(exports, "normalizeChannelSlug", { enumerable: true, get: function () {return _sendDPZOoQ.Vt;} });exports.normalizeDiscordMessagingTarget = normalizeDiscordMessagingTarget;exports.normalizeDiscordOutboundTarget = normalizeDiscordOutboundTarget;Object.defineProperty(exports, "normalizeE164", { enumerable: true, get: function () {return _loggerU3s76KST.C;} });exports.normalizeHostnameSuffixAllowlist = normalizeHostnameSuffixAllowlist;exports.normalizeIMessageMessagingTarget = normalizeIMessageMessagingTarget;Object.defineProperty(exports, "normalizeLineAccountId", { enumerable: true, get: function () {return _dispatchF_Zbttj.v;} });exports.normalizeOutboundReplyPayload = normalizeOutboundReplyPayload;Object.defineProperty(exports, "normalizePluginHttpPath", { enumerable: true, get: function () {return _configDiiPndBn.Pt;} });Object.defineProperty(exports, "normalizeResolvedSecretInputString", { enumerable: true, get: function () {return _configDiiPndBn.Xr;} });Object.defineProperty(exports, "normalizeSecretInputString", { enumerable: true, get: function () {return _configDiiPndBn.Zr;} });Object.defineProperty(exports, "normalizeSignalMessagingTarget", { enumerable: true, get: function () {return _thinkingCfIPyoMg.g;} });Object.defineProperty(exports, "normalizeSlackMessagingTarget", { enumerable: true, get: function () {return _pluginsBhm3N6Y.p;} });exports.normalizeTelegramMessagingTarget = normalizeTelegramMessagingTarget;exports.normalizeWebhookPath = normalizeWebhookPath;Object.defineProperty(exports, "normalizeWhatsAppAllowFromEntries", { enumerable: true, get: function () {return _pluginsBhm3N6Y.et;} });Object.defineProperty(exports, "normalizeWhatsAppMessagingTarget", { enumerable: true, get: function () {return _pluginsBhm3N6Y.tt;} });Object.defineProperty(exports, "normalizeWhatsAppTarget", { enumerable: true, get: function () {return _pluginsBhm3N6Y.at;} });Object.defineProperty(exports, "onDiagnosticEvent", { enumerable: true, get: function () {return _diagnosticCKfPvpU.g;} });Object.defineProperty(exports, "optionalStringEnum", { enumerable: true, get: function () {return _dispatchF_Zbttj.ft;} });Object.defineProperty(exports, "parseChatAllowTargetPrefixes", { enumerable: true, get: function () {return _sendBlv_6HQ.l;} });Object.defineProperty(exports, "parseChatTargetPrefixesOrThrow", { enumerable: true, get: function () {return _sendBlv_6HQ.u;} });Object.defineProperty(exports, "parseTelegramReplyToMessageId", { enumerable: true, get: function () {return _dispatchF_Zbttj.lt;} });Object.defineProperty(exports, "parseTelegramThreadId", { enumerable: true, get: function () {return _dispatchF_Zbttj.ut;} });Object.defineProperty(exports, "processLineMessage", { enumerable: true, get: function () {return _dispatchF_Zbttj.Ot;} });exports.promptAccountId = void 0;exports.promptChannelAccessConfig = promptChannelAccessConfig;exports.promptSingleChannelSecretInput = promptSingleChannelSecretInput;Object.defineProperty(exports, "rawDataToString", { enumerable: true, get: function () {return _chromeCtHBrex.E;} });Object.defineProperty(exports, "readBooleanParam", { enumerable: true, get: function () {return _dispatchF_Zbttj.dt;} });Object.defineProperty(exports, "readJsonBodyWithLimit", { enumerable: true, get: function () {return _dispatchF_Zbttj.tn;} });Object.defineProperty(exports, "readJsonFileWithFallback", { enumerable: true, get: function () {return _sendXbYokfdQ.rt;} });exports.readJsonWebhookBodyOrReject = readJsonWebhookBodyOrReject;Object.defineProperty(exports, "readNumberParam", { enumerable: true, get: function () {return _targetErrorsByT48YHg.d;} });Object.defineProperty(exports, "readReactionParams", { enumerable: true, get: function () {return _targetErrorsByT48YHg.f;} });Object.defineProperty(exports, "readRequestBodyWithLimit", { enumerable: true, get: function () {return _dispatchF_Zbttj.nn;} });Object.defineProperty(exports, "readStoreAllowFromForDmPolicy", { enumerable: true, get: function () {return _dispatchF_Zbttj.Vt;} });Object.defineProperty(exports, "readStringParam", { enumerable: true, get: function () {return _targetErrorsByT48YHg.h;} });exports.readWebhookBodyOrReject = readWebhookBodyOrReject;Object.defineProperty(exports, "recordInboundSession", { enumerable: true, get: function () {return _dispatchF_Zbttj.G;} });exports.recordInboundSessionAndDispatchReply = recordInboundSessionAndDispatchReply;Object.defineProperty(exports, "recordPendingHistoryEntry", { enumerable: true, get: function () {return _dispatchF_Zbttj.V;} });Object.defineProperty(exports, "recordPendingHistoryEntryIfEnabled", { enumerable: true, get: function () {return _dispatchF_Zbttj.H;} });Object.defineProperty(exports, "redactSensitiveText", { enumerable: true, get: function () {return _redactZ6WVaymT.t;} });Object.defineProperty(exports, "registerAcpRuntimeBackend", { enumerable: true, get: function () {return _dispatchF_Zbttj.ln;} });Object.defineProperty(exports, "registerContextEngine", { enumerable: true, get: function () {return _configDiiPndBn.Ht;} });Object.defineProperty(exports, "registerLogTransport", { enumerable: true, get: function () {return _loggerU3s76KST.q;} });Object.defineProperty(exports, "registerPluginHttpRoute", { enumerable: true, get: function () {return _dispatchF_Zbttj.sn;} });exports.registerWebhookTarget = registerWebhookTarget;exports.registerWebhookTargetWithPluginRoute = registerWebhookTargetWithPluginRoute;Object.defineProperty(exports, "rejectDevicePairing", { enumerable: true, get: function () {return _dispatchF_Zbttj.xt;} });exports.rejectNonPostWebhookRequest = rejectNonPostWebhookRequest;Object.defineProperty(exports, "removeAckReactionAfterReply", { enumerable: true, get: function () {return _dispatchF_Zbttj.K;} });Object.defineProperty(exports, "requestBodyErrorToText", { enumerable: true, get: function () {return _dispatchF_Zbttj.rn;} });Object.defineProperty(exports, "requireAcpRuntimeBackend", { enumerable: true, get: function () {return _dispatchF_Zbttj.un;} });Object.defineProperty(exports, "requireOpenAllowFrom", { enumerable: true, get: function () {return _configDiiPndBn.U;} });Object.defineProperty(exports, "resetMissingProviderGroupPolicyFallbackWarningsForTesting", { enumerable: true, get: function () {return _sendDPZOoQ.jt;} });exports.resolveAccountIdForConfigure = resolveAccountIdForConfigure;Object.defineProperty(exports, "resolveAccountWithDefaultFallback", { enumerable: true, get: function () {return _pluginsBhm3N6Y.j;} });Object.defineProperty(exports, "resolveAckReaction", { enumerable: true, get: function () {return _dispatchF_Zbttj.gt;} });Object.defineProperty(exports, "resolveAllowlistMatchByCandidates", { enumerable: true, get: function () {return _dispatchF_Zbttj.vn;} });Object.defineProperty(exports, "resolveAllowlistMatchSimple", { enumerable: true, get: function () {return _dispatchF_Zbttj.yn;} });Object.defineProperty(exports, "resolveAllowlistProviderRuntimeGroupPolicy", { enumerable: true, get: function () {return _sendDPZOoQ.Mt;} });Object.defineProperty(exports, "resolveBlueBubblesGroupRequireMention", { enumerable: true, get: function () {return _thinkingCfIPyoMg._;} });Object.defineProperty(exports, "resolveBlueBubblesGroupToolPolicy", { enumerable: true, get: function () {return _thinkingCfIPyoMg.v;} });exports.resolveChannelAccountConfigBasePath = resolveChannelAccountConfigBasePath;Object.defineProperty(exports, "resolveChannelEntryMatch", { enumerable: true, get: function () {return _sendDPZOoQ.Ht;} });Object.defineProperty(exports, "resolveChannelEntryMatchWithFallback", { enumerable: true, get: function () {return _sendDPZOoQ.Ut;} });Object.defineProperty(exports, "resolveChannelGroupRequireMention", { enumerable: true, get: function () {return _thinkingCfIPyoMg.F;} });Object.defineProperty(exports, "resolveChannelMediaMaxBytes", { enumerable: true, get: function () {return _deliverCEMUYXvr.h;} });Object.defineProperty(exports, "resolveControlCommandGate", { enumerable: true, get: function () {return _dispatchF_Zbttj.Jt;} });Object.defineProperty(exports, "resolveDefaultDiscordAccountId", { enumerable: true, get: function () {return _pluginsBhm3N6Y.pt;} });Object.defineProperty(exports, "resolveDefaultGroupPolicy", { enumerable: true, get: function () {return _sendDPZOoQ.Nt;} });Object.defineProperty(exports, "resolveDefaultIMessageAccountId", { enumerable: true, get: function () {return _pluginsBhm3N6Y.Z;} });Object.defineProperty(exports, "resolveDefaultLineAccountId", { enumerable: true, get: function () {return _dispatchF_Zbttj.y;} });Object.defineProperty(exports, "resolveDefaultSignalAccountId", { enumerable: true, get: function () {return _accountsCx0R0Kpq.r;} });Object.defineProperty(exports, "resolveDefaultSlackAccountId", { enumerable: true, get: function () {return _pluginsBhm3N6Y.F;} });Object.defineProperty(exports, "resolveDefaultTelegramAccountId", { enumerable: true, get: function () {return _pluginsBhm3N6Y.C;} });Object.defineProperty(exports, "resolveDefaultWhatsAppAccountId", { enumerable: true, get: function () {return _accountsBFBjizxh.r;} });exports.resolveDirectDmAuthorizationOutcome = resolveDirectDmAuthorizationOutcome;Object.defineProperty(exports, "resolveDiscordAccount", { enumerable: true, get: function () {return _pluginsBhm3N6Y.mt;} });Object.defineProperty(exports, "resolveDiscordGroupRequireMention", { enumerable: true, get: function () {return _thinkingCfIPyoMg.y;} });Object.defineProperty(exports, "resolveDiscordGroupToolPolicy", { enumerable: true, get: function () {return _thinkingCfIPyoMg.b;} });Object.defineProperty(exports, "resolveDmAllowState", { enumerable: true, get: function () {return _dispatchF_Zbttj.Ht;} });Object.defineProperty(exports, "resolveDmGroupAccessDecision", { enumerable: true, get: function () {return _dispatchF_Zbttj.Ut;} });Object.defineProperty(exports, "resolveDmGroupAccessWithCommandGate", { enumerable: true, get: function () {return _dispatchF_Zbttj.Wt;} });Object.defineProperty(exports, "resolveDmGroupAccessWithLists", { enumerable: true, get: function () {return _dispatchF_Zbttj.Gt;} });Object.defineProperty(exports, "resolveEffectiveAllowFromLists", { enumerable: true, get: function () {return _dispatchF_Zbttj.Kt;} });exports.resolveGatewayBindUrl = resolveGatewayBindUrl;Object.defineProperty(exports, "resolveGoogleChatGroupRequireMention", { enumerable: true, get: function () {return _thinkingCfIPyoMg.x;} });Object.defineProperty(exports, "resolveGoogleChatGroupToolPolicy", { enumerable: true, get: function () {return _thinkingCfIPyoMg.S;} });Object.defineProperty(exports, "resolveIMessageAccount", { enumerable: true, get: function () {return _pluginsBhm3N6Y.Q;} });Object.defineProperty(exports, "resolveIMessageConfigAllowFrom", { enumerable: true, get: function () {return _pluginsBhm3N6Y.G;} });Object.defineProperty(exports, "resolveIMessageConfigDefaultTo", { enumerable: true, get: function () {return _pluginsBhm3N6Y.K;} });Object.defineProperty(exports, "resolveIMessageGroupRequireMention", { enumerable: true, get: function () {return _thinkingCfIPyoMg.C;} });Object.defineProperty(exports, "resolveIMessageGroupToolPolicy", { enumerable: true, get: function () {return _thinkingCfIPyoMg.w;} });exports.resolveInboundRouteEnvelopeBuilder = resolveInboundRouteEnvelopeBuilder;exports.resolveInboundRouteEnvelopeBuilderWithRuntime = resolveInboundRouteEnvelopeBuilderWithRuntime;Object.defineProperty(exports, "resolveInboundSessionEnvelopeContext", { enumerable: true, get: function () {return _dispatchF_Zbttj.Pt;} });Object.defineProperty(exports, "resolveLineAccount", { enumerable: true, get: function () {return _dispatchF_Zbttj.b;} });Object.defineProperty(exports, "resolveMentionGating", { enumerable: true, get: function () {return _dispatchF_Zbttj.D;} });Object.defineProperty(exports, "resolveMentionGatingWithBypass", { enumerable: true, get: function () {return _dispatchF_Zbttj.O;} });Object.defineProperty(exports, "resolveNestedAllowlistDecision", { enumerable: true, get: function () {return _sendDPZOoQ.Wt;} });Object.defineProperty(exports, "resolveOpenProviderRuntimeGroupPolicy", { enumerable: true, get: function () {return _sendDPZOoQ.Pt;} });Object.defineProperty(exports, "resolveOptionalConfigString", { enumerable: true, get: function () {return _pluginsBhm3N6Y.q;} });exports.resolveOutboundMediaUrls = resolveOutboundMediaUrls;Object.defineProperty(exports, "resolvePreferredOpenClawTmpDir", { enumerable: true, get: function () {return _loggerU3s76KST.Z;} });exports.resolveRequestUrl = resolveRequestUrl;exports.resolveRuntimeEnv = resolveRuntimeEnv;exports.resolveRuntimeEnvWithUnavailableExit = resolveRuntimeEnvWithUnavailableExit;Object.defineProperty(exports, "resolveRuntimeGroupPolicy", { enumerable: true, get: function () {return _sendDPZOoQ.Ft;} });exports.resolveSenderCommandAuthorization = resolveSenderCommandAuthorization;exports.resolveSenderCommandAuthorizationWithRuntime = resolveSenderCommandAuthorizationWithRuntime;Object.defineProperty(exports, "resolveSenderScopedGroupPolicy", { enumerable: true, get: function () {return _sendDPZOoQ.kt;} });Object.defineProperty(exports, "resolveServicePrefixedAllowTarget", { enumerable: true, get: function () {return _sendBlv_6HQ.d;} });Object.defineProperty(exports, "resolveServicePrefixedChatTarget", { enumerable: true, get: function () {return _sendBlv_6HQ.f;} });Object.defineProperty(exports, "resolveServicePrefixedOrChatAllowTarget", { enumerable: true, get: function () {return _sendBlv_6HQ.p;} });Object.defineProperty(exports, "resolveServicePrefixedTarget", { enumerable: true, get: function () {return _sendBlv_6HQ.m;} });Object.defineProperty(exports, "resolveSignalAccount", { enumerable: true, get: function () {return _accountsCx0R0Kpq.i;} });exports.resolveSingleWebhookTarget = resolveSingleWebhookTarget;exports.resolveSingleWebhookTargetAsync = resolveSingleWebhookTargetAsync;Object.defineProperty(exports, "resolveSlackAccount", { enumerable: true, get: function () {return _pluginsBhm3N6Y.I;} });Object.defineProperty(exports, "resolveSlackGroupRequireMention", { enumerable: true, get: function () {return _thinkingCfIPyoMg.T;} });Object.defineProperty(exports, "resolveSlackGroupToolPolicy", { enumerable: true, get: function () {return _thinkingCfIPyoMg.E;} });Object.defineProperty(exports, "resolveSlackReplyToMode", { enumerable: true, get: function () {return _pluginsBhm3N6Y.L;} });exports.resolveTailnetHostWithRunner = resolveTailnetHostWithRunner;Object.defineProperty(exports, "resolveTelegramAccount", { enumerable: true, get: function () {return _pluginsBhm3N6Y.w;} });Object.defineProperty(exports, "resolveTelegramGroupRequireMention", { enumerable: true, get: function () {return _thinkingCfIPyoMg.D;} });Object.defineProperty(exports, "resolveTelegramGroupToolPolicy", { enumerable: true, get: function () {return _thinkingCfIPyoMg.O;} });Object.defineProperty(exports, "resolveThreadSessionKeys", { enumerable: true, get: function () {return _runWithConcurrency2ga3CMk.ot;} });Object.defineProperty(exports, "resolveTimezone", { enumerable: true, get: function () {return _dispatchF_Zbttj.zt;} });Object.defineProperty(exports, "resolveToolsBySender", { enumerable: true, get: function () {return _thinkingCfIPyoMg.L;} });exports.resolveWebhookPath = resolveWebhookPath;exports.resolveWebhookTargetWithAuthOrReject = resolveWebhookTargetWithAuthOrReject;exports.resolveWebhookTargetWithAuthOrRejectSync = resolveWebhookTargetWithAuthOrRejectSync;exports.resolveWebhookTargets = resolveWebhookTargets;Object.defineProperty(exports, "resolveWhatsAppAccount", { enumerable: true, get: function () {return _accountsBFBjizxh.i;} });Object.defineProperty(exports, "resolveWhatsAppConfigAllowFrom", { enumerable: true, get: function () {return _pluginsBhm3N6Y.J;} });Object.defineProperty(exports, "resolveWhatsAppConfigDefaultTo", { enumerable: true, get: function () {return _pluginsBhm3N6Y.Y;} });Object.defineProperty(exports, "resolveWhatsAppGroupIntroHint", { enumerable: true, get: function () {return _thinkingCfIPyoMg.p;} });Object.defineProperty(exports, "resolveWhatsAppGroupRequireMention", { enumerable: true, get: function () {return _thinkingCfIPyoMg.k;} });Object.defineProperty(exports, "resolveWhatsAppGroupToolPolicy", { enumerable: true, get: function () {return _thinkingCfIPyoMg.A;} });Object.defineProperty(exports, "resolveWhatsAppHeartbeatRecipients", { enumerable: true, get: function () {return _channelWebDd_aWvzo.r;} });Object.defineProperty(exports, "resolveWhatsAppMentionStripPatterns", { enumerable: true, get: function () {return _thinkingCfIPyoMg.m;} });Object.defineProperty(exports, "resolveWhatsAppOutboundTarget", { enumerable: true, get: function () {return _resolveOutboundTargetZvBoACjP.t;} });Object.defineProperty(exports, "resolveWindowsExecutablePath", { enumerable: true, get: function () {return _windowsSpawnCpTF7CWy.r;} });Object.defineProperty(exports, "resolveWindowsSpawnProgram", { enumerable: true, get: function () {return _windowsSpawnCpTF7CWy.i;} });Object.defineProperty(exports, "resolveWindowsSpawnProgramCandidate", { enumerable: true, get: function () {return _windowsSpawnCpTF7CWy.a;} });exports.runPluginCommandWithTimeout = runPluginCommandWithTimeout;Object.defineProperty(exports, "safeParseJson", { enumerable: true, get: function () {return _loggerU3s76KST.O;} });exports.sendMediaWithLeadingCaption = sendMediaWithLeadingCaption;exports.sendPayloadWithChunkedTextAndMedia = sendPayloadWithChunkedTextAndMedia;Object.defineProperty(exports, "setAccountEnabledInConfigSection", { enumerable: true, get: function () {return _pluginsBhm3N6Y.ct;} });exports.setTopLevelChannelAllowFrom = setTopLevelChannelAllowFrom;exports.setTopLevelChannelDmPolicyWithAllowFrom = setTopLevelChannelDmPolicyWithAllowFrom;exports.setTopLevelChannelGroupPolicy = setTopLevelChannelGroupPolicy;Object.defineProperty(exports, "shouldAckReaction", { enumerable: true, get: function () {return _dispatchF_Zbttj.q;} });Object.defineProperty(exports, "shouldAckReactionForWhatsApp", { enumerable: true, get: function () {return _dispatchF_Zbttj.J;} });exports.slackOnboardingAdapter = exports.signalOnboardingAdapter = void 0;Object.defineProperty(exports, "sleep", { enumerable: true, get: function () {return _loggerU3s76KST.j;} });Object.defineProperty(exports, "stringEnum", { enumerable: true, get: function () {return _dispatchF_Zbttj.pt;} });Object.defineProperty(exports, "stripAnsi", { enumerable: true, get: function () {return _loggerU3s76KST.s;} });Object.defineProperty(exports, "stripMarkdown", { enumerable: true, get: function () {return _dispatchF_Zbttj.kt;} });Object.defineProperty(exports, "summarizeMapping", { enumerable: true, get: function () {return _dispatchF_Zbttj.T;} });exports.tagDiscordChannelResult = tagDiscordChannelResult;exports.telegramOnboardingAdapter = void 0;exports.toFormUrlEncoded = toFormUrlEncoded;Object.defineProperty(exports, "toLocationContext", { enumerable: true, get: function () {return _sendXbYokfdQ.X;} });Object.defineProperty(exports, "unbindThreadBindingsBySessionKey", { enumerable: true, get: function () {return _dispatchF_Zbttj.gn;} });Object.defineProperty(exports, "unregisterAcpRuntimeBackend", { enumerable: true, get: function () {return _dispatchF_Zbttj.dn;} });exports.waitUntilAbort = waitUntilAbort;Object.defineProperty(exports, "warnMissingProviderGroupPolicyFallbackOnce", { enumerable: true, get: function () {return _sendDPZOoQ.It;} });exports.whatsappOnboardingAdapter = void 0;Object.defineProperty(exports, "withFileLock", { enumerable: true, get: function () {return _configDiiPndBn.Ir;} });exports.withResolvedWebhookRequestPipeline = withResolvedWebhookRequestPipeline;Object.defineProperty(exports, "withTempDownloadPath", { enumerable: true, get: function () {return _audioTranscriptionRunnerC72KQQVh.f;} });Object.defineProperty(exports, "writeJsonFileAtomically", { enumerable: true, get: function () {return _sendXbYokfdQ.it;} });var _runWithConcurrency2ga3CMk = require("./run-with-concurrency-2ga3-CMk.js"); var _accountsBFBjizxh = require("./accounts-BFBjizxh.js"); var _dispatchF_Zbttj = require("./dispatch-F_Zbttj6.js"); require("./paths-eFexkPEh.js"); require("./github-copilot-token-Cxf8QYZb.js"); var _configDiiPndBn = require("./config-DiiPndBn.js"); var _loggerU3s76KST = require("./logger-U3s76KST.js"); var _thinkingCfIPyoMg = require("./thinking-CfIPyoMg.js"); var _imageOpsZjRT9yvG = require("./image-ops-ZjRT9yvG.js"); require("./pi-embedded-helpers-Dmr3bcbH.js"); var _pluginsBhm3N6Y = require("./plugins-Bhm3N6Y-.js"); var _allowFromCfbQs9EO = require("./allow-from-CfbQs9EO.js"); var _accountsCx0R0Kpq = require("./accounts-Cx0R0Kpq.js"); var _sendDPZOoQ = require("./send-D-p-zOoQ.js"); require("./paths-yc45qYMp.js"); require("./fetch-C_ro9dG3.js"); var _redactZ6WVaymT = require("./redact-z6WVaymT.js"); var _errorsDR1SiaHP = require("./errors-DR1SiaHP.js"); require("./channel-activity-DH-8wxjI.js"); require("./path-alias-guards-DFv45kR8.js"); var _fsSafeBbZgytb = require("./fs-safe-BbZgytb6.js"); var _ssrfD6FSPiLK = require("./ssrf-D6FSPiLK.js"); var _fetchGuardBMQY_BjF = require("./fetch-guard-BMQY_BjF.js"); require("./local-roots-Zhwi3hFj.js"); var _irKp5uANes = require("./ir-Kp5uANes.js"); require("./render-C15_5JiR.js"); require("./tables-DkBUhlLj.js"); var _sendXbYokfdQ = require("./send-XbYokfdQ.js"); require("./tool-images-DGP_dM0r.js"); var _targetErrorsByT48YHg = require("./target-errors-ByT48YHg.js"); var _sendCoJpuv4Y = require("./send-CoJpuv4Y.js"); var _deliverCEMUYXvr = require("./deliver-CEMUYXvr.js"); var _diagnosticCKfPvpU = require("./diagnostic-CKfPvpU1.js"); require("./pi-model-discovery-oqT3sUem.js"); var _audioTranscriptionRunnerC72KQQVh = require("./audio-transcription-runner-C72KQQVh.js"); require("./image-DqJ0oIQs.js"); var _chromeCtHBrex = require("./chrome-Ct-HBrex.js"); require("./skills-BC9BA6b0.js"); var _storeBfiJnRiX = require("./store-BfiJnRiX.js"); var _windowsSpawnCpTF7CWy = require("./windows-spawn-CpTF7CWy.js"); require("./api-key-rotation-DoiAvDNZ.js"); require("./proxy-fetch-0VcTBuoM.js"); var _tokensCgeKcoW = require("./tokens-CgeKcoW1.js"); require("./commands-registry-DmjEuzd5.js"); var _targetsBP_LjgWp = require("./targets-BP_LjgWp.js"); var _skillCommandsD9AhwcyN = require("./skill-commands-D9AhwcyN.js"); require("./send-CWALh87S.js"); require("./outbound-attachment-CflAwcGk.js"); var _sendBlv_6HQ = require("./send-Blv_6-hQ.js"); require("./sqlite-DsAPHNp3.js"); require("./proxy-DnXFtvOD.js"); require("./manager-B4pKBBvG.js"); var _resolveOutboundTargetZvBoACjP = require("./resolve-outbound-target-zvBoACjP.js"); var _channelWebDd_aWvzo = require("./channel-web-Dd_aWvzo.js"); require("./outbound-DV7ZS1T6.js"); require("./session-DwL-pNct.js"); var _loginC7cFTFMn = require("./login-C7cFTFMn.js"); var _nodeFs = _interopRequireWildcard(require("node:fs")); var _nodePath = _interopRequireDefault(require("node:path")); var _nodeOs = _interopRequireDefault(require("node:os")); var _promises = _interopRequireDefault(require("node:fs/promises")); var _nodeCrypto = require("node:crypto"); var _nodeUtil = require("node:util"); var _zod = require("zod"); var _promises2 = require("node:stream/promises"); var _nodeHttps = require("node:https"); var _nodeStream = require("node:stream"); var _jszip = _interopRequireDefault(require("jszip")); var tar = _interopRequireWildcard(require("tar"));function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };}function _interopRequireWildcard(e, t) {if ("function" == typeof WeakMap) var r = new WeakMap(),n = new WeakMap();return (_interopRequireWildcard = function (e, t) {if (!t && e && e.__esModule) return e;var o,i,f = { __proto__: null, default: e };if (null === e || "object" != typeof e && "function" != typeof e) return f;if (o = t ? n : r) {if (o.has(e)) return o.get(e);o.set(e, f);}for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]);return f;})(e, t);} //#region src/plugins/config-schema.ts function error(message) { return { success: false, error: { issues: [{ path: [], message }] } }; } function emptyPluginConfigSchema() { return { safeParse(value) { if (value === void 0) return { success: true, data: void 0 }; if (!value || typeof value !== "object" || Array.isArray(value)) return error("expected config object"); if (Object.keys(value).length > 0) return error("config must be empty"); return { success: true, data: value }; }, jsonSchema: { type: "object", additionalProperties: false, properties: {} } }; } //#endregion //#region src/plugin-sdk/allowlist-resolution.ts function mapBasicAllowlistResolutionEntries(entries) { return entries.map((entry) => ({ input: entry.input, resolved: entry.resolved, id: entry.id, name: entry.name, note: entry.note })); } async function mapAllowlistResolutionInputs(params) { const results = []; for (const input of params.inputs) results.push(await params.mapInput(input)); return results; } //#endregion //#region src/plugin-sdk/request-url.ts function resolveRequestUrl(input) { if (typeof input === "string") return input; if (input instanceof URL) return input.toString(); if (typeof input === "object" && input && "url" in input && typeof input.url === "string") return input.url; return ""; } //#endregion //#region src/plugin-sdk/discord-send.ts function buildDiscordSendOptions(input) { return { verbose: false, replyTo: input.replyToId ?? void 0, accountId: input.accountId ?? void 0, silent: input.silent ?? void 0 }; } function buildDiscordSendMediaOptions(input) { return { ...buildDiscordSendOptions(input), mediaUrl: input.mediaUrl, mediaLocalRoots: input.mediaLocalRoots }; } function tagDiscordChannelResult(result) { return { channel: "discord", ...result }; } //#endregion //#region src/plugin-sdk/webhook-path.ts function normalizeWebhookPath(raw) { const trimmed = raw.trim(); if (!trimmed) return "/"; const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`; if (withSlash.length > 1 && withSlash.endsWith("/")) return withSlash.slice(0, -1); return withSlash; } function resolveWebhookPath(params) { const trimmedPath = params.webhookPath?.trim(); if (trimmedPath) return normalizeWebhookPath(trimmedPath); if (params.webhookUrl?.trim()) try { return normalizeWebhookPath(new URL(params.webhookUrl).pathname || "/"); } catch { return null; } return params.defaultPath ?? null; } //#endregion //#region src/plugin-sdk/webhook-request-guards.ts const WEBHOOK_BODY_READ_DEFAULTS = exports.WEBHOOK_BODY_READ_DEFAULTS = Object.freeze({ preAuth: { maxBytes: 64 * 1024, timeoutMs: 5e3 }, postAuth: { maxBytes: 1024 * 1024, timeoutMs: 3e4 } }); const WEBHOOK_IN_FLIGHT_DEFAULTS = exports.WEBHOOK_IN_FLIGHT_DEFAULTS = Object.freeze({ maxInFlightPerKey: 8, maxTrackedKeys: 4096 }); function resolveWebhookBodyReadLimits(params) { const defaults = params.profile === "pre-auth" ? WEBHOOK_BODY_READ_DEFAULTS.preAuth : WEBHOOK_BODY_READ_DEFAULTS.postAuth; return { maxBytes: typeof params.maxBytes === "number" && Number.isFinite(params.maxBytes) && params.maxBytes > 0 ? Math.floor(params.maxBytes) : defaults.maxBytes, timeoutMs: typeof params.timeoutMs === "number" && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0 ? Math.floor(params.timeoutMs) : defaults.timeoutMs }; } function respondWebhookBodyReadError(params) { const { res, code, invalidMessage } = params; if (code === "PAYLOAD_TOO_LARGE") { res.statusCode = 413; res.end((0, _dispatchF_Zbttj.rn)("PAYLOAD_TOO_LARGE")); return { ok: false }; } if (code === "REQUEST_BODY_TIMEOUT") { res.statusCode = 408; res.end((0, _dispatchF_Zbttj.rn)("REQUEST_BODY_TIMEOUT")); return { ok: false }; } if (code === "CONNECTION_CLOSED") { res.statusCode = 400; res.end((0, _dispatchF_Zbttj.rn)("CONNECTION_CLOSED")); return { ok: false }; } res.statusCode = 400; res.end(invalidMessage ?? "Bad Request"); return { ok: false }; } function createWebhookInFlightLimiter(options) { const maxInFlightPerKey = Math.max(1, Math.floor(options?.maxInFlightPerKey ?? WEBHOOK_IN_FLIGHT_DEFAULTS.maxInFlightPerKey)); const maxTrackedKeys = Math.max(1, Math.floor(options?.maxTrackedKeys ?? WEBHOOK_IN_FLIGHT_DEFAULTS.maxTrackedKeys)); const active = /* @__PURE__ */new Map(); return { tryAcquire: (key) => { if (!key) return true; const current = active.get(key) ?? 0; if (current >= maxInFlightPerKey) return false; active.set(key, current + 1); (0, _dispatchF_Zbttj.Yt)(active, maxTrackedKeys); return true; }, release: (key) => { if (!key) return; const current = active.get(key); if (current === void 0) return; if (current <= 1) { active.delete(key); return; } active.set(key, current - 1); }, size: () => active.size, clear: () => active.clear() }; } function isJsonContentType(value) { const first = Array.isArray(value) ? value[0] : value; if (!first) return false; const mediaType = first.split(";", 1)[0]?.trim().toLowerCase(); return mediaType === "application/json" || Boolean(mediaType?.endsWith("+json")); } function applyBasicWebhookRequestGuards(params) { const allowMethods = params.allowMethods?.length ? params.allowMethods : null; if (allowMethods && !allowMethods.includes(params.req.method ?? "")) { params.res.statusCode = 405; params.res.setHeader("Allow", allowMethods.join(", ")); params.res.end("Method Not Allowed"); return false; } if (params.rateLimiter && params.rateLimitKey && params.rateLimiter.isRateLimited(params.rateLimitKey, params.nowMs ?? Date.now())) { params.res.statusCode = 429; params.res.end("Too Many Requests"); return false; } if (params.requireJsonContentType && params.req.method === "POST" && !isJsonContentType(params.req.headers["content-type"])) { params.res.statusCode = 415; params.res.end("Unsupported Media Type"); return false; } return true; } function beginWebhookRequestPipelineOrReject(params) { if (!applyBasicWebhookRequestGuards({ req: params.req, res: params.res, allowMethods: params.allowMethods, rateLimiter: params.rateLimiter, rateLimitKey: params.rateLimitKey, nowMs: params.nowMs, requireJsonContentType: params.requireJsonContentType })) return { ok: false }; const inFlightKey = params.inFlightKey ?? ""; const inFlightLimiter = params.inFlightLimiter; if (inFlightLimiter && inFlightKey && !inFlightLimiter.tryAcquire(inFlightKey)) { params.res.statusCode = params.inFlightLimitStatusCode ?? 429; params.res.end(params.inFlightLimitMessage ?? "Too Many Requests"); return { ok: false }; } let released = false; return { ok: true, release: () => { if (released) return; released = true; if (inFlightLimiter && inFlightKey) inFlightLimiter.release(inFlightKey); } }; } async function readWebhookBodyOrReject(params) { const limits = resolveWebhookBodyReadLimits({ maxBytes: params.maxBytes, timeoutMs: params.timeoutMs, profile: params.profile }); try { return { ok: true, value: await (0, _dispatchF_Zbttj.nn)(params.req, limits) }; } catch (error) { if ((0, _dispatchF_Zbttj.en)(error)) return respondWebhookBodyReadError({ res: params.res, code: error.code, invalidMessage: params.invalidBodyMessage }); return respondWebhookBodyReadError({ res: params.res, code: "INVALID_BODY", invalidMessage: params.invalidBodyMessage ?? (error instanceof Error ? error.message : String(error)) }); } } async function readJsonWebhookBodyOrReject(params) { const limits = resolveWebhookBodyReadLimits({ maxBytes: params.maxBytes, timeoutMs: params.timeoutMs, profile: params.profile }); const body = await (0, _dispatchF_Zbttj.tn)(params.req, { maxBytes: limits.maxBytes, timeoutMs: limits.timeoutMs, emptyObjectOnEmpty: params.emptyObjectOnEmpty }); if (body.ok) return { ok: true, value: body.value }; return respondWebhookBodyReadError({ res: params.res, code: body.code, invalidMessage: params.invalidJsonMessage }); } //#endregion //#region src/plugin-sdk/webhook-targets.ts function registerWebhookTargetWithPluginRoute(params) { return registerWebhookTarget(params.targetsByPath, params.target, { onFirstPathTarget: ({ path }) => (0, _dispatchF_Zbttj.sn)({ ...params.route, path, replaceExisting: params.route.replaceExisting ?? true }), onLastPathTargetRemoved: params.onLastPathTargetRemoved }); } const pathTeardownByTargetMap = /* @__PURE__ */new WeakMap(); function getPathTeardownMap(targetsByPath) { const mapKey = targetsByPath; const existing = pathTeardownByTargetMap.get(mapKey); if (existing) return existing; const created = /* @__PURE__ */new Map(); pathTeardownByTargetMap.set(mapKey, created); return created; } function registerWebhookTarget(targetsByPath, target, opts) { const key = normalizeWebhookPath(target.path); const normalizedTarget = { ...target, path: key }; const existing = targetsByPath.get(key) ?? []; if (existing.length === 0) { const onFirstPathResult = opts?.onFirstPathTarget?.({ path: key, target: normalizedTarget }); if (typeof onFirstPathResult === "function") getPathTeardownMap(targetsByPath).set(key, onFirstPathResult); } targetsByPath.set(key, [...existing, normalizedTarget]); let isActive = true; const unregister = () => { if (!isActive) return; isActive = false; const updated = (targetsByPath.get(key) ?? []).filter((entry) => entry !== normalizedTarget); if (updated.length > 0) { targetsByPath.set(key, updated); return; } targetsByPath.delete(key); const teardown = getPathTeardownMap(targetsByPath).get(key); if (teardown) { getPathTeardownMap(targetsByPath).delete(key); teardown(); } opts?.onLastPathTargetRemoved?.({ path: key }); }; return { target: normalizedTarget, unregister }; } function resolveWebhookTargets(req, targetsByPath) { const path = normalizeWebhookPath(new URL(req.url ?? "/", "http://localhost").pathname); const targets = targetsByPath.get(path); if (!targets || targets.length === 0) return null; return { path, targets }; } async function withResolvedWebhookRequestPipeline(params) { const resolved = resolveWebhookTargets(params.req, params.targetsByPath); if (!resolved) return false; const inFlightKey = typeof params.inFlightKey === "function" ? params.inFlightKey({ req: params.req, path: resolved.path, targets: resolved.targets }) : params.inFlightKey ?? `${resolved.path}:${params.req.socket?.remoteAddress ?? "unknown"}`; const requestLifecycle = beginWebhookRequestPipelineOrReject({ req: params.req, res: params.res, allowMethods: params.allowMethods, rateLimiter: params.rateLimiter, rateLimitKey: params.rateLimitKey, nowMs: params.nowMs, requireJsonContentType: params.requireJsonContentType, inFlightLimiter: params.inFlightLimiter, inFlightKey, inFlightLimitStatusCode: params.inFlightLimitStatusCode, inFlightLimitMessage: params.inFlightLimitMessage }); if (!requestLifecycle.ok) return true; try { await params.handle(resolved); return true; } finally { requestLifecycle.release(); } } function updateMatchedWebhookTarget(matched, target) { if (matched) return { ok: false, result: { kind: "ambiguous" } }; return { ok: true, matched: target }; } function finalizeMatchedWebhookTarget(matched) { if (!matched) return { kind: "none" }; return { kind: "single", target: matched }; } function resolveSingleWebhookTarget(targets, isMatch) { let matched; for (const target of targets) { if (!isMatch(target)) continue; const updated = updateMatchedWebhookTarget(matched, target); if (!updated.ok) return updated.result; matched = updated.matched; } return finalizeMatchedWebhookTarget(matched); } async function resolveSingleWebhookTargetAsync(targets, isMatch) { let matched; for (const target of targets) { if (!(await isMatch(target))) continue; const updated = updateMatchedWebhookTarget(matched, target); if (!updated.ok) return updated.result; matched = updated.matched; } return finalizeMatchedWebhookTarget(matched); } async function resolveWebhookTargetWithAuthOrReject(params) { return resolveWebhookTargetMatchOrReject(params, await resolveSingleWebhookTargetAsync(params.targets, async (target) => Boolean(await params.isMatch(target)))); } function resolveWebhookTargetWithAuthOrRejectSync(params) { return resolveWebhookTargetMatchOrReject(params, resolveSingleWebhookTarget(params.targets, params.isMatch)); } function resolveWebhookTargetMatchOrReject(params, match) { if (match.kind === "single") return match.target; if (match.kind === "ambiguous") { params.res.statusCode = params.ambiguousStatusCode ?? 401; params.res.end(params.ambiguousMessage ?? "ambiguous webhook target"); return null; } params.res.statusCode = params.unauthorizedStatusCode ?? 401; params.res.end(params.unauthorizedMessage ?? "unauthorized"); return null; } function rejectNonPostWebhookRequest(req, res) { if (req.method === "POST") return false; res.statusCode = 405; res.setHeader("Allow", "POST"); res.end("Method Not Allowed"); return true; } //#endregion //#region src/plugin-sdk/channel-lifecycle.ts /** * Return a promise that resolves when the signal is aborted. * * If no signal is provided, the promise stays pending forever. */ function waitUntilAbort(signal) { return new Promise((resolve) => { if (!signal) return; if (signal.aborted) { resolve(); return; } signal.addEventListener("abort", () => resolve(), { once: true }); }); } /** * Keep a channel/provider task pending until the HTTP server closes. * * When an abort signal is provided, `onAbort` is invoked once and should * trigger server shutdown. The returned promise resolves only after `close`. */ async function keepHttpServerTaskAlive(params) { const { server, abortSignal, onAbort } = params; let abortTask = Promise.resolve(); let abortTriggered = false; const triggerAbort = () => { if (abortTriggered) return; abortTriggered = true; abortTask = Promise.resolve(onAbort?.()).then(() => void 0); }; const onAbortSignal = () => { triggerAbort(); }; if (abortSignal) if (abortSignal.aborted) triggerAbort();else abortSignal.addEventListener("abort", onAbortSignal, { once: true }); await new Promise((resolve) => { server.once("close", () => resolve()); }); if (abortSignal) abortSignal.removeEventListener("abort", onAbortSignal); await abortTask; } //#endregion //#region src/plugin-sdk/agent-media-payload.ts function buildAgentMediaPayload(mediaList) { const first = mediaList[0]; const mediaPaths = mediaList.map((media) => media.path); const mediaTypes = mediaList.map((media) => media.contentType).filter(Boolean); return { MediaPath: first?.path, MediaType: first?.contentType ?? void 0, MediaUrl: first?.path, MediaPaths: mediaPaths.length > 0 ? mediaPaths : void 0, MediaUrls: mediaPaths.length > 0 ? mediaPaths : void 0, MediaTypes: mediaTypes.length > 0 ? mediaTypes : void 0 }; } //#endregion //#region src/plugin-sdk/status-helpers.ts function createDefaultChannelRuntimeState(accountId, extra) { return { accountId, running: false, lastStartAt: null, lastStopAt: null, lastError: null, ...(extra ?? {}) }; } function buildBaseChannelStatusSummary(snapshot) { return { configured: snapshot.configured ?? false, running: snapshot.running ?? false, lastStartAt: snapshot.lastStartAt ?? null, lastStopAt: snapshot.lastStopAt ?? null, lastError: snapshot.lastError ?? null }; } function buildProbeChannelStatusSummary(snapshot, extra) { return { ...buildBaseChannelStatusSummary(snapshot), ...(extra ?? {}), probe: snapshot.probe, lastProbeAt: snapshot.lastProbeAt ?? null }; } function buildBaseAccountStatusSnapshot(params) { const { account, runtime, probe } = params; return { accountId: account.accountId, name: account.name, enabled: account.enabled, configured: account.configured, ...buildRuntimeAccountStatusSnapshot({ runtime, probe }), lastInboundAt: runtime?.lastInboundAt ?? null, lastOutboundAt: runtime?.lastOutboundAt ?? null }; } function buildComputedAccountStatusSnapshot(params) { const { accountId, name, enabled, configured, runtime, probe } = params; return buildBaseAccountStatusSnapshot({ account: { accountId, name, enabled, configured }, runtime, probe }); } function buildRuntimeAccountStatusSnapshot(params) { const { runtime, probe } = params; return { running: runtime?.running ?? false, lastStartAt: runtime?.lastStartAt ?? null, lastStopAt: runtime?.lastStopAt ?? null, lastError: runtime?.lastError ?? null, probe }; } function buildTokenChannelStatusSummary(snapshot, opts) { const base = { ...buildBaseChannelStatusSummary(snapshot), tokenSource: snapshot.tokenSource ?? "none", probe: snapshot.probe, lastProbeAt: snapshot.lastProbeAt ?? null }; if (opts?.includeMode === false) return base; return { ...base, mode: snapshot.mode ?? null }; } function collectStatusIssuesFromLastError(channel, accounts) { return accounts.flatMap((account) => { const lastError = typeof account.lastError === "string" ? account.lastError.trim() : ""; if (!lastError) return []; return [{ channel, accountId: account.accountId, kind: "runtime", message: `Channel error: ${lastError}` }]; }); } //#endregion //#region src/secrets/provider-env-vars.ts const PROVIDER_ENV_VARS = { openai: ["OPENAI_API_KEY"], anthropic: ["ANTHROPIC_API_KEY"], google: ["GEMINI_API_KEY"], minimax: ["MINIMAX_API_KEY"], "minimax-cn": ["MINIMAX_API_KEY"], moonshot: ["MOONSHOT_API_KEY"], "kimi-coding": ["KIMI_API_KEY", "KIMICODE_API_KEY"], synthetic: ["SYNTHETIC_API_KEY"], venice: ["VENICE_API_KEY"], zai: ["ZAI_API_KEY", "Z_AI_API_KEY"], xiaomi: ["XIAOMI_API_KEY"], openrouter: ["OPENROUTER_API_KEY"], "cloudflare-ai-gateway": ["CLOUDFLARE_AI_GATEWAY_API_KEY"], litellm: ["LITELLM_API_KEY"], "vercel-ai-gateway": ["AI_GATEWAY_API_KEY"], opencode: ["OPENCODE_API_KEY", "OPENCODE_ZEN_API_KEY"], together: ["TOGETHER_API_KEY"], huggingface: ["HUGGINGFACE_HUB_TOKEN", "HF_TOKEN"], qianfan: ["QIANFAN_API_KEY"], xai: ["XAI_API_KEY"], mistral: ["MISTRAL_API_KEY"], kilocode: ["KILOCODE_API_KEY"], volcengine: ["VOLCANO_ENGINE_API_KEY"], byteplus: ["BYTEPLUS_API_KEY"] }; //#endregion //#region src/commands/auth-choice.apply-helpers.ts function formatErrorMessage$1(error) { if (error instanceof Error && typeof error.message === "string" && error.message.trim()) return error.message; return String(error); } function resolveDefaultProviderEnvVar(provider) { return PROVIDER_ENV_VARS[provider]?.find((candidate) => candidate.trim().length > 0); } function resolveDefaultFilePointerId(provider) { return `/providers/${(0, _configDiiPndBn.Dr)(provider)}/apiKey`; } async function promptSecretRefForOnboarding(params) { const defaultEnvVar = params.preferredEnvVar ?? resolveDefaultProviderEnvVar(params.provider) ?? ""; const defaultFilePointer = resolveDefaultFilePointerId(params.provider); let sourceChoice = "env"; while (true) { const source = (await params.prompter.select({ message: params.copy?.sourceMessage ?? "Where is this API key stored?", initialValue: sourceChoice, options: [{ value: "env", label: "Environment variable", hint: "Reference a variable from your runtime environment" }, { value: "provider", label: "Configured secret provider", hint: "Use a configured file or exec secret provider" }] })) === "provider" ? "provider" : "env"; sourceChoice = source; if (source === "env") { const envVarRaw = await params.prompter.text({ message: params.copy?.envVarMessage ?? "Environment variable name", initialValue: defaultEnvVar || void 0, placeholder: params.copy?.envVarPlaceholder ?? "OPENAI_API_KEY", validate: (value) => { const candidate = value.trim(); if (!(0, _configDiiPndBn.Yr)(candidate)) return params.copy?.envVarFormatError ?? "Use an env var name like \"OPENAI_API_KEY\" (uppercase letters, numbers, underscores)."; if (!process.env[candidate]?.trim()) return params.copy?.envVarMissingError?.(candidate) ?? `Environment variable "${candidate}" is missing or empty in this session.`; } }); const envCandidate = String(envVarRaw ?? "").trim(); const envVar = envCandidate && (0, _configDiiPndBn.Yr)(envCandidate) ? envCandidate : defaultEnvVar; if (!envVar) throw new Error(`No valid environment variable name provided for provider "${params.provider}".`); const ref = { source: "env", provider: (0, _configDiiPndBn.Tr)(params.config, "env", { preferFirstProviderForSource: true }), id: envVar }; const resolvedValue = await (0, _configDiiPndBn._r)(ref, { config: params.config, env: process.env }); await params.prompter.note(params.copy?.envValidatedMessage?.(envVar) ?? `Validated environment variable ${envVar}. OpenClaw will store a reference, not the key value.`, "Reference validated"); return { ref, resolvedValue }; } const externalProviders = Object.entries(params.config.secrets?.providers ?? {}).filter(([, provider]) => provider?.source === "file" || provider?.source === "exec"); if (externalProviders.length === 0) { await params.prompter.note(params.copy?.noProvidersMessage ?? "No file/exec secret providers are configured yet. Add one under secrets.providers, or select Environment variable.", "No providers configured"); continue; } const defaultProvider = (0, _configDiiPndBn.Tr)(params.config, "file", { preferFirstProviderForSource: true }); const selectedProvider = await params.prompter.select({ message: "Select secret provider", initialValue: externalProviders.find(([providerName]) => providerName === defaultProvider)?.[0] ?? externalProviders[0]?.[0], options: externalProviders.map(([providerName, provider]) => ({ value: providerName, label: providerName, hint: provider?.source === "exec" ? "Exec provider" : "File provider" })) }); const providerEntry = params.config.secrets?.providers?.[selectedProvider]; if (!providerEntry || providerEntry.source !== "file" && providerEntry.source !== "exec") { await params.prompter.note(`Provider "${selectedProvider}" is not a file/exec provider.`, "Invalid provider"); continue; } const idPrompt = providerEntry.source === "file" ? "Secret id (JSON pointer for json mode, or 'value' for singleValue mode)" : "Secret id for the exec provider"; const idDefault = providerEntry.source === "file" ? providerEntry.mode === "singleValue" ? "value" : defaultFilePointer : `${params.provider}/apiKey`; const idRaw = await params.prompter.text({ message: idPrompt, initialValue: idDefault, placeholder: providerEntry.source === "file" ? "/providers/openai/apiKey" : "openai/api-key", validate: (value) => { const candidate = value.trim(); if (!candidate) return "Secret id cannot be empty."; if (providerEntry.source === "file" && providerEntry.mode !== "singleValue" && !(0, _configDiiPndBn.wr)(candidate)) return "Use an absolute JSON pointer like \"/providers/openai/apiKey\"."; if (providerEntry.source === "file" && providerEntry.mode === "singleValue" && candidate !== "value") return "singleValue mode expects id \"value\"."; } }); const id = String(idRaw ?? "").trim() || idDefault; const ref = { source: providerEntry.source, provider: selectedProvider, id }; try { const resolvedValue = await (0, _configDiiPndBn._r)(ref, { config: params.config, env: process.env }); await params.prompter.note(params.copy?.providerValidatedMessage?.(selectedProvider, id, providerEntry.source) ?? `Validated ${providerEntry.source} reference ${selectedProvider}:${id}. OpenClaw will store a reference, not the key value.`, "Reference validated"); return { ref, resolvedValue }; } catch (error) { await params.prompter.note([ `Could not validate provider reference ${selectedProvider}:${id}.`, formatErrorMessage$1(error), "Check your provider configuration and try again."]. join("\n"), "Reference check failed"); } } } async function resolveSecretInputModeForEnvSelection(params) { if (params.explicitMode) return params.explicitMode; if (typeof params.prompter.select !== "function") return "plaintext"; return (await params.prompter.select({ message: params.copy?.modeMessage ?? "How do you want to provide this API key?", initialValue: "plaintext", options: [{ value: "plaintext", label: params.copy?.plaintextLabel ?? "Paste API key now", hint: params.copy?.plaintextHint ?? "Stores the key directly in OpenClaw config" }, { value: "ref", label: params.copy?.refLabel ?? "Use external secret provider", hint: params.copy?.refHint ?? "Stores a reference to env or configured external secret providers" }] })) === "ref" ? "ref" : "plaintext"; } //#endregion //#region src/plugin-sdk/onboarding.ts async function promptAccountId$1(params) { const existingIds = params.listAccountIds(params.cfg); const initial = params.currentId?.trim() || params.defaultAccountId || "default"; const choice = await params.prompter.select({ message: `${params.label} account`, options: [...existingIds.map((id) => ({ value: id, label: id === "default" ? "default (primary)" : id })), { value: "__new__", label: "Add a new account" }], initialValue: initial }); if (choice !== "__new__") return (0, _runWithConcurrency2ga3CMk.ut)(choice); const entered = await params.prompter.text({ message: `New ${params.label} account id`, validate: (value) => value?.trim() ? void 0 : "Required" }); const normalized = (0, _runWithConcurrency2ga3CMk.ut)(String(entered)); if (String(entered).trim() !== normalized) await params.prompter.note(`Normalized account id to "${normalized}".`, `${params.label} account`); return normalized; } //#endregion //#region src/channels/plugins/setup-helpers.ts function channelHasAccounts(cfg, channelKey) { const base = cfg.channels?.[channelKey]; return Boolean(base?.accounts && Object.keys(base.accounts).length > 0); } function shouldStoreNameInAccounts(params) { if (params.alwaysUseAccounts) return true; if (params.accountId !== "default") return true; return channelHasAccounts(params.cfg, params.channelKey); } function applyAccountNameToChannelSection(params) { const trimmed = params.name?.trim(); if (!trimmed) return params.cfg; const accountId = (0, _runWithConcurrency2ga3CMk.ut)(params.accountId); const baseConfig = params.cfg.channels?.[params.channelKey]; const base = typeof baseConfig === "object" && baseConfig ? baseConfig : void 0; if (!shouldStoreNameInAccounts({ cfg: params.cfg, channelKey: params.channelKey, accountId, alwaysUseAccounts: params.alwaysUseAccounts }) && accountId === "default") { const safeBase = base ?? {}; return { ...params.cfg, channels: { ...params.cfg.channels, [params.channelKey]: { ...safeBase, name: trimmed } } }; } const baseAccounts = base?.accounts ?? {}; const existingAccount = baseAccounts[accountId] ?? {}; const baseWithoutName = accountId === "default" ? (({ name: _ignored, ...rest }) => rest)(base ?? {}) : base ?? {}; return { ...params.cfg, channels: { ...params.cfg.channels, [params.channelKey]: { ...baseWithoutName, accounts: { ...baseAccounts, [accountId]: { ...existingAccount, name: trimmed } } } } }; } function migrateBaseNameToDefaultAccount(params) { if (params.alwaysUseAccounts) return params.cfg; const base = params.cfg.channels?.[params.channelKey]; const baseName = base?.name?.trim(); if (!baseName) return params.cfg; const accounts = { ...base?.accounts }; const defaultAccount = accounts["default"] ?? {}; if (!defaultAccount.name) accounts[_runWithConcurrency2ga3CMk.lt] = { ...defaultAccount, name: baseName }; const { name: _ignored, ...rest } = base ?? {}; return { ...params.cfg, channels: { ...params.cfg.channels, [params.channelKey]: { ...rest, accounts } } }; } const COMMON_SINGLE_ACCOUNT_KEYS_TO_MOVE = new Set([ "name", "token", "tokenFile", "botToken", "appToken", "account", "signalNumber", "authDir", "cliPath", "dbPath", "httpUrl", "httpHost", "httpPort", "webhookPath", "webhookUrl", "webhookSecret", "service", "region", "homeserver", "userId", "accessToken", "password", "deviceName", "url", "code", "dmPolicy", "allowFrom", "groupPolicy", "groupAllowFrom", "defaultTo"] ); const SINGLE_ACCOUNT_KEYS_TO_MOVE_BY_CHANNEL = { telegram: new Set(["streaming"]) }; function shouldMoveSingleAccountChannelKey(params) { if (COMMON_SINGLE_ACCOUNT_KEYS_TO_MOVE.has(params.key)) return true; return SINGLE_ACCOUNT_KEYS_TO_MOVE_BY_CHANNEL[params.channelKey]?.has(params.key) ?? false; } function cloneIfObject(value) { if (value && typeof value === "object") return structuredClone(value); return value; } function moveSingleAccountChannelSectionToDefaultAccount(params) { const baseConfig = params.cfg.channels?.[params.channelKey]; const base = typeof baseConfig === "object" && baseConfig ? baseConfig : void 0; if (!base) return params.cfg; const accounts = base.accounts ?? {}; if (Object.keys(accounts).length > 0) return params.cfg; const keysToMove = Object.entries(base).filter(([key, value]) => key !== "accounts" && key !== "enabled" && value !== void 0 && shouldMoveSingleAccountChannelKey({ channelKey: params.channelKey, key })).map(([key]) => key); const defaultAccount = {}; for (const key of keysToMove) { const value = base[key]; defaultAccount[key] = cloneIfObject(value); } const nextChannel = { ...base }; for (const key of keysToMove) delete nextChannel[key]; return { ...params.cfg, channels: { ...params.cfg.channels, [params.channelKey]: { ...nextChannel, accounts: { ...accounts, [_runWithConcurrency2ga3CMk.lt]: defaultAccount } } } }; } //#endregion //#region src/channels/plugins/onboarding/helpers.ts const promptAccountId = async (params) => { return await promptAccountId$1(params); };exports.promptAccountId = promptAccountId; function addWildcardAllowFrom(allowFrom) { const next = (allowFrom ?? []).map((v) => String(v).trim()).filter(Boolean); if (!next.includes("*")) next.push("*"); return next; } function mergeAllowFromEntries(current, additions) { const merged = [...(current ?? []), ...additions].map((v) => String(v).trim()).filter(Boolean); return [...new Set(merged)]; } function splitOnboardingEntries(raw) { return raw.split(/[\n,;]+/g).map((entry) => entry.trim()).filter(Boolean); } function parseOnboardingEntriesWithParser(raw, parseEntry) { const parts = splitOnboardingEntries(String(raw ?? "")); const entries = []; for (const part of parts) { const parsed = parseEntry(part); if ("error" in parsed) return { entries: [], error: parsed.error }; entries.push(parsed.value); } return { entries: normalizeAllowFromEntries(entries) }; } function parseOnboardingEntriesAllowingWildcard(raw, parseEntry) { return parseOnboardingEntriesWithParser(raw, (entry) => { if (entry === "*") return { value: "*" }; return parseEntry(entry); }); } function parseMentionOrPrefixedId(params) { const trimmed = params.value.trim(); if (!trimmed) return null; const mentionMatch = trimmed.match(params.mentionPattern); if (mentionMatch?.[1]) return params.normalizeId ? params.normalizeId(mentionMatch[1]) : mentionMatch[1]; const stripped = params.prefixPattern ? trimmed.replace(params.prefixPattern, "") : trimmed; if (!params.idPattern.test(stripped)) return null; return params.normalizeId ? params.normalizeId(stripped) : stripped; } function normalizeAllowFromEntries(entries, normalizeEntry) { const normalized = entries.map((entry) => String(entry).trim()).filter(Boolean).map((entry) => { if (entry === "*") return "*"; if (!normalizeEntry) return entry; const value = normalizeEntry(entry); return typeof value === "string" ? value.trim() : ""; }).filter(Boolean); return [...new Set(normalized)]; } function resolveOnboardingAccountId(params) { return params.accountId?.trim() ? (0, _runWithConcurrency2ga3CMk.ut)(params.accountId) : params.defaultAccountId; } async function resolveAccountIdForConfigure(params) { const override = params.accountOverride?.trim(); let accountId = override ? (0, _runWithConcurrency2ga3CMk.ut)(override) : params.defaultAccountId; if (params.shouldPromptAccountIds && !override) accountId = await promptAccountId({ cfg: params.cfg, prompter: params.prompter, label: params.label, currentId: accountId, listAccountIds: params.listAccountIds, defaultAccountId: params.defaultAccountId }); return accountId; } function setAccountAllowFromForChannel(params) { const { cfg, channel, accountId, allowFrom } = params; return patchConfigForScopedAccount({ cfg, channel, accountId, patch: { allowFrom }, ensureEnabled: false }); } function setTopLevelChannelAllowFrom(params) { const channelConfig = params.cfg.channels?.[params.channel] ?? {}; return { ...params.cfg, channels: { ...params.cfg.channels, [params.channel]: { ...channelConfig, ...(params.enabled ? { enabled: true } : {}), allowFrom: params.allowFrom } } }; } function setTopLevelChannelDmPolicyWithAllowFrom(params) { const channelConfig = params.cfg.channels?.[params.channel] ?? {}; const existingAllowFrom = params.getAllowFrom?.(params.cfg) ?? channelConfig.allowFrom ?? void 0; const allowFrom = params.dmPolicy === "open" ? addWildcardAllowFrom(existingAllowFrom) : void 0; return { ...params.cfg, channels: { ...params.cfg.channels, [params.channel]: { ...channelConfig, dmPolicy: params.dmPolicy, ...(allowFrom ? { allowFrom } : {}) } } }; } function setTopLevelChannelGroupPolicy(params) { const channelConfig = params.cfg.channels?.[params.channel] ?? {}; return { ...params.cfg, channels: { ...params.cfg.channels, [params.channel]: { ...channelConfig, ...(params.enabled ? { enabled: true } : {}), groupPolicy: params.groupPolicy } } }; } function setChannelDmPolicyWithAllowFrom(params) { const { cfg, channel, dmPolicy } = params; const allowFrom = dmPolicy === "open" ? addWildcardAllowFrom(cfg.channels?.[channel]?.allowFrom) : void 0; return { ...cfg, channels: { ...cfg.channels, [channel]: { ...cfg.channels?.[channel], dmPolicy, ...(allowFrom ? { allowFrom } : {}) } } }; } function setLegacyChannelDmPolicyWithAllowFrom(params) { const channelConfig = params.cfg.channels?.[params.channel] ?? { allowFrom: void 0, dm: void 0 }; const existingAllowFrom = channelConfig.allowFrom ?? channelConfig.dm?.allowFrom; const allowFrom = params.dmPolicy === "open" ? addWildcardAllowFrom(existingAllowFrom) : void 0; return patchLegacyDmChannelConfig({ cfg: params.cfg, channel: params.channel, patch: { dmPolicy: params.dmPolicy, ...(allowFrom ? { allowFrom } : {}) } }); } function setLegacyChannelAllowFrom(params) { return patchLegacyDmChannelConfig({ cfg: params.cfg, channel: params.channel, patch: { allowFrom: params.allowFrom } }); } function setAccountGroupPolicyForChannel(params) { return patchChannelConfigForAccount({ cfg: params.cfg, channel: params.channel, accountId: params.accountId, patch: { groupPolicy: params.groupPolicy } }); } function patchLegacyDmChannelConfig(params) { const { cfg, channel, patch } = params; const channelConfig = cfg.channels?.[channel] ?? {}; const dmConfig = channelConfig.dm ?? {}; return { ...cfg, channels: { ...cfg.channels, [channel]: { ...channelConfig, ...patch, dm: { ...dmConfig, enabled: typeof dmConfig.enabled === "boolean" ? dmConfig.enabled : true } } } }; } function setOnboardingChannelEnabled(cfg, channel, enabled) { const channelConfig = cfg.channels?.[channel] ?? {}; return { ...cfg, channels: { ...cfg.channels, [channel]: { ...channelConfig, enabled } } }; } function patchConfigForScopedAccount(params) { const { cfg, channel, accountId, patch, ensureEnabled } = params; const seededCfg = accountId === "default" ? cfg : moveSingleAccountChannelSectionToDefaultAccount({ cfg, channelKey: channel }); const channelConfig = seededCfg.channels?.[channel] ?? {}; if (accountId === "default") return { ...seededCfg, channels: { ...seededCfg.channels, [channel]: { ...channelConfig, ...(ensureEnabled ? { enabled: true } : {}), ...patch } } }; const accounts = channelConfig.accounts ?? {}; const existingAccount = accounts[accountId] ?? {}; return { ...seededCfg, channels: { ...seededCfg.channels, [channel]: { ...channelConfig, ...(ensureEnabled ? { enabled: true } : {}), accounts: { ...accounts, [accountId]: { ...existingAccount, ...(ensureEnabled ? { enabled: typeof existingAccount.enabled === "boolean" ? existingAccount.enabled : true } : {}), ...patch } } } } }; } function patchChannelConfigForAccount(params) { return patchConfigForScopedAccount({ ...params, ensureEnabled: true }); } function applySingleTokenPromptResult(params) { let next = params.cfg; if (params.tokenResult.useEnv) next = patchChannelConfigForAccount({ cfg: next, channel: params.channel, accountId: params.accountId, patch: {} }); if (params.tokenResult.token) next = patchChannelConfigForAccount({ cfg: next, channel: params.channel, accountId: params.accountId, patch: { [params.tokenPatchKey]: params.tokenResult.token } }); return next; } function buildSingleChannelSecretPromptState(params) { return { accountConfigured: params.accountConfigured, hasConfigToken: params.hasConfigToken, canUseEnv: params.allowEnv && Boolean(params.envValue?.trim()) && !params.hasConfigToken }; } async function promptSingleChannelToken(params) { const promptToken = async () => String(await params.prompter.text({ message: params.inputPrompt, validate: (value) => value?.trim() ? void 0 : "Required" })).trim(); if (params.canUseEnv) { if (await params.prompter.confirm({ message: params.envPrompt, initialValue: true })) return { useEnv: true, token: null }; return { useEnv: false, token: await promptToken() }; } if (params.hasConfigToken && params.accountConfigured) { if (await params.prompter.confirm({ message: params.keepPrompt, initialValue: true })) return { useEnv: false, token: null }; } return { useEnv: false, token: await promptToken() }; } async function promptSingleChannelSecretInput(params) { if ((await resolveSecretInputModeForEnvSelection({ prompter: params.prompter, explicitMode: params.secretInputMode, copy: { modeMessage: `How do you want to provide this ${params.credentialLabel}?`, plaintextLabel: `Enter ${params.credentialLabel}`, plaintextHint: "Stores the credential directly in OpenClaw config", refLabel: "Use external secret provider", refHint: "Stores a reference to env or configured external secret providers" } })) === "plaintext") { const plainResult = await promptSingleChannelToken({ prompter: params.prompter, accountConfigured: params.accountConfigured, canUseEnv: params.canUseEnv, hasConfigToken: params.hasConfigToken, envPrompt: params.envPrompt, keepPrompt: params.keepPrompt, inputPrompt: params.inputPrompt }); if (plainResult.useEnv) return { action: "use-env" }; if (plainResult.token) return { action: "set", value: plainResult.token, resolvedValue: plainResult.token }; return { action: "keep" }; } if (params.hasConfigToken && params.accountConfigured) { if (await params.prompter.confirm({ message: params.keepPrompt, initialValue: true })) return { action: "keep" }; } const resolved = await promptSecretRefForOnboarding({ provider: params.providerHint, config: params.cfg, prompter: params.prompter, preferredEnvVar: params.preferredEnvVar, copy: { sourceMessage: `Where is this ${params.credentialLabel} stored?`, envVarPlaceholder: params.preferredEnvVar ?? "OPENCLAW_SECRET", envVarFormatError: "Use an env var name like \"OPENCLAW_SECRET\" (uppercase letters, numbers, underscores).", noProvidersMessage: "No file/exec secret providers are configured yet. Add one under secrets.providers, or select Environment variable." } }); return { action: "set", value: resolved.ref, resolvedValue: resolved.resolvedValue }; } async function promptParsedAllowFromForScopedChannel(params) { const accountId = resolveOnboardingAccountId({ accountId: params.accountId, defaultAccountId: params.defaultAccountId }); const existing = params.getExistingAllowFrom({ cfg: params.cfg, accountId }); await params.prompter.note(params.noteLines.join("\n"), params.noteTitle); const entry = await params.prompter.text({ message: params.message, placeholder: params.placeholder, initialValue: existing[0] ? String(existing[0]) : void 0, validate: (value) => { const raw = String(value ?? "").trim(); if (!raw) return "Required"; return params.parseEntries(raw).error; } }); const unique = mergeAllowFromEntries(void 0, params.parseEntries(String(entry)).entries); return setAccountAllowFromForChannel({ cfg: params.cfg, channel: params.channel, accountId, allowFrom: unique }); } async function noteChannelLookupSummary(params) { const lines = []; for (const section of params.resolvedSections) { if (section.values.length === 0) continue; lines.push(`${section.title}: ${section.values.join(", ")}`); } if (params.unresolved && params.unresolved.length > 0) lines.push(`Unresolved (kept as typed): ${params.unresolved.join(", ")}`); if (lines.length > 0) await params.prompter.note(lines.join("\n"), params.label); } async function noteChannelLookupFailure(params) { await params.prompter.note(`Channel lookup failed; keeping entries as typed. ${String(params.error)}`, params.label); } async function promptResolvedAllowFrom(params) { while (true) { const entry = await params.prompter.text({ message: params.message, placeholder: params.placeholder, initialValue: params.existing[0] ? String(params.existing[0]) : void 0, validate: (value) => String(value ?? "").trim() ? void 0 : "Required" }); const parts = params.parseInputs(String(entry)); if (!params.token) { const ids = parts.map(params.parseId).filter(Boolean); if (ids.length !== parts.length) { await params.prompter.note(params.invalidWithoutTokenNote, params.label); continue; } return mergeAllowFromEntries(params.existing, ids); } const results = await params.resolveEntries({ token: params.token, entries: parts }).catch(() => null); if (!results) { await params.prompter.note("Failed to resolve usernames. Try again.", params.label); continue; } const unresolved = results.filter((res) => !res.resolved || !res.id); if (unresolved.length > 0) { await params.prompter.note(`Could not resolve: ${unresolved.map((res) => res.input).join(", ")}`, params.label); continue; } const ids = results.map((res) => res.id); return mergeAllowFromEntries(params.existing, ids); } } async function promptLegacyChannelAllowFrom(params) { await params.prompter.note(params.noteLines.join("\n"), params.noteTitle); const unique = await promptResolvedAllowFrom({ prompter: params.prompter, existing: params.existing, token: params.token, message: params.message, placeholder: params.placeholder, label: params.noteTitle, parseInputs: splitOnboardingEntries, parseId: params.parseId, invalidWithoutTokenNote: params.invalidWithoutTokenNote, resolveEntries: params.resolveEntries }); return setLegacyChannelAllowFrom({ cfg: params.cfg, channel: params.channel, allowFrom: unique }); } //#endregion //#region src/plugin-sdk/provider-auth-result.ts function buildOauthProviderAuthResult(params) { const email = params.email ?? void 0; return { profiles: [{ profileId: `${params.profilePrefix ?? params.providerId}:${email ?? "default"}`, credential: { type: "oauth", provider: params.providerId, access: params.access, ...(params.refresh ? { refresh: params.refresh } : {}), ...(Number.isFinite(params.expires) ? { expires: params.expires } : {}), ...(email ? { email } : {}), ...params.credentialExtra } }], configPatch: params.configPatch ?? { agents: { defaults: { models: { [params.defaultModel]: {} } } } }, defaultModel: params.defaultModel, notes: params.notes }; } //#endregion //#region src/plugin-sdk/resolution-notes.ts function formatResolvedUnresolvedNote(params) { if (params.resolved.length === 0 && params.unresolved.length === 0) return; return [params.resolved.length > 0 ? `Resolved: ${params.resolved.join(", ")}` : void 0, params.unresolved.length > 0 ? `Unresolved (kept as typed): ${params.unresolved.join(", ")}` : void 0].filter(Boolean).join("\n"); } //#endregion //#region src/plugin-sdk/channel-send-result.ts function buildChannelSendResult(channel, result) { return { channel, ok: result.ok, messageId: result.messageId ?? "", error: result.error ? new Error(result.error) : void 0 }; } //#endregion //#region src/plugin-sdk/runtime-store.ts function createPluginRuntimeStore(errorMessage) { let runtime = null; return { setRuntime(next) { runtime = next; }, clearRuntime() { runtime = null; }, tryGetRuntime() { return runtime; }, getRuntime() { if (!runtime) throw new Error(errorMessage); return runtime; } }; } //#endregion //#region src/channels/plugins/config-schema.ts const AllowFromEntrySchema = exports.AllowFromEntrySchema = _zod.z.union([_zod.z.string(), _zod.z.number()]); function buildCatchallMultiAccountChannelSchema(accountSchema) { return accountSchema.extend({ accounts: _zod.z.object({}).catchall(accountSchema).optional(), defaultAccount: _zod.z.string().optional() }); } function buildChannelConfigSchema(schema) { const schemaWithJson = schema; if (typeof schemaWithJson.toJSONSchema === "function") return { schema: schemaWithJson.toJSONSchema({ target: "draft-07", unrepresentable: "any" }) }; return { schema: { type: "object", additionalProperties: true } }; } //#endregion //#region src/plugin-sdk/command-auth.ts function resolveDirectDmAuthorizationOutcome(params) { if (params.isGroup) return "allowed"; if (params.dmPolicy === "disabled") return "disabled"; if (params.dmPolicy !== "open" && !params.senderAllowedForCommands) return "unauthorized"; return "allowed"; } async function resolveSenderCommandAuthorizationWithRuntime(params) { return resolveSenderCommandAuthorization({ ...params, shouldComputeCommandAuthorized: params.runtime.shouldComputeCommandAuthorized, resolveCommandAuthorizedFromAuthorizers: params.runtime.resolveCommandAuthorizedFromAuthorizers }); } async function resolveSenderCommandAuthorization(params) { const shouldComputeAuth = params.shouldComputeCommandAuthorized(params.rawBody, params.cfg); const storeAllowFrom = !params.isGroup && params.dmPolicy !== "allowlist" && (params.dmPolicy !== "open" || shouldComputeAuth) ? await params.readAllowFromStore().catch(() => []) : []; const access = (0, _dispatchF_Zbttj.Gt)({ isGroup: params.isGroup, dmPolicy: params.dmPolicy, groupPolicy: "allowlist", allowFrom: params.configuredAllowFrom, groupAllowFrom: params.configuredGroupAllowFrom ?? [], storeAllowFrom, isSenderAllowed: (allowFrom) => params.isSenderAllowed(params.senderId, allowFrom) }); const effectiveAllowFrom = access.effectiveAllowFrom; const effectiveGroupAllowFrom = access.effectiveGroupAllowFrom; const useAccessGroups = params.cfg.commands?.useAccessGroups !== false; const senderAllowedForCommands = params.isSenderAllowed(params.senderId, params.isGroup ? effectiveGroupAllowFrom : effectiveAllowFrom); const ownerAllowedForCommands = params.isSenderAllowed(params.senderId, effectiveAllowFrom); const groupAllowedForCommands = params.isSenderAllowed(params.senderId, effectiveGroupAllowFrom); return { shouldComputeAuth, effectiveAllowFrom, effectiveGroupAllowFrom, senderAllowedForCommands, commandAuthorized: shouldComputeAuth ? params.resolveCommandAuthorizedFromAuthorizers({ useAccessGroups, authorizers: [{ configured: effectiveAllowFrom.length > 0, allowed: ownerAllowedForCommands }, { configured: effectiveGroupAllowFrom.length > 0, allowed: groupAllowedForCommands }] }) : void 0 }; } //#endregion //#region src/plugin-sdk/pairing-access.ts function createScopedPairingAccess(params) { const resolvedAccountId = (0, _runWithConcurrency2ga3CMk.ut)(params.accountId); return { accountId: resolvedAccountId, readAllowFromStore: () => params.core.channel.pairing.readAllowFromStore({ channel: params.channel, accountId: resolvedAccountId }), readStoreForDmPolicy: (provider, accountId) => params.core.channel.pairing.readAllowFromStore({ channel: provider, accountId: (0, _runWithConcurrency2ga3CMk.ut)(accountId) }), upsertPairingRequest: (input) => params.core.channel.pairing.upsertPairingRequest({ channel: params.channel, accountId: resolvedAccountId, ...input }) }; } //#endregion //#region src/plugin-sdk/inbound-envelope.ts function createInboundEnvelopeBuilder(params) { const storePath = params.resolveStorePath(params.sessionStore, { agentId: params.route.agentId }); const envelopeOptions = params.resolveEnvelopeFormatOptions(params.cfg); return (input) => { const previousTimestamp = params.readSessionUpdatedAt({ storePath, sessionKey: params.route.sessionKey }); return { storePath, body: params.formatAgentEnvelope({ channel: input.channel, from: input.from, timestamp: input.timestamp, previousTimestamp, envelope: envelopeOptions, body: input.body }) }; }; } function resolveInboundRouteEnvelopeBuilder(params) { const route = params.resolveAgentRoute({ cfg: params.cfg, channel: params.channel, accountId: params.accountId, peer: params.peer }); return { route, buildEnvelope: createInboundEnvelopeBuilder({ cfg: params.cfg, route, sessionStore: params.sessionStore, resolveStorePath: params.resolveStorePath, readSessionUpdatedAt: params.readSessionUpdatedAt, resolveEnvelopeFormatOptions: params.resolveEnvelopeFormatOptions, formatAgentEnvelope: params.formatAgentEnvelope }) }; } function resolveInboundRouteEnvelopeBuilderWithRuntime(params) { return resolveInboundRouteEnvelopeBuilder({ cfg: params.cfg, channel: params.channel, accountId: params.accountId, peer: params.peer, resolveAgentRoute: (routeParams) => params.runtime.routing.resolveAgentRoute(routeParams), sessionStore: params.sessionStore, resolveStorePath: params.runtime.session.resolveStorePath, readSessionUpdatedAt: params.runtime.session.readSessionUpdatedAt, resolveEnvelopeFormatOptions: params.runtime.reply.resolveEnvelopeFormatOptions, formatAgentEnvelope: params.runtime.reply.formatAgentEnvelope }); } //#endregion //#region src/plugin-sdk/slack-message-actions.ts function readSlackBlocksParam(actionParams) { return (0, _sendCoJpuv4Y.s)(actionParams.blocks); } async function handleSlackMessageAction(params) { const { providerId, ctx, invoke, normalizeChannelId, includeReadThreadId = false } = params; const { action, cfg, params: actionParams } = ctx; const accountId = ctx.accountId ?? void 0; const resolveChannelId = () => { const channelId = (0, _targetErrorsByT48YHg.h)(actionParams, "channelId") ?? (0, _targetErrorsByT48YHg.h)(actionParams, "to", { required: true }); return normalizeChannelId ? normalizeChannelId(channelId) : channelId; }; if (action === "send") { const to = (0, _targetErrorsByT48YHg.h)(actionParams, "to", { required: true }); const content = (0, _targetErrorsByT48YHg.h)(actionParams, "message", { required: false, allowEmpty: true }); const mediaUrl = (0, _targetErrorsByT48YHg.h)(actionParams, "media", { trim: false }); const blocks = readSlackBlocksParam(actionParams); if (!content && !mediaUrl && !blocks) throw new Error("Slack send requires message, blocks, or media."); if (mediaUrl && blocks) throw new Error("Slack send does not support blocks with media."); const threadId = (0, _targetErrorsByT48YHg.h)(actionParams, "threadId"); const replyTo = (0, _targetErrorsByT48YHg.h)(actionParams, "replyTo"); return await invoke({ action: "sendMessage", to, content: content ?? "", mediaUrl: mediaUrl ?? void 0, blocks, accountId, threadTs: threadId ?? replyTo ?? void 0 }, cfg, ctx.toolContext); } if (action === "react") { const messageId = (0, _targetErrorsByT48YHg.h)(actionParams, "messageId", { required: true }); const emoji = (0, _targetErrorsByT48YHg.h)(actionParams, "emoji", { allowEmpty: true }); const remove = typeof actionParams.remove === "boolean" ? actionParams.remove : void 0; return await invoke({ action: "react", channelId: resolveChannelId(), messageId, emoji, remove, accountId }, cfg); } if (action === "reactions") { const messageId = (0, _targetErrorsByT48YHg.h)(actionParams, "messageId", { required: true }); const limit = (0, _targetErrorsByT48YHg.d)(actionParams, "limit", { integer: true }); return await invoke({ action: "reactions", channelId: resolveChannelId(), messageId, limit, accountId }, cfg); } if (action === "read") { const limit = (0, _targetErrorsByT48YHg.d)(actionParams, "limit", { integer: true }); const readAction = { action: "readMessages", channelId: resolveChannelId(), limit, before: (0, _targetErrorsByT48YHg.h)(actionParams, "before"), after: (0, _targetErrorsByT48YHg.h)(actionParams, "after"), accountId }; if (includeReadThreadId) readAction.threadId = (0, _targetErrorsByT48YHg.h)(actionParams, "threadId"); return await invoke(readAction, cfg); } if (action === "edit") { const messageId = (0, _targetErrorsByT48YHg.h)(actionParams, "messageId", { required: true }); const content = (0, _targetErrorsByT48YHg.h)(actionParams, "message", { allowEmpty: true }); const blocks = readSlackBlocksParam(actionParams); if (!content && !blocks) throw new Error("Slack edit requires message or blocks."); return await invoke({ action: "editMessage", channelId: resolveChannelId(), messageId, content: content ?? "", blocks, accountId }, cfg); } if (action === "delete") { const messageId = (0, _targetErrorsByT48YHg.h)(actionParams, "messageId", { required: true }); return await invoke({ action: "deleteMessage", channelId: resolveChannelId(), messageId, accountId }, cfg); } if (action === "pin" || action === "unpin" || action === "list-pins") { const messageId = action === "list-pins" ? void 0 : (0, _targetErrorsByT48YHg.h)(actionParams, "messageId", { required: true }); return await invoke({ action: action === "pin" ? "pinMessage" : action === "unpin" ? "unpinMessage" : "listPins", channelId: resolveChannelId(), messageId, accountId }, cfg); } if (action === "member-info") return await invoke({ action: "memberInfo", userId: (0, _targetErrorsByT48YHg.h)(actionParams, "userId", { required: true }), accountId }, cfg); if (action === "emoji-list") return await invoke({ action: "emojiList", limit: (0, _targetErrorsByT48YHg.d)(actionParams, "limit", { integer: true }), accountId }, cfg); if (action === "download-file") { const fileId = (0, _targetErrorsByT48YHg.h)(actionParams, "fileId", { required: true }); const channelId = (0, _targetErrorsByT48YHg.h)(actionParams, "channelId") ?? (0, _targetErrorsByT48YHg.h)(actionParams, "to"); const threadId = (0, _targetErrorsByT48YHg.h)(actionParams, "threadId") ?? (0, _targetErrorsByT48YHg.h)(actionParams, "replyTo"); return await invoke({ action: "downloadFile", fileId, channelId: channelId ?? void 0, threadId: threadId ?? void 0, accountId }, cfg); } throw new Error(`Action ${action} is not supported for provider ${providerId}.`); } //#endregion //#region src/plugin-sdk/reply-payload.ts function normalizeOutboundReplyPayload(payload) { return { text: typeof payload.text === "string" ? payload.text : void 0, mediaUrls: Array.isArray(payload.mediaUrls) ? payload.mediaUrls.filter((entry) => typeof entry === "string" && entry.length > 0) : void 0, mediaUrl: typeof payload.mediaUrl === "string" ? payload.mediaUrl : void 0, replyToId: typeof payload.replyToId === "string" ? payload.replyToId : void 0 }; } function createNormalizedOutboundDeliverer(handler) { return async (payload) => { await handler(payload && typeof payload === "object" ? normalizeOutboundReplyPayload(payload) : {}); }; } function resolveOutboundMediaUrls(payload) { if (payload.mediaUrls?.length) return payload.mediaUrls; if (payload.mediaUrl) return [payload.mediaUrl]; return []; } async function sendPayloadWithChunkedTextAndMedia(params) { const payload = params.ctx.payload; const text = payload.text ?? ""; const urls = resolveOutboundMediaUrls(payload); if (!text && urls.length === 0) return params.emptyResult; if (urls.length > 0) { let lastResult = await params.sendMedia({ ...params.ctx, text, mediaUrl: urls[0] }); for (let i = 1; i < urls.length; i++) lastResult = await params.sendMedia({ ...params.ctx, text: "", mediaUrl: urls[i] }); return lastResult; } const limit = params.textChunkLimit; const chunks = limit && params.chunker ? params.chunker(text, limit) : [text]; let lastResult; for (const chunk of chunks) lastResult = await params.sendText({ ...params.ctx, text: chunk }); return lastResult; } function isNumericTargetId(raw) { const trimmed = raw.trim(); if (!trimmed) return false; return /^\d{3,}$/.test(trimmed); } function formatTextWithAttachmentLinks(text, mediaUrls) { const trimmedText = text?.trim() ?? ""; if (!trimmedText && mediaUrls.length === 0) return ""; const mediaBlock = mediaUrls.length ? mediaUrls.map((url) => `Attachment: ${url}`).join("\n") : ""; if (!trimmedText) return mediaBlock; if (!mediaBlock) return trimmedText; return `${trimmedText}\n\n${mediaBlock}`; } async function sendMediaWithLeadingCaption(params) { if (params.mediaUrls.length === 0) return false; let first = true; for (const mediaUrl of params.mediaUrls) { const caption = first ? params.caption : void 0; first = false; try { await params.send({ mediaUrl, caption }); } catch (error) { if (params.onError) { params.onError(error, mediaUrl); continue; } throw error; } } return true; } //#endregion //#region src/line/flex-templates/basic-cards.ts /** * Create an info card with title, body, and optional footer * * Editorial design: Clean hierarchy with accent bar, generous spacing, * and subtle background zones for visual separation. */ function createInfoCard(title, body, footer) { const bubble = { type: "bubble", size: "mega", body: { type: "box", layout: "vertical", contents: [{ type: "box", layout: "horizontal", contents: [{ type: "box", layout: "vertical", contents: [], width: "4px", backgroundColor: "#06C755", cornerRadius: "2px" }, { type: "text", text: title, weight: "bold", size: "xl", color: "#111111", wrap: true, flex: 1, margin: "lg" }] }, { type: "box", layout: "vertical", contents: [{ type: "text", text: body, size: "md", color: "#444444", wrap: true, lineSpacing: "6px" }], margin: "xl", paddingAll: "lg", backgroundColor: "#F8F9FA", cornerRadius: "lg" }], paddingAll: "xl", backgroundColor: "#FFFFFF" } }; if (footer) (0, _dispatchF_Zbttj.jt)(bubble, footer); return bubble; } /** * Create a list card with title and multiple items * * Editorial design: Numbered/bulleted list with clear visual hierarchy, * accent dots for each item, and generous spacing. */ function createListCard(title, items) { const itemContents = items.slice(0, 8).map((item, index) => { const itemContents = [{ type: "text", text: item.title, size: "md", weight: "bold", color: "#1a1a1a", wrap: true }]; if (item.subtitle) itemContents.push({ type: "text", text: item.subtitle, size: "sm", color: "#888888", wrap: true, margin: "xs" }); const itemBox = { type: "box", layout: "horizontal", contents: [{ type: "box", layout: "vertical", contents: [{ type: "box", layout: "vertical", contents: [], width: "8px", height: "8px", backgroundColor: index === 0 ? "#06C755" : "#DDDDDD", cornerRadius: "4px" }], width: "20px", alignItems: "center", paddingTop: "sm" }, { type: "box", layout: "vertical", contents: itemContents, flex: 1 }], margin: index > 0 ? "lg" : void 0 }; if (item.action) itemBox.action = item.action; return itemBox; }); return { type: "bubble", size: "mega", body: { type: "box", layout: "vertical", contents: [ { type: "text", text: title, weight: "bold", size: "xl", color: "#111111", wrap: true }, { type: "separator", margin: "lg", color: "#EEEEEE" }, { type: "box", layout: "vertical", contents: itemContents, margin: "lg" }], paddingAll: "xl", backgroundColor: "#FFFFFF" } }; } /** * Create an image card with image, title, and optional body text */ function createImageCard(imageUrl, title, body, options) { const bubble = { type: "bubble", hero: { type: "image", url: imageUrl, size: "full", aspectRatio: options?.aspectRatio ?? "20:13", aspectMode: options?.aspectMode ?? "cover", action: options?.action }, body: { type: "box", layout: "vertical", contents: [{ type: "text", text: title, weight: "bold", size: "xl", wrap: true }], paddingAll: "lg" } }; if (body && bubble.body) bubble.body.contents.push({ type: "text", text: body, size: "md", wrap: true, margin: "md", color: "#666666" }); return bubble; } /** * Create an action card with title, body, and action buttons */ function createActionCard(title, body, actions, options) { const bubble = { type: "bubble", body: { type: "box", layout: "vertical", contents: [{ type: "text", text: title, weight: "bold", size: "xl", wrap: true }, { type: "text", text: body, size: "md", wrap: true, margin: "md", color: "#666666" }], paddingAll: "lg" }, footer: { type: "box", layout: "vertical", contents: actions.slice(0, 4).map((action, index) => ({ type: "button", action: action.action, style: index === 0 ? "primary" : "secondary", margin: index > 0 ? "sm" : void 0 })), paddingAll: "md" } }; if (options?.imageUrl) bubble.hero = { type: "image", url: options.imageUrl, size: "full", aspectRatio: options.aspectRatio ?? "20:13", aspectMode: "cover" }; return bubble; } //#endregion //#region src/plugin-sdk/inbound-reply-dispatch.ts async function dispatchReplyFromConfigWithSettledDispatcher(params) { return await (0, _dispatchF_Zbttj.t)({ dispatcher: params.dispatcher, onSettled: params.onSettled, run: () => (0, _dispatchF_Zbttj.n)({ ctx: params.ctxPayload, cfg: params.cfg, dispatcher: params.dispatcher, replyOptions: params.replyOptions }) }); } function buildInboundReplyDispatchBase(params) { return { cfg: params.cfg, channel: params.channel, accountId: params.accountId, agentId: params.route.agentId, routeSessionKey: params.route.sessionKey, storePath: params.storePath, ctxPayload: params.ctxPayload, recordInboundSession: params.core.channel.session.recordInboundSession, dispatchReplyWithBufferedBlockDispatcher: params.core.channel.reply.dispatchReplyWithBufferedBlockDispatcher }; } async function dispatchInboundReplyWithBase(params) { await recordInboundSessionAndDispatchReply({ ...buildInboundReplyDispatchBase(params), deliver: params.deliver, onRecordError: params.onRecordError, onDispatchError: params.onDispatchError, replyOptions: params.replyOptions }); } async function recordInboundSessionAndDispatchReply(params) { await params.recordInboundSession({ storePath: params.storePath, sessionKey: params.ctxPayload.SessionKey ?? params.routeSessionKey, ctx: params.ctxPayload, onRecordError: params.onRecordError }); const { onModelSelected, ...prefixOptions } = (0, _dispatchF_Zbttj.j)({ cfg: params.cfg, agentId: params.agentId, channel: params.channel, accountId: params.accountId }); const deliver = createNormalizedOutboundDeliverer(params.deliver); await params.dispatchReplyWithBufferedBlockDispatcher({ ctx: params.ctxPayload, cfg: params.cfg, dispatcherOptions: { ...prefixOptions, deliver, onError: params.onDispatchError }, replyOptions: { ...params.replyOptions, onModelSelected } }); } //#endregion //#region src/plugin-sdk/outbound-media.ts async function loadOutboundMediaFromUrl(mediaUrl, options = {}) { return await (0, _irKp5uANes.v)(mediaUrl, { maxBytes: options.maxBytes, localRoots: options.mediaLocalRoots }); } //#endregion //#region src/plugin-sdk/config-paths.ts function resolveChannelAccountConfigBasePath(params) { const accounts = params.cfg.channels?.[params.channelKey]?.accounts; return Boolean(accounts?.[params.accountId]) ? `channels.${params.channelKey}.accounts.${params.accountId}.` : `channels.${params.channelKey}.`; } //#endregion //#region src/plugin-sdk/runtime.ts function createLoggerBackedRuntime(params) { return { log: (...args) => { params.logger.info((0, _nodeUtil.format)(...args)); }, error: (...args) => { params.logger.error((0, _nodeUtil.format)(...args)); }, exit: (code) => { throw params.exitError?.(code) ?? /* @__PURE__ */new Error(`exit ${code}`); } }; } function resolveRuntimeEnv(params) { return params.runtime ?? createLoggerBackedRuntime(params); } function resolveRuntimeEnvWithUnavailableExit(params) { return resolveRuntimeEnv({ runtime: params.runtime, logger: params.logger, exitError: () => new Error(params.unavailableMessage ?? "Runtime exit not available") }); } //#endregion //#region src/plugin-sdk/text-chunking.ts function chunkTextForOutbound(text, limit) { return (0, _irKp5uANes.p)(text, limit, (window) => { const lastNewline = window.lastIndexOf("\n"); const lastSpace = window.lastIndexOf(" "); return lastNewline > 0 ? lastNewline : lastSpace; }); } //#endregion //#region src/plugin-sdk/oauth-utils.ts function toFormUrlEncoded(data) { return Object.entries(data).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&"); } function generatePkceVerifierChallenge() { const verifier = (0, _nodeCrypto.randomBytes)(32).toString("base64url"); return { verifier, challenge: (0, _nodeCrypto.createHash)("sha256").update(verifier).digest("base64url") }; } //#endregion //#region src/plugin-sdk/run-command.ts async function runPluginCommandWithTimeout(options) { const [command] = options.argv; if (!command) return { code: 1, stdout: "", stderr: "command is required" }; try { const result = await (0, _runWithConcurrency2ga3CMk.D)(options.argv, { timeoutMs: options.timeoutMs, cwd: options.cwd, env: options.env }); const timedOut = result.termination === "timeout" || result.termination === "no-output-timeout"; return { code: result.code ?? 1, stdout: result.stdout, stderr: timedOut ? result.stderr || `command timed out after ${options.timeoutMs}ms` : result.stderr }; } catch (error) { return { code: 1, stdout: "", stderr: error instanceof Error ? error.message : String(error) }; } } //#endregion //#region src/shared/gateway-bind-url.ts function resolveGatewayBindUrl(params) { const bind = params.bind ?? "loopback"; if (bind === "custom") { const host = params.customBindHost?.trim(); if (host) return { url: `${params.scheme}://${host}:${params.port}`, source: "gateway.bind=custom" }; return { error: "gateway.bind=custom requires gateway.customBindHost." }; } if (bind === "tailnet") { const host = params.pickTailnetHost(); if (host) return { url: `${params.scheme}://${host}:${params.port}`, source: "gateway.bind=tailnet" }; return { error: "gateway.bind=tailnet set, but no tailnet IP was found." }; } if (bind === "lan") { const host = params.pickLanHost(); if (host) return { url: `${params.scheme}://${host}:${params.port}`, source: "gateway.bind=lan" }; return { error: "gateway.bind=lan set, but no private LAN IP was found." }; } return null; } //#endregion //#region src/shared/tailscale-status.ts const TAILSCALE_STATUS_COMMAND_CANDIDATES = ["tailscale", "/Applications/Tailscale.app/Contents/MacOS/Tailscale"]; function parsePossiblyNoisyJsonObject(raw) { const start = raw.indexOf("{"); const end = raw.lastIndexOf("}"); if (start === -1 || end <= start) return {}; try { return JSON.parse(raw.slice(start, end + 1)); } catch { return {}; } } function extractTailnetHostFromStatusJson(raw) { const parsed = parsePossiblyNoisyJsonObject(raw); const self = typeof parsed.Self === "object" && parsed.Self !== null ? parsed.Self : void 0; const dns = typeof self?.DNSName === "string" ? self.DNSName : void 0; if (dns && dns.length > 0) return dns.replace(/\.$/, ""); const ips = Array.isArray(self?.TailscaleIPs) ? self.TailscaleIPs : []; return ips.length > 0 ? ips[0] ?? null : null; } async function resolveTailnetHostWithRunner(runCommandWithTimeout) { if (!runCommandWithTimeout) return null; for (const candidate of TAILSCALE_STATUS_COMMAND_CANDIDATES) try { const result = await runCommandWithTimeout([ candidate, "status", "--json"], { timeoutMs: 5e3 }); if (result.code !== 0) continue; const raw = result.stdout.trim(); if (!raw) continue; const host = extractTailnetHostFromStatusJson(raw); if (host) return host; } catch { continue; } return null; } //#endregion //#region src/plugin-sdk/persistent-dedupe.ts const DEFAULT_LOCK_OPTIONS = { retries: { retries: 6, factor: 1.35, minTimeout: 8, maxTimeout: 180, randomize: true }, stale: 6e4 }; function mergeLockOptions(overrides) { return { stale: overrides?.stale ?? DEFAULT_LOCK_OPTIONS.stale, retries: { retries: overrides?.retries?.retries ?? DEFAULT_LOCK_OPTIONS.retries.retries, factor: overrides?.retries?.factor ?? DEFAULT_LOCK_OPTIONS.retries.factor, minTimeout: overrides?.retries?.minTimeout ?? DEFAULT_LOCK_OPTIONS.retries.minTimeout, maxTimeout: overrides?.retries?.maxTimeout ?? DEFAULT_LOCK_OPTIONS.retries.maxTimeout, randomize: overrides?.retries?.randomize ?? DEFAULT_LOCK_OPTIONS.retries.randomize } }; } function sanitizeData(value) { if (!value || typeof value !== "object") return {}; const out = {}; for (const [key, ts] of Object.entries(value)) if (typeof ts === "number" && Number.isFinite(ts) && ts > 0) out[key] = ts; return out; } function pruneData(data, now, ttlMs, maxEntries) { if (ttlMs > 0) { for (const [key, ts] of Object.entries(data)) if (now - ts >= ttlMs) delete data[key]; } const keys = Object.keys(data); if (keys.length <= maxEntries) return; keys.toSorted((a, b) => data[a] - data[b]).slice(0, keys.length - maxEntries).forEach((key) => { delete data[key]; }); } function createPersistentDedupe(options) { const ttlMs = Math.max(0, Math.floor(options.ttlMs)); const memoryMaxSize = Math.max(0, Math.floor(options.memoryMaxSize)); const fileMaxEntries = Math.max(1, Math.floor(options.fileMaxEntries)); const lockOptions = mergeLockOptions(options.lockOptions); const memory = (0, _dispatchF_Zbttj.ot)({ ttlMs, maxSize: memoryMaxSize }); const inflight = /* @__PURE__ */new Map(); async function checkAndRecordInner(key, namespace, scopedKey, now, onDiskError) { if (memory.check(scopedKey, now)) return false; const path = options.resolveFilePath(namespace); try { return !(await (0, _configDiiPndBn.Ir)(path, lockOptions, async () => { const { value } = await (0, _sendXbYokfdQ.rt)(path, {}); const data = sanitizeData(value); const seenAt = data[key]; if (seenAt != null && (ttlMs <= 0 || now - seenAt < ttlMs)) return true; data[key] = now; pruneData(data, now, ttlMs, fileMaxEntries); await (0, _sendXbYokfdQ.it)(path, data); return false; })); } catch (error) { onDiskError?.(error); memory.check(scopedKey, now); return true; } } async function warmup(namespace = "global", onError) { const filePath = options.resolveFilePath(namespace); const now = Date.now(); try { const { value } = await (0, _sendXbYokfdQ.rt)(filePath, {}); const data = sanitizeData(value); let loaded = 0; for (const [key, ts] of Object.entries(data)) { if (ttlMs > 0 && now - ts >= ttlMs) continue; const scopedKey = `${namespace}:${key}`; memory.check(scopedKey, ts); loaded++; } return loaded; } catch (error) { onError?.(error); return 0; } } async function checkAndRecord(key, dedupeOptions) { const trimmed = key.trim(); if (!trimmed) return true; const namespace = dedupeOptions?.namespace?.trim() || "global"; const scopedKey = `${namespace}:${trimmed}`; if (inflight.has(scopedKey)) return false; const onDiskError = dedupeOptions?.onDiskError ?? options.onDiskError; const work = checkAndRecordInner(trimmed, namespace, scopedKey, dedupeOptions?.now ?? Date.now(), onDiskError); inflight.set(scopedKey, work); try { return await work; } finally { inflight.delete(scopedKey); } } return { checkAndRecord, warmup, clearMemory: () => memory.clear(), memorySize: () => memory.size() }; } //#endregion //#region src/plugin-sdk/webhook-memory-guards.ts const WEBHOOK_RATE_LIMIT_DEFAULTS = exports.WEBHOOK_RATE_LIMIT_DEFAULTS = Object.freeze({ windowMs: 6e4, maxRequests: 120, maxTrackedKeys: 4096 }); const WEBHOOK_ANOMALY_COUNTER_DEFAULTS = exports.WEBHOOK_ANOMALY_COUNTER_DEFAULTS = Object.freeze({ maxTrackedKeys: 4096, ttlMs: 360 * 6e4, logEvery: 25 }); const WEBHOOK_ANOMALY_STATUS_CODES = exports.WEBHOOK_ANOMALY_STATUS_CODES = Object.freeze([ 400, 401, 408, 413, 415, 429] ); function createFixedWindowRateLimiter(options) { const windowMs = Math.max(1, Math.floor(options.windowMs)); const maxRequests = Math.max(1, Math.floor(options.maxRequests)); const maxTrackedKeys = Math.max(1, Math.floor(options.maxTrackedKeys)); const pruneIntervalMs = Math.max(1, Math.floor(options.pruneIntervalMs ?? windowMs)); const state = /* @__PURE__ */new Map(); let lastPruneMs = 0; const touch = (key, value) => { state.delete(key); state.set(key, value); }; const prune = (nowMs) => { for (const [key, entry] of state) if (nowMs - entry.windowStartMs >= windowMs) state.delete(key); }; return { isRateLimited: (key, nowMs = Date.now()) => { if (!key) return false; if (nowMs - lastPruneMs >= pruneIntervalMs) { prune(nowMs); lastPruneMs = nowMs; } const existing = state.get(key); if (!existing || nowMs - existing.windowStartMs >= windowMs) { touch(key, { count: 1, windowStartMs: nowMs }); (0, _dispatchF_Zbttj.Yt)(state, maxTrackedKeys); return false; } const nextCount = existing.count + 1; touch(key, { count: nextCount, windowStartMs: existing.windowStartMs }); (0, _dispatchF_Zbttj.Yt)(state, maxTrackedKeys); return nextCount > maxRequests; }, size: () => state.size, clear: () => { state.clear(); lastPruneMs = 0; } }; } function createBoundedCounter(options) { const maxTrackedKeys = Math.max(1, Math.floor(options.maxTrackedKeys)); const ttlMs = Math.max(0, Math.floor(options.ttlMs ?? 0)); const pruneIntervalMs = Math.max(1, Math.floor(options.pruneIntervalMs ?? (ttlMs > 0 ? ttlMs : 6e4))); const counters = /* @__PURE__ */new Map(); let lastPruneMs = 0; const touch = (key, value) => { counters.delete(key); counters.set(key, value); }; const isExpired = (entry, nowMs) => ttlMs > 0 && nowMs - entry.updatedAtMs >= ttlMs; const prune = (nowMs) => { if (ttlMs > 0) { for (const [key, entry] of counters) if (isExpired(entry, nowMs)) counters.delete(key); } }; return { increment: (key, nowMs = Date.now()) => { if (!key) return 0; if (nowMs - lastPruneMs >= pruneIntervalMs) { prune(nowMs); lastPruneMs = nowMs; } const existing = counters.get(key); const nextCount = (existing && !isExpired(existing, nowMs) ? existing.count : 0) + 1; touch(key, { count: nextCount, updatedAtMs: nowMs }); (0, _dispatchF_Zbttj.Yt)(counters, maxTrackedKeys); return nextCount; }, size: () => counters.size, clear: () => { counters.clear(); lastPruneMs = 0; } }; } function createWebhookAnomalyTracker(options) { const maxTrackedKeys = Math.max(1, Math.floor(options?.maxTrackedKeys ?? WEBHOOK_ANOMALY_COUNTER_DEFAULTS.maxTrackedKeys)); const ttlMs = Math.max(0, Math.floor(options?.ttlMs ?? WEBHOOK_ANOMALY_COUNTER_DEFAULTS.ttlMs)); const logEvery = Math.max(1, Math.floor(options?.logEvery ?? WEBHOOK_ANOMALY_COUNTER_DEFAULTS.logEvery)); const trackedStatusCodes = new Set(options?.trackedStatusCodes ?? WEBHOOK_ANOMALY_STATUS_CODES); const counter = createBoundedCounter({ maxTrackedKeys, ttlMs }); return { record: ({ key, statusCode, message, log, nowMs }) => { if (!trackedStatusCodes.has(statusCode)) return 0; const next = counter.increment(key, nowMs); if (log && (next === 1 || next % logEvery === 0)) log(message(next)); return next; }, size: () => counter.size(), clear: () => counter.clear() }; } //#endregion //#region src/plugin-sdk/ssrf-policy.ts function normalizeHostnameSuffix(value) { const trimmed = value.trim().toLowerCase(); if (!trimmed) return ""; if (trimmed === "*" || trimmed === "*.") return "*"; return trimmed.replace(/^\*\.?/, "").replace(/^\.+/, "").replace(/\.+$/, ""); } function isHostnameAllowedBySuffixAllowlist(hostname, allowlist) { if (allowlist.includes("*")) return true; const normalized = hostname.toLowerCase(); return allowlist.some((entry) => normalized === entry || normalized.endsWith(`.${entry}`)); } function normalizeHostnameSuffixAllowlist(input, defaults) { const source = input && input.length > 0 ? input : defaults; if (!source || source.length === 0) return []; const normalized = source.map(normalizeHostnameSuffix).filter(Boolean); if (normalized.includes("*")) return ["*"]; return Array.from(new Set(normalized)); } function isHttpsUrlAllowedByHostnameSuffixAllowlist(url, allowlist) { try { const parsed = new URL(url); if (parsed.protocol !== "https:") return false; return isHostnameAllowedBySuffixAllowlist(parsed.hostname, allowlist); } catch { return false; } } /** * Converts suffix-style host allowlists (for example "example.com") into SSRF * hostname allowlist patterns used by the shared fetch guard. * * Suffix semantics: * - "example.com" allows "example.com" and "*.example.com" * - "*" disables hostname allowlist restrictions */ function buildHostnameAllowlistPolicyFromSuffixAllowlist(allowHosts) { const normalizedAllowHosts = normalizeHostnameSuffixAllowlist(allowHosts); if (normalizedAllowHosts.length === 0) return; const patterns = /* @__PURE__ */new Set(); for (const normalized of normalizedAllowHosts) { if (normalized === "*") return; patterns.add(normalized); patterns.add(`*.${normalized}`); } if (patterns.size === 0) return; return { hostnameAllowlist: Array.from(patterns) }; } //#endregion //#region src/plugin-sdk/fetch-auth.ts function isAuthFailureStatus(status) { return status === 401 || status === 403; } async function fetchWithBearerAuthScopeFallback(params) { const fetchFn = params.fetchFn ?? fetch; let parsedUrl; try { parsedUrl = new URL(params.url); } catch { throw new Error(`Invalid URL: ${params.url}`); } if (params.requireHttps === true && parsedUrl.protocol !== "https:") throw new Error(`URL must use HTTPS: ${params.url}`); const fetchOnce = (headers) => fetchFn(params.url, { ...params.requestInit, ...(headers ? { headers } : {}) }); const firstAttempt = await fetchOnce(); if (firstAttempt.ok) return firstAttempt; if (!params.tokenProvider) return firstAttempt; const shouldRetry = params.shouldRetry ?? ((response) => isAuthFailureStatus(response.status)); if (!shouldRetry(firstAttempt)) return firstAttempt; if (params.shouldAttachAuth && !params.shouldAttachAuth(params.url)) return firstAttempt; for (const scope of params.scopes) try { const token = await params.tokenProvider.getAccessToken(scope); const authHeaders = new Headers(params.requestInit?.headers); authHeaders.set("Authorization", `Bearer ${token}`); const authAttempt = await fetchOnce(authHeaders); if (authAttempt.ok) return authAttempt; if (!shouldRetry(authAttempt)) continue; } catch {} return firstAttempt; } //#endregion //#region src/channels/plugins/directory-config-helpers.ts function resolveDirectoryQuery(query) { return query?.trim().toLowerCase() || ""; } function resolveDirectoryLimit(limit) { return typeof limit === "number" && limit > 0 ? limit : void 0; } function applyDirectoryQueryAndLimit(ids, params) { const q = resolveDirectoryQuery(params.query); const limit = resolveDirectoryLimit(params.limit); const filtered = ids.filter((id) => q ? id.toLowerCase().includes(q) : true); return typeof limit === "number" ? filtered.slice(0, limit) : filtered; } function toDirectoryEntries(kind, ids) { return ids.map((id) => ({ kind, id })); } function collectDirectoryIdsFromEntries(params) { return (params.entries ?? []).map((entry) => String(entry).trim()).filter((entry) => Boolean(entry) && entry !== "*").map((entry) => { const normalized = params.normalizeId ? params.normalizeId(entry) : entry; return typeof normalized === "string" ? normalized.trim() : ""; }).filter(Boolean); } function collectDirectoryIdsFromMapKeys(params) { return Object.keys(params.groups ?? {}).map((entry) => entry.trim()).filter((entry) => Boolean(entry) && entry !== "*").map((entry) => { const normalized = params.normalizeId ? params.normalizeId(entry) : entry; return typeof normalized === "string" ? normalized.trim() : ""; }).filter(Boolean); } function dedupeDirectoryIds(ids) { return Array.from(new Set(ids)); } function listDirectoryUserEntriesFromAllowFrom(params) { return toDirectoryEntries("user", applyDirectoryQueryAndLimit(dedupeDirectoryIds(collectDirectoryIdsFromEntries({ entries: params.allowFrom, normalizeId: params.normalizeId })), params)); } function listDirectoryUserEntriesFromAllowFromAndMapKeys(params) { return toDirectoryEntries("user", applyDirectoryQueryAndLimit(dedupeDirectoryIds([...collectDirectoryIdsFromEntries({ entries: params.allowFrom, normalizeId: params.normalizeAllowFromId }), ...collectDirectoryIdsFromMapKeys({ groups: params.map, normalizeId: params.normalizeMapKeyId })]), params)); } function listDirectoryGroupEntriesFromMapKeys(params) { return toDirectoryEntries("group", applyDirectoryQueryAndLimit(dedupeDirectoryIds(collectDirectoryIdsFromMapKeys({ groups: params.groups, normalizeId: params.normalizeId })), params)); } function listDirectoryGroupEntriesFromMapKeysAndAllowFrom(params) { return toDirectoryEntries("group", applyDirectoryQueryAndLimit(dedupeDirectoryIds([...collectDirectoryIdsFromMapKeys({ groups: params.groups, normalizeId: params.normalizeMapKeyId }), ...collectDirectoryIdsFromEntries({ entries: params.allowFrom, normalizeId: params.normalizeAllowFromId })]), params)); } //#endregion //#region src/channels/plugins/group-policy-warnings.ts function buildOpenGroupPolicyWarning(params) { return `- ${params.surface}: groupPolicy="open" ${params.openBehavior}. ${params.remediation}.`; } function buildOpenGroupPolicyRestrictSendersWarning(params) { const mentionSuffix = params.mentionGated === false ? "" : " (mention-gated)"; return buildOpenGroupPolicyWarning({ surface: params.surface, openBehavior: `allows ${params.openScope} to trigger${mentionSuffix}`, remediation: `Set ${params.groupPolicyPath}="allowlist" + ${params.groupAllowFromPath} to restrict senders` }); } function buildOpenGroupPolicyNoRouteAllowlistWarning(params) { const mentionSuffix = params.mentionGated === false ? "" : " (mention-gated)"; return buildOpenGroupPolicyWarning({ surface: params.surface, openBehavior: `with no ${params.routeAllowlistPath} allowlist; any ${params.routeScope} can add + ping${mentionSuffix}`, remediation: `Set ${params.groupPolicyPath}="allowlist" + ${params.groupAllowFromPath} or configure ${params.routeAllowlistPath}` }); } function buildOpenGroupPolicyConfigureRouteAllowlistWarning(params) { const mentionSuffix = params.mentionGated === false ? "" : " (mention-gated)"; return buildOpenGroupPolicyWarning({ surface: params.surface, openBehavior: `allows ${params.openScope} to trigger${mentionSuffix}`, remediation: `Set ${params.groupPolicyPath}="allowlist" and configure ${params.routeAllowlistPath}` }); } function collectOpenGroupPolicyRestrictSendersWarnings(params) { if (params.groupPolicy !== "open") return []; return [buildOpenGroupPolicyRestrictSendersWarning(params)]; } function collectAllowlistProviderRestrictSendersWarnings(params) { return collectAllowlistProviderGroupPolicyWarnings({ cfg: params.cfg, providerConfigPresent: params.providerConfigPresent, configuredGroupPolicy: params.configuredGroupPolicy, collect: (groupPolicy) => collectOpenGroupPolicyRestrictSendersWarnings({ groupPolicy, surface: params.surface, openScope: params.openScope, groupPolicyPath: params.groupPolicyPath, groupAllowFromPath: params.groupAllowFromPath, mentionGated: params.mentionGated }) }); } function collectAllowlistProviderGroupPolicyWarnings(params) { const defaultGroupPolicy = (0, _sendDPZOoQ.Nt)(params.cfg); const { groupPolicy } = (0, _sendDPZOoQ.Mt)({ providerConfigPresent: params.providerConfigPresent, groupPolicy: params.configuredGroupPolicy ?? void 0, defaultGroupPolicy }); return params.collect(groupPolicy); } function collectOpenProviderGroupPolicyWarnings(params) { const defaultGroupPolicy = (0, _sendDPZOoQ.Nt)(params.cfg); const { groupPolicy } = (0, _sendDPZOoQ.Pt)({ providerConfigPresent: params.providerConfigPresent, groupPolicy: params.configuredGroupPolicy ?? void 0, defaultGroupPolicy }); return params.collect(groupPolicy); } function collectOpenGroupPolicyRouteAllowlistWarnings(params) { if (params.groupPolicy !== "open") return []; if (params.routeAllowlistConfigured) return [buildOpenGroupPolicyRestrictSendersWarning(params.restrictSenders)]; return [buildOpenGroupPolicyNoRouteAllowlistWarning(params.noRouteAllowlist)]; } function collectOpenGroupPolicyConfiguredRouteWarnings(params) { if (params.groupPolicy !== "open") return []; if (params.routeAllowlistConfigured) return [buildOpenGroupPolicyConfigureRouteAllowlistWarning(params.configureRouteAllowlist)]; return [buildOpenGroupPolicyWarning(params.missingRouteAllowlist)]; } //#endregion //#region src/channels/plugins/helpers.ts function formatPairingApproveHint(channelId) { return `Approve via: ${(0, _configDiiPndBn.Br)(`openclaw pairing list ${channelId}`)} / ${(0, _configDiiPndBn.Br)(`openclaw pairing approve ${channelId} `)}`; } function buildAccountScopedDmSecurityPolicy(params) { const resolvedAccountId = params.accountId ?? params.fallbackAccountId ?? "default"; const channelConfig = params.cfg.channels?.[params.channelKey]; const basePath = Boolean(channelConfig?.accounts?.[resolvedAccountId]) ? `channels.${params.channelKey}.accounts.${resolvedAccountId}.` : `channels.${params.channelKey}.`; const allowFromPath = `${basePath}${params.allowFromPathSuffix ?? ""}`; const policyPath = params.policyPathSuffix != null ? `${basePath}${params.policyPathSuffix}` : void 0; return { policy: params.policy ?? params.defaultPolicy ?? "pairing", allowFrom: params.allowFrom ?? [], policyPath, allowFromPath, approveHint: params.approveHint ?? formatPairingApproveHint(params.approveChannelId ?? params.channelKey), normalizeEntry: params.normalizeEntry }; } //#endregion //#region src/channels/plugins/pairing-message.ts const PAIRING_APPROVED_MESSAGE = exports.PAIRING_APPROVED_MESSAGE = "✅ OpenClaw access approved. Send a message to start chatting."; //#endregion //#region src/channels/plugins/onboarding/channel-access.ts function parseAllowlistEntries(raw) { return splitOnboardingEntries(String(raw ?? "")); } function formatAllowlistEntries(entries) { return entries.map((entry) => entry.trim()).filter(Boolean).join(", "); } async function promptChannelAccessPolicy(params) { const options = [{ value: "allowlist", label: "Allowlist (recommended)" }]; if (params.allowOpen !== false) options.push({ value: "open", label: "Open (allow all channels)" }); if (params.allowDisabled !== false) options.push({ value: "disabled", label: "Disabled (block all channels)" }); const initialValue = params.currentPolicy ?? "allowlist"; return await params.prompter.select({ message: `${params.label} access`, options, initialValue }); } async function promptChannelAllowlist(params) { const initialValue = params.currentEntries && params.currentEntries.length > 0 ? formatAllowlistEntries(params.currentEntries) : void 0; return parseAllowlistEntries(await params.prompter.text({ message: `${params.label} allowlist (comma-separated)`, placeholder: params.placeholder, initialValue })); } async function promptChannelAccessConfig(params) { const hasEntries = (params.currentEntries ?? []).length > 0; const shouldPrompt = params.defaultPrompt ?? !hasEntries; if (!(await params.prompter.confirm({ message: params.updatePrompt ? `Update ${params.label} access?` : `Configure ${params.label} access?`, initialValue: shouldPrompt }))) return null; const policy = await promptChannelAccessPolicy({ prompter: params.prompter, label: params.label, currentPolicy: params.currentPolicy, allowOpen: params.allowOpen, allowDisabled: params.allowDisabled }); if (policy !== "allowlist") return { policy, entries: [] }; return { policy, entries: await promptChannelAllowlist({ prompter: params.prompter, label: params.label, currentEntries: params.currentEntries, placeholder: params.placeholder }) }; } //#endregion //#region src/channels/plugins/onboarding/channel-access-configure.ts async function configureChannelAccessWithAllowlist(params) { let next = params.cfg; const accessConfig = await promptChannelAccessConfig({ prompter: params.prompter, label: params.label, currentPolicy: params.currentPolicy, currentEntries: params.currentEntries, placeholder: params.placeholder, updatePrompt: params.updatePrompt }); if (!accessConfig) return next; if (accessConfig.policy !== "allowlist") return params.setPolicy(next, accessConfig.policy); const resolved = await params.resolveAllowlist({ cfg: next, entries: accessConfig.entries }); next = params.setPolicy(next, "allowlist"); return params.applyAllowlist({ cfg: next, resolved }); } //#endregion //#region src/channels/plugins/onboarding/discord.ts const channel$5 = "discord"; async function noteDiscordTokenHelp(prompter) { await prompter.note([ "1) Discord Developer Portal → Applications → New Application", "2) Bot → Add Bot → Reset Token → copy token", "3) OAuth2 → URL Generator → scope 'bot' → invite to your server", "Tip: enable Message Content Intent if you need message text. (Bot → Privileged Gateway Intents → Message Content Intent)", `Docs: ${(0, _dispatchF_Zbttj.f)("/discord", "discord")}`]. join("\n"), "Discord bot token"); } function setDiscordGuildChannelAllowlist(cfg, accountId, entries) { const guilds = { ...(accountId === "default" ? cfg.channels?.discord?.guilds ?? {} : cfg.channels?.discord?.accounts?.[accountId]?.guilds ?? {}) }; for (const entry of entries) { const guildKey = entry.guildKey || "*"; const existing = guilds[guildKey] ?? {}; if (entry.channelKey) { const channels = { ...existing.channels }; channels[entry.channelKey] = { allow: true }; guilds[guildKey] = { ...existing, channels }; } else guilds[guildKey] = existing; } return patchChannelConfigForAccount({ cfg, channel: "discord", accountId, patch: { guilds } }); } async function promptDiscordAllowFrom(params) { const accountId = resolveOnboardingAccountId({ accountId: params.accountId, defaultAccountId: (0, _pluginsBhm3N6Y.pt)(params.cfg) }); const token = (0, _pluginsBhm3N6Y.mt)({ cfg: params.cfg, accountId }).token; const existing = params.cfg.channels?.discord?.allowFrom ?? params.cfg.channels?.discord?.dm?.allowFrom ?? []; const parseId = (value) => parseMentionOrPrefixedId({ value, mentionPattern: /^<@!?(\d+)>$/, prefixPattern: /^(user:|discord:)/i, idPattern: /^\d+$/ }); return promptLegacyChannelAllowFrom({ cfg: params.cfg, channel: "discord", prompter: params.prompter, existing, token, noteTitle: "Discord allowlist", noteLines: [ "Allowlist Discord DMs by username (we resolve to user ids).", "Examples:", "- 123456789012345678", "- @alice", "- alice#1234", "Multiple entries: comma-separated.", `Docs: ${(0, _dispatchF_Zbttj.f)("/discord", "discord")}`], message: "Discord allowFrom (usernames or ids)", placeholder: "@alice, 123456789012345678", parseId, invalidWithoutTokenNote: "Bot token missing; use numeric user ids (or mention form) only.", resolveEntries: ({ token, entries }) => (0, _dispatchF_Zbttj.S)({ token, entries }) }); } const discordOnboardingAdapter = exports.discordOnboardingAdapter = { channel: channel$5, getStatus: async ({ cfg }) => { const configured = (0, _pluginsBhm3N6Y.dt)(cfg).some((accountId) => { return (0, _pluginsBhm3N6Y.lt)({ cfg, accountId }).configured; }); return { channel: channel$5, configured, statusLines: [`Discord: ${configured ? "configured" : "needs token"}`], selectionHint: configured ? "configured" : "needs token", quickstartScore: configured ? 2 : 1 }; }, configure: async ({ cfg, prompter, options, accountOverrides, shouldPromptAccountIds }) => { const defaultDiscordAccountId = (0, _pluginsBhm3N6Y.pt)(cfg); const discordAccountId = await resolveAccountIdForConfigure({ cfg, prompter, label: "Discord", accountOverride: accountOverrides.discord, shouldPromptAccountIds, listAccountIds: _pluginsBhm3N6Y.dt, defaultAccountId: defaultDiscordAccountId }); let next = cfg; const resolvedAccount = (0, _pluginsBhm3N6Y.mt)({ cfg: next, accountId: discordAccountId }); const allowEnv = discordAccountId === _runWithConcurrency2ga3CMk.lt; const tokenPromptState = buildSingleChannelSecretPromptState({ accountConfigured: Boolean(resolvedAccount.token), hasConfigToken: (0, _configDiiPndBn.qr)(resolvedAccount.config.token), allowEnv, envValue: process.env.DISCORD_BOT_TOKEN }); if (!tokenPromptState.accountConfigured) await noteDiscordTokenHelp(prompter); const tokenResult = await promptSingleChannelSecretInput({ cfg: next, prompter, providerHint: "discord", credentialLabel: "Discord bot token", secretInputMode: options?.secretInputMode, accountConfigured: tokenPromptState.accountConfigured, canUseEnv: tokenPromptState.canUseEnv, hasConfigToken: tokenPromptState.hasConfigToken, envPrompt: "DISCORD_BOT_TOKEN detected. Use env var?", keepPrompt: "Discord token already configured. Keep it?", inputPrompt: "Enter Discord bot token", preferredEnvVar: allowEnv ? "DISCORD_BOT_TOKEN" : void 0 }); let resolvedTokenForAllowlist; if (tokenResult.action === "use-env") { next = applySingleTokenPromptResult({ cfg: next, channel: "discord", accountId: discordAccountId, tokenPatchKey: "token", tokenResult: { useEnv: true, token: null } }); resolvedTokenForAllowlist = process.env.DISCORD_BOT_TOKEN?.trim() || void 0; } else if (tokenResult.action === "set") { next = applySingleTokenPromptResult({ cfg: next, channel: "discord", accountId: discordAccountId, tokenPatchKey: "token", tokenResult: { useEnv: false, token: tokenResult.value } }); resolvedTokenForAllowlist = tokenResult.resolvedValue; } const currentEntries = Object.entries(resolvedAccount.config.guilds ?? {}).flatMap(([guildKey, value]) => { const channels = value?.channels ?? {}; const channelKeys = Object.keys(channels); if (channelKeys.length === 0) return [/^\d+$/.test(guildKey) ? `guild:${guildKey}` : guildKey]; return channelKeys.map((channelKey) => `${guildKey}/${channelKey}`); }); next = await configureChannelAccessWithAllowlist({ cfg: next, prompter, label: "Discord channels", currentPolicy: resolvedAccount.config.groupPolicy ?? "allowlist", currentEntries, placeholder: "My Server/#general, guildId/channelId, #support", updatePrompt: Boolean(resolvedAccount.config.guilds), setPolicy: (cfg, policy) => setAccountGroupPolicyForChannel({ cfg, channel: "discord", accountId: discordAccountId, groupPolicy: policy }), resolveAllowlist: async ({ cfg, entries }) => { const accountWithTokens = (0, _pluginsBhm3N6Y.mt)({ cfg, accountId: discordAccountId }); let resolved = entries.map((input) => ({ input, resolved: false })); const activeToken = accountWithTokens.token || resolvedTokenForAllowlist || ""; if (activeToken && entries.length > 0) try { resolved = await (0, _dispatchF_Zbttj.C)({ token: activeToken, entries }); const resolvedChannels = resolved.filter((entry) => entry.resolved && entry.channelId); const resolvedGuilds = resolved.filter((entry) => entry.resolved && entry.guildId && !entry.channelId); const unresolved = resolved.filter((entry) => !entry.resolved).map((entry) => entry.input); await noteChannelLookupSummary({ prompter, label: "Discord channels", resolvedSections: [{ title: "Resolved channels", values: resolvedChannels.map((entry) => entry.channelId).filter((value) => Boolean(value)) }, { title: "Resolved guilds", values: resolvedGuilds.map((entry) => entry.guildId).filter((value) => Boolean(value)) }], unresolved }); } catch (err) { await noteChannelLookupFailure({ prompter, label: "Discord channels", error: err }); } return resolved; }, applyAllowlist: ({ cfg, resolved }) => { const allowlistEntries = []; for (const entry of resolved) { const guildKey = entry.guildId ?? (entry.guildName ? (0, _sendDPZOoQ.dt)(entry.guildName) : void 0) ?? "*"; const channelKey = entry.channelId ?? (entry.channelName ? (0, _sendDPZOoQ.dt)(entry.channelName) : void 0); if (!channelKey && guildKey === "*") continue; allowlistEntries.push({ guildKey, ...(channelKey ? { channelKey } : {}) }); } return setDiscordGuildChannelAllowlist(cfg, discordAccountId, allowlistEntries); } }); return { cfg: next, accountId: discordAccountId }; }, dmPolicy: { label: "Discord", channel: channel$5, policyKey: "channels.discord.dmPolicy", allowFromKey: "channels.discord.allowFrom", getCurrent: (cfg) => cfg.channels?.discord?.dmPolicy ?? cfg.channels?.discord?.dm?.policy ?? "pairing", setPolicy: (cfg, policy) => setLegacyChannelDmPolicyWithAllowFrom({ cfg, channel: "discord", dmPolicy: policy }), promptAllowFrom: promptDiscordAllowFrom }, disable: (cfg) => setOnboardingChannelEnabled(cfg, channel$5, false) }; //#endregion //#region src/channels/plugins/normalize/discord.ts function normalizeDiscordMessagingTarget(raw) { return (0, _sendDPZOoQ.at)(raw, { defaultKind: "channel" })?.normalized; } /** * Normalize a Discord outbound target for delivery. Bare numeric IDs are * prefixed with "channel:" to avoid the ambiguous-target error in * parseDiscordTarget. All other formats pass through unchanged. */ function normalizeDiscordOutboundTarget(to) { const trimmed = to?.trim(); if (!trimmed) return { ok: false, error: /* @__PURE__ */new Error("Discord recipient is required. Use \"channel:\" for channels or \"user:\" for DMs.") }; if (/^\d+$/.test(trimmed)) return { ok: true, to: `channel:${trimmed}` }; return { ok: true, to: trimmed }; } function looksLikeDiscordTargetId(raw) { const trimmed = raw.trim(); if (!trimmed) return false; if (/^<@!?\d+>$/.test(trimmed)) return true; if (/^(user|channel|discord):/i.test(trimmed)) return true; if (/^\d{6,}$/.test(trimmed)) return true; return false; } //#endregion //#region src/channels/plugins/status-issues/shared.ts function asString(value) { return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0; } function formatMatchMetadata(params) { const matchKey = typeof params.matchKey === "string" ? params.matchKey : typeof params.matchKey === "number" ? String(params.matchKey) : void 0; const matchSource = asString(params.matchSource); const parts = [matchKey ? `matchKey=${matchKey}` : null, matchSource ? `matchSource=${matchSource}` : null].filter((entry) => Boolean(entry)); return parts.length > 0 ? parts.join(" ") : void 0; } function appendMatchMetadata(message, params) { const meta = formatMatchMetadata(params); return meta ? `${message} (${meta})` : message; } function resolveEnabledConfiguredAccountId(account) { const accountId = asString(account.accountId) ?? "default"; const enabled = account.enabled !== false; const configured = account.configured === true; return enabled && configured ? accountId : null; } function collectIssuesForEnabledAccounts(params) { const issues = []; for (const entry of params.accounts) { const account = params.readAccount(entry); if (!account || account.enabled === false) continue; const accountId = asString(account.accountId) ?? "default"; params.collectIssues({ account, accountId, issues }); } return issues; } //#endregion //#region src/channels/plugins/status-issues/discord.ts function readDiscordAccountStatus(value) { if (!(0, _loggerU3s76KST.b)(value)) return null; return { accountId: value.accountId, enabled: value.enabled, configured: value.configured, application: value.application, audit: value.audit }; } function readDiscordApplicationSummary(value) { if (!(0, _loggerU3s76KST.b)(value)) return {}; const intentsRaw = value.intents; if (!(0, _loggerU3s76KST.b)(intentsRaw)) return {}; return { intents: { messageContent: intentsRaw.messageContent === "enabled" || intentsRaw.messageContent === "limited" || intentsRaw.messageContent === "disabled" ? intentsRaw.messageContent : void 0 } }; } function readDiscordPermissionsAuditSummary(value) { if (!(0, _loggerU3s76KST.b)(value)) return {}; const unresolvedChannels = typeof value.unresolvedChannels === "number" && Number.isFinite(value.unresolvedChannels) ? value.unresolvedChannels : void 0; const channelsRaw = value.channels; return { unresolvedChannels, channels: Array.isArray(channelsRaw) ? channelsRaw.map((entry) => { if (!(0, _loggerU3s76KST.b)(entry)) return null; const channelId = asString(entry.channelId); if (!channelId) return null; const ok = typeof entry.ok === "boolean" ? entry.ok : void 0; const missing = Array.isArray(entry.missing) ? entry.missing.map((v) => asString(v)).filter(Boolean) : void 0; const error = asString(entry.error) ?? null; const matchKey = asString(entry.matchKey) ?? void 0; const matchSource = asString(entry.matchSource) ?? void 0; return { channelId, ok, missing: missing?.length ? missing : void 0, error, matchKey, matchSource }; }).filter(Boolean) : void 0 }; } function collectDiscordStatusIssues(accounts) { const issues = []; for (const entry of accounts) { const account = readDiscordAccountStatus(entry); if (!account) continue; const accountId = resolveEnabledConfiguredAccountId(account); if (!accountId) continue; if (readDiscordApplicationSummary(account.application).intents?.messageContent === "disabled") issues.push({ channel: "discord", accountId, kind: "intent", message: "Message Content Intent is disabled. Bot may not see normal channel messages.", fix: "Enable Message Content Intent in Discord Dev Portal → Bot → Privileged Gateway Intents, or require mention-only operation." }); const audit = readDiscordPermissionsAuditSummary(account.audit); if (audit.unresolvedChannels && audit.unresolvedChannels > 0) issues.push({ channel: "discord", accountId, kind: "config", message: `Some configured guild channels are not numeric IDs (unresolvedChannels=${audit.unresolvedChannels}). Permission audit can only check numeric channel IDs.`, fix: "Use numeric channel IDs as keys in channels.discord.guilds.*.channels (then rerun channels status --probe)." }); for (const channel of audit.channels ?? []) { if (channel.ok === true) continue; const missing = channel.missing?.length ? ` missing ${channel.missing.join(", ")}` : ""; const error = channel.error ? `: ${channel.error}` : ""; const baseMessage = `Channel ${channel.channelId} permission check failed.${missing}${error}`; issues.push({ channel: "discord", accountId, kind: "permissions", message: appendMatchMetadata(baseMessage, { matchKey: channel.matchKey, matchSource: channel.matchSource }), fix: "Ensure the bot role can view + send in this channel (and that channel overrides don't deny it)." }); } } return issues; } //#endregion //#region src/channels/plugins/onboarding/imessage.ts const channel$4 = "imessage"; function parseIMessageAllowFromEntries(raw) { return parseOnboardingEntriesAllowingWildcard(raw, (entry) => { const lower = entry.toLowerCase(); if (lower.startsWith("chat_id:")) { const id = entry.slice(8).trim(); if (!/^\d+$/.test(id)) return { error: `Invalid chat_id: ${entry}` }; return { value: entry }; } if (lower.startsWith("chat_guid:")) { if (!entry.slice(10).trim()) return { error: "Invalid chat_guid entry" }; return { value: entry }; } if (lower.startsWith("chat_identifier:")) { if (!entry.slice(16).trim()) return { error: "Invalid chat_identifier entry" }; return { value: entry }; } if (!(0, _sendBlv_6HQ.o)(entry)) return { error: `Invalid handle: ${entry}` }; return { value: entry }; }); } async function promptIMessageAllowFrom(params) { return promptParsedAllowFromForScopedChannel({ cfg: params.cfg, channel: "imessage", accountId: params.accountId, defaultAccountId: (0, _pluginsBhm3N6Y.Z)(params.cfg), prompter: params.prompter, noteTitle: "iMessage allowlist", noteLines: [ "Allowlist iMessage DMs by handle or chat target.", "Examples:", "- +15555550123", "- user@example.com", "- chat_id:123", "- chat_guid:... or chat_identifier:...", "Multiple entries: comma-separated.", `Docs: ${(0, _dispatchF_Zbttj.f)("/imessage", "imessage")}`], message: "iMessage allowFrom (handle or chat_id)", placeholder: "+15555550123, user@example.com, chat_id:123", parseEntries: parseIMessageAllowFromEntries, getExistingAllowFrom: ({ cfg, accountId }) => { return (0, _pluginsBhm3N6Y.Q)({ cfg, accountId }).config.allowFrom ?? []; } }); } const imessageOnboardingAdapter = exports.imessageOnboardingAdapter = { channel: channel$4, getStatus: async ({ cfg }) => { const configured = (0, _pluginsBhm3N6Y.X)(cfg).some((accountId) => { const account = (0, _pluginsBhm3N6Y.Q)({ cfg, accountId }); return Boolean(account.config.cliPath || account.config.dbPath || account.config.allowFrom || account.config.service || account.config.region); }); const imessageCliPath = cfg.channels?.imessage?.cliPath ?? "imsg"; const imessageCliDetected = await (0, _dispatchF_Zbttj.x)(imessageCliPath); return { channel: channel$4, configured, statusLines: [`iMessage: ${configured ? "configured" : "needs setup"}`, `imsg: ${imessageCliDetected ? "found" : "missing"} (${imessageCliPath})`], selectionHint: imessageCliDetected ? "imsg found" : "imsg missing", quickstartScore: imessageCliDetected ? 1 : 0 }; }, configure: async ({ cfg, prompter, accountOverrides, shouldPromptAccountIds }) => { const defaultIMessageAccountId = (0, _pluginsBhm3N6Y.Z)(cfg); const imessageAccountId = await resolveAccountIdForConfigure({ cfg, prompter, label: "iMessage", accountOverride: accountOverrides.imessage, shouldPromptAccountIds, listAccountIds: _pluginsBhm3N6Y.X, defaultAccountId: defaultIMessageAccountId }); let next = cfg; let resolvedCliPath = (0, _pluginsBhm3N6Y.Q)({ cfg: next, accountId: imessageAccountId }).config.cliPath ?? "imsg"; if (!(await (0, _dispatchF_Zbttj.x)(resolvedCliPath))) { const entered = await prompter.text({ message: "imsg CLI path", initialValue: resolvedCliPath, validate: (value) => value?.trim() ? void 0 : "Required" }); resolvedCliPath = String(entered).trim(); if (!resolvedCliPath) await prompter.note("imsg CLI path required to enable iMessage.", "iMessage"); } if (resolvedCliPath) next = patchChannelConfigForAccount({ cfg: next, channel: "imessage", accountId: imessageAccountId, patch: { cliPath: resolvedCliPath } }); await prompter.note([ "This is still a work in progress.", "Ensure OpenClaw has Full Disk Access to Messages DB.", "Grant Automation permission for Messages when prompted.", "List chats with: imsg chats --limit 20", `Docs: ${(0, _dispatchF_Zbttj.f)("/imessage", "imessage")}`]. join("\n"), "iMessage next steps"); return { cfg: next, accountId: imessageAccountId }; }, dmPolicy: { label: "iMessage", channel: channel$4, policyKey: "channels.imessage.dmPolicy", allowFromKey: "channels.imessage.allowFrom", getCurrent: (cfg) => cfg.channels?.imessage?.dmPolicy ?? "pairing", setPolicy: (cfg, policy) => setChannelDmPolicyWithAllowFrom({ cfg, channel: "imessage", dmPolicy: policy }), promptAllowFrom: promptIMessageAllowFrom }, disable: (cfg) => setOnboardingChannelEnabled(cfg, channel$4, false) }; //#endregion //#region src/channels/plugins/normalize/imessage.ts const SERVICE_PREFIXES = [ "imessage:", "sms:", "auto:"]; const CHAT_TARGET_PREFIX_RE = /^(chat_id:|chatid:|chat:|chat_guid:|chatguid:|guid:|chat_identifier:|chatidentifier:|chatident:)/i; function normalizeIMessageMessagingTarget(raw) { const trimmed = (0, _pluginsBhm3N6Y.rt)(raw); if (!trimmed) return; const lower = trimmed.toLowerCase(); for (const prefix of SERVICE_PREFIXES) if (lower.startsWith(prefix)) { const normalizedHandle = (0, _sendBlv_6HQ.o)(trimmed.slice(prefix.length).trim()); if (!normalizedHandle) return; if (CHAT_TARGET_PREFIX_RE.test(normalizedHandle)) return normalizedHandle; return `${prefix}${normalizedHandle}`; } return (0, _sendBlv_6HQ.o)(trimmed) || void 0; } function looksLikeIMessageTargetId(raw) { const trimmed = (0, _pluginsBhm3N6Y.rt)(raw); if (!trimmed) return false; if (CHAT_TARGET_PREFIX_RE.test(trimmed)) return true; return (0, _pluginsBhm3N6Y.nt)({ raw: trimmed, prefixPattern: /^(imessage:|sms:|auto:)/i }); } //#endregion //#region src/slack/message-actions.ts function listSlackMessageActions(cfg) { const accounts = (0, _pluginsBhm3N6Y.N)(cfg).filter((account) => account.botTokenSource !== "none"); if (accounts.length === 0) return []; const isActionEnabled = (key, defaultValue = true) => { for (const account of accounts) if ((0, _targetErrorsByT48YHg.o)(account.actions ?? cfg.channels?.slack?.actions)(key, defaultValue)) return true; return false; }; const actions = new Set(["send"]); if (isActionEnabled("reactions")) { actions.add("react"); actions.add("reactions"); } if (isActionEnabled("messages")) { actions.add("read"); actions.add("edit"); actions.add("delete"); actions.add("download-file"); } if (isActionEnabled("pins")) { actions.add("pin"); actions.add("unpin"); actions.add("list-pins"); } if (isActionEnabled("memberInfo")) actions.add("member-info"); if (isActionEnabled("emojiList")) actions.add("emoji-list"); return Array.from(actions); } function extractSlackToolSend(args) { if ((typeof args.action === "string" ? args.action.trim() : "") !== "sendMessage") return null; const to = typeof args.to === "string" ? args.to : void 0; if (!to) return null; return { to, accountId: typeof args.accountId === "string" ? args.accountId.trim() : void 0 }; } //#endregion //#region src/channels/plugins/onboarding/slack.ts const channel$3 = "slack"; function buildSlackManifest(botName) { const safeName = botName.trim() || "OpenClaw"; const manifest = { display_information: { name: safeName, description: `${safeName} connector for OpenClaw` }, features: { bot_user: { display_name: safeName, always_online: false }, app_home: { messages_tab_enabled: true, messages_tab_read_only_enabled: false }, slash_commands: [{ command: "/openclaw", description: "Send a message to OpenClaw", should_escape: false }] }, oauth_config: { scopes: { bot: [ "chat:write", "channels:history", "channels:read", "groups:history", "im:history", "mpim:history", "users:read", "app_mentions:read", "reactions:read", "reactions:write", "pins:read", "pins:write", "emoji:read", "commands", "files:read", "files:write"] } }, settings: { socket_mode_enabled: true, event_subscriptions: { bot_events: [ "app_mention", "message.channels", "message.groups", "message.im", "message.mpim", "reaction_added", "reaction_removed", "member_joined_channel", "member_left_channel", "channel_rename", "pin_added", "pin_removed"] } } }; return JSON.stringify(manifest, null, 2); } async function noteSlackTokenHelp(prompter, botName) { const manifest = buildSlackManifest(botName); await prompter.note([ "1) Slack API → Create App → From scratch or From manifest (with the JSON below)", "2) Add Socket Mode + enable it to get the app-level token (xapp-...)", "3) Install App to workspace to get the xoxb- bot token", "4) Enable Event Subscriptions (socket) for message events", "5) App Home → enable the Messages tab for DMs", "Tip: set SLACK_BOT_TOKEN + SLACK_APP_TOKEN in your env.", `Docs: ${(0, _dispatchF_Zbttj.f)("/slack", "slack")}`, "", "Manifest (JSON):", manifest]. join("\n"), "Slack socket mode tokens"); } function setSlackChannelAllowlist(cfg, accountId, channelKeys) { return patchChannelConfigForAccount({ cfg, channel: "slack", accountId, patch: { channels: Object.fromEntries(channelKeys.map((key) => [key, { allow: true }])) } }); } async function promptSlackAllowFrom(params) { const accountId = resolveOnboardingAccountId({ accountId: params.accountId, defaultAccountId: (0, _pluginsBhm3N6Y.F)(params.cfg) }); const resolved = (0, _pluginsBhm3N6Y.I)({ cfg: params.cfg, accountId }); const token = resolved.userToken ?? resolved.botToken ?? ""; const existing = params.cfg.channels?.slack?.allowFrom ?? params.cfg.channels?.slack?.dm?.allowFrom ?? []; const parseId = (value) => parseMentionOrPrefixedId({ value, mentionPattern: /^<@([A-Z0-9]+)>$/i, prefixPattern: /^(slack:|user:)/i, idPattern: /^[A-Z][A-Z0-9]+$/i, normalizeId: (id) => id.toUpperCase() }); return promptLegacyChannelAllowFrom({ cfg: params.cfg, channel: "slack", prompter: params.prompter, existing, token, noteTitle: "Slack allowlist", noteLines: [ "Allowlist Slack DMs by username (we resolve to user ids).", "Examples:", "- U12345678", "- @alice", "Multiple entries: comma-separated.", `Docs: ${(0, _dispatchF_Zbttj.f)("/slack", "slack")}`], message: "Slack allowFrom (usernames or ids)", placeholder: "@alice, U12345678", parseId, invalidWithoutTokenNote: "Slack token missing; use user ids (or mention form) only.", resolveEntries: ({ token, entries }) => (0, _dispatchF_Zbttj.h)({ token, entries }) }); } const slackOnboardingAdapter = exports.slackOnboardingAdapter = { channel: channel$3, getStatus: async ({ cfg }) => { const configured = (0, _pluginsBhm3N6Y.P)(cfg).some((accountId) => { return (0, _pluginsBhm3N6Y.M)({ cfg, accountId }).configured; }); return { channel: channel$3, configured, statusLines: [`Slack: ${configured ? "configured" : "needs tokens"}`], selectionHint: configured ? "configured" : "needs tokens", quickstartScore: configured ? 2 : 1 }; }, configure: async ({ cfg, prompter, options, accountOverrides, shouldPromptAccountIds }) => { const defaultSlackAccountId = (0, _pluginsBhm3N6Y.F)(cfg); const slackAccountId = await resolveAccountIdForConfigure({ cfg, prompter, label: "Slack", accountOverride: accountOverrides.slack, shouldPromptAccountIds, listAccountIds: _pluginsBhm3N6Y.P, defaultAccountId: defaultSlackAccountId }); let next = cfg; const resolvedAccount = (0, _pluginsBhm3N6Y.I)({ cfg: next, accountId: slackAccountId }); const hasConfiguredBotToken = (0, _configDiiPndBn.qr)(resolvedAccount.config.botToken); const hasConfiguredAppToken = (0, _configDiiPndBn.qr)(resolvedAccount.config.appToken); const hasConfigTokens = hasConfiguredBotToken && hasConfiguredAppToken; const accountConfigured = Boolean(resolvedAccount.botToken && resolvedAccount.appToken) || hasConfigTokens; const allowEnv = slackAccountId === _runWithConcurrency2ga3CMk.lt; const botPromptState = buildSingleChannelSecretPromptState({ accountConfigured: Boolean(resolvedAccount.botToken) || hasConfiguredBotToken, hasConfigToken: hasConfiguredBotToken, allowEnv, envValue: process.env.SLACK_BOT_TOKEN }); const appPromptState = buildSingleChannelSecretPromptState({ accountConfigured: Boolean(resolvedAccount.appToken) || hasConfiguredAppToken, hasConfigToken: hasConfiguredAppToken, allowEnv, envValue: process.env.SLACK_APP_TOKEN }); let resolvedBotTokenForAllowlist = resolvedAccount.botToken; const slackBotName = String(await prompter.text({ message: "Slack bot display name (used for manifest)", initialValue: "OpenClaw" })).trim(); if (!accountConfigured) await noteSlackTokenHelp(prompter, slackBotName); const botTokenResult = await promptSingleChannelSecretInput({ cfg: next, prompter, providerHint: "slack-bot", credentialLabel: "Slack bot token", secretInputMode: options?.secretInputMode, accountConfigured: botPromptState.accountConfigured, canUseEnv: botPromptState.canUseEnv, hasConfigToken: botPromptState.hasConfigToken, envPrompt: "SLACK_BOT_TOKEN detected. Use env var?", keepPrompt: "Slack bot token already configured. Keep it?", inputPrompt: "Enter Slack bot token (xoxb-...)", preferredEnvVar: allowEnv ? "SLACK_BOT_TOKEN" : void 0 }); if (botTokenResult.action === "use-env") resolvedBotTokenForAllowlist = process.env.SLACK_BOT_TOKEN?.trim() || void 0;else if (botTokenResult.action === "set") { next = patchChannelConfigForAccount({ cfg: next, channel: "slack", accountId: slackAccountId, patch: { botToken: botTokenResult.value } }); resolvedBotTokenForAllowlist = botTokenResult.resolvedValue; } const appTokenResult = await promptSingleChannelSecretInput({ cfg: next, prompter, providerHint: "slack-app", credentialLabel: "Slack app token", secretInputMode: options?.secretInputMode, accountConfigured: appPromptState.accountConfigured, canUseEnv: appPromptState.canUseEnv, hasConfigToken: appPromptState.hasConfigToken, envPrompt: "SLACK_APP_TOKEN detected. Use env var?", keepPrompt: "Slack app token already configured. Keep it?", inputPrompt: "Enter Slack app token (xapp-...)", preferredEnvVar: allowEnv ? "SLACK_APP_TOKEN" : void 0 }); if (appTokenResult.action === "set") next = patchChannelConfigForAccount({ cfg: next, channel: "slack", accountId: slackAccountId, patch: { appToken: appTokenResult.value } }); next = await configureChannelAccessWithAllowlist({ cfg: next, prompter, label: "Slack channels", currentPolicy: resolvedAccount.config.groupPolicy ?? "allowlist", currentEntries: Object.entries(resolvedAccount.config.channels ?? {}).filter(([, value]) => value?.allow !== false && value?.enabled !== false).map(([key]) => key), placeholder: "#general, #private, C123", updatePrompt: Boolean(resolvedAccount.config.channels), setPolicy: (cfg, policy) => setAccountGroupPolicyForChannel({ cfg, channel: "slack", accountId: slackAccountId, groupPolicy: policy }), resolveAllowlist: async ({ cfg, entries }) => { let keys = entries; const activeBotToken = (0, _pluginsBhm3N6Y.I)({ cfg, accountId: slackAccountId }).botToken || resolvedBotTokenForAllowlist || ""; if (activeBotToken && entries.length > 0) try { const resolved = await (0, _dispatchF_Zbttj.g)({ token: activeBotToken, entries }); const resolvedKeys = resolved.filter((entry) => entry.resolved && entry.id).map((entry) => entry.id); const unresolved = resolved.filter((entry) => !entry.resolved).map((entry) => entry.input); keys = [...resolvedKeys, ...unresolved.map((entry) => entry.trim()).filter(Boolean)]; await noteChannelLookupSummary({ prompter, label: "Slack channels", resolvedSections: [{ title: "Resolved", values: resolvedKeys }], unresolved }); } catch (err) { await noteChannelLookupFailure({ prompter, label: "Slack channels", error: err }); } return keys; }, applyAllowlist: ({ cfg, resolved }) => { return setSlackChannelAllowlist(cfg, slackAccountId, resolved); } }); return { cfg: next, accountId: slackAccountId }; }, dmPolicy: { label: "Slack", channel: channel$3, policyKey: "channels.slack.dmPolicy", allowFromKey: "channels.slack.allowFrom", getCurrent: (cfg) => cfg.channels?.slack?.dmPolicy ?? cfg.channels?.slack?.dm?.policy ?? "pairing", setPolicy: (cfg, policy) => setLegacyChannelDmPolicyWithAllowFrom({ cfg, channel: "slack", dmPolicy: policy }), promptAllowFrom: promptSlackAllowFrom }, disable: (cfg) => setOnboardingChannelEnabled(cfg, channel$3, false) }; //#endregion //#region src/channels/telegram/api.ts async function fetchTelegramChatId(params) { const url = `https://api.telegram.org/bot${params.token}/getChat?chat_id=${encodeURIComponent(params.chatId)}`; try { const res = await fetch(url, params.signal ? { signal: params.signal } : void 0); if (!res.ok) return null; const data = await res.json().catch(() => null); const id = data?.ok ? data?.result?.id : void 0; if (typeof id === "number" || typeof id === "string") return String(id); return null; } catch { return null; } } //#endregion //#region src/channels/plugins/onboarding/telegram.ts const channel$2 = "telegram"; async function noteTelegramTokenHelp(prompter) { await prompter.note([ "1) Open Telegram and chat with @BotFather", "2) Run /newbot (or /mybots)", "3) Copy the token (looks like 123456:ABC...)", "Tip: you can also set TELEGRAM_BOT_TOKEN in your env.", `Docs: ${(0, _dispatchF_Zbttj.f)("/telegram")}`, "Website: https://openclaw.ai"]. join("\n"), "Telegram bot token"); } async function noteTelegramUserIdHelp(prompter) { await prompter.note([ `1) DM your bot, then read from.id in \`${(0, _configDiiPndBn.Br)("openclaw logs --follow")}\` (safest)`, "2) Or call https://api.telegram.org/bot/getUpdates and read message.from.id", "3) Third-party: DM @userinfobot or @getidsbot", `Docs: ${(0, _dispatchF_Zbttj.f)("/telegram")}`, "Website: https://openclaw.ai"]. join("\n"), "Telegram user id"); } function normalizeTelegramAllowFromInput(raw) { return raw.trim().replace(/^(telegram|tg):/i, "").trim(); } function parseTelegramAllowFromId(raw) { const stripped = normalizeTelegramAllowFromInput(raw); return /^\d+$/.test(stripped) ? stripped : null; } async function promptTelegramAllowFrom(params) { const { cfg, prompter, accountId } = params; const resolved = (0, _pluginsBhm3N6Y.w)({ cfg, accountId }); const existingAllowFrom = resolved.config.allowFrom ?? []; await noteTelegramUserIdHelp(prompter); const token = params.tokenOverride?.trim() || resolved.token; if (!token) await prompter.note("Telegram token missing; username lookup is unavailable.", "Telegram"); return patchChannelConfigForAccount({ cfg, channel: "telegram", accountId, patch: { dmPolicy: "allowlist", allowFrom: await promptResolvedAllowFrom({ prompter, existing: existingAllowFrom, token, message: "Telegram allowFrom (numeric sender id; @username resolves to id)", placeholder: "@username", label: "Telegram allowlist", parseInputs: splitOnboardingEntries, parseId: parseTelegramAllowFromId, invalidWithoutTokenNote: "Telegram token missing; use numeric sender ids (usernames require a bot token).", resolveEntries: async ({ token: tokenValue, entries }) => { return await Promise.all(entries.map(async (entry) => { const numericId = parseTelegramAllowFromId(entry); if (numericId) return { input: entry, resolved: true, id: numericId }; const stripped = normalizeTelegramAllowFromInput(entry); if (!stripped) return { input: entry, resolved: false, id: null }; const id = await fetchTelegramChatId({ token: tokenValue, chatId: stripped.startsWith("@") ? stripped : `@${stripped}` }); return { input: entry, resolved: Boolean(id), id }; })); } }) } }); } async function promptTelegramAllowFromForAccount(params) { const accountId = resolveOnboardingAccountId({ accountId: params.accountId, defaultAccountId: (0, _pluginsBhm3N6Y.C)(params.cfg) }); return promptTelegramAllowFrom({ cfg: params.cfg, prompter: params.prompter, accountId }); } const telegramOnboardingAdapter = exports.telegramOnboardingAdapter = { channel: channel$2, getStatus: async ({ cfg }) => { const configured = (0, _pluginsBhm3N6Y.S)(cfg).some((accountId) => { return (0, _pluginsBhm3N6Y.y)({ cfg, accountId }).configured; }); return { channel: channel$2, configured, statusLines: [`Telegram: ${configured ? "configured" : "needs token"}`], selectionHint: configured ? "recommended · configured" : "recommended · newcomer-friendly", quickstartScore: configured ? 1 : 10 }; }, configure: async ({ cfg, prompter, options, accountOverrides, shouldPromptAccountIds, forceAllowFrom }) => { const defaultTelegramAccountId = (0, _pluginsBhm3N6Y.C)(cfg); const telegramAccountId = await resolveAccountIdForConfigure({ cfg, prompter, label: "Telegram", accountOverride: accountOverrides.telegram, shouldPromptAccountIds, listAccountIds: _pluginsBhm3N6Y.S, defaultAccountId: defaultTelegramAccountId }); let next = cfg; const resolvedAccount = (0, _pluginsBhm3N6Y.w)({ cfg: next, accountId: telegramAccountId }); const hasConfigToken = (0, _configDiiPndBn.qr)(resolvedAccount.config.botToken) || Boolean(resolvedAccount.config.tokenFile?.trim()); const allowEnv = telegramAccountId === _runWithConcurrency2ga3CMk.lt; const tokenPromptState = buildSingleChannelSecretPromptState({ accountConfigured: Boolean(resolvedAccount.token) || hasConfigToken, hasConfigToken, allowEnv, envValue: process.env.TELEGRAM_BOT_TOKEN }); if (!tokenPromptState.accountConfigured) await noteTelegramTokenHelp(prompter); const tokenResult = await promptSingleChannelSecretInput({ cfg: next, prompter, providerHint: "telegram", credentialLabel: "Telegram bot token", secretInputMode: options?.secretInputMode, accountConfigured: tokenPromptState.accountConfigured, canUseEnv: tokenPromptState.canUseEnv, hasConfigToken: tokenPromptState.hasConfigToken, envPrompt: "TELEGRAM_BOT_TOKEN detected. Use env var?", keepPrompt: "Telegram token already configured. Keep it?", inputPrompt: "Enter Telegram bot token", preferredEnvVar: allowEnv ? "TELEGRAM_BOT_TOKEN" : void 0 }); let resolvedTokenForAllowFrom; if (tokenResult.action === "use-env") { next = applySingleTokenPromptResult({ cfg: next, channel: "telegram", accountId: telegramAccountId, tokenPatchKey: "botToken", tokenResult: { useEnv: true, token: null } }); resolvedTokenForAllowFrom = process.env.TELEGRAM_BOT_TOKEN?.trim() || void 0; } else if (tokenResult.action === "set") { next = applySingleTokenPromptResult({ cfg: next, channel: "telegram", accountId: telegramAccountId, tokenPatchKey: "botToken", tokenResult: { useEnv: false, token: tokenResult.value } }); resolvedTokenForAllowFrom = tokenResult.resolvedValue; } if (forceAllowFrom) next = await promptTelegramAllowFrom({ cfg: next, prompter, accountId: telegramAccountId, tokenOverride: resolvedTokenForAllowFrom }); return { cfg: next, accountId: telegramAccountId }; }, dmPolicy: { label: "Telegram", channel: channel$2, policyKey: "channels.telegram.dmPolicy", allowFromKey: "channels.telegram.allowFrom", getCurrent: (cfg) => cfg.channels?.telegram?.dmPolicy ?? "pairing", setPolicy: (cfg, policy) => setChannelDmPolicyWithAllowFrom({ cfg, channel: "telegram", dmPolicy: policy }), promptAllowFrom: promptTelegramAllowFromForAccount }, disable: (cfg) => setOnboardingChannelEnabled(cfg, channel$2, false) }; //#endregion //#region src/channels/plugins/normalize/telegram.ts const TELEGRAM_PREFIX_RE = /^(telegram|tg):/i; function normalizeTelegramTargetBody(raw) { const trimmed = raw.trim(); if (!trimmed) return; const prefixStripped = trimmed.replace(TELEGRAM_PREFIX_RE, "").trim(); if (!prefixStripped) return; const parsed = (0, _targetsBP_LjgWp.r)(trimmed); const normalizedChatId = (0, _targetsBP_LjgWp.n)(parsed.chatId); if (!normalizedChatId) return; const keepLegacyGroupPrefix = /^group:/i.test(prefixStripped); const hasTopicSuffix = /:topic:\d+$/i.test(prefixStripped); const chatSegment = keepLegacyGroupPrefix ? `group:${normalizedChatId}` : normalizedChatId; if (parsed.messageThreadId == null) return chatSegment; return `${chatSegment}${hasTopicSuffix ? `:topic:${parsed.messageThreadId}` : `:${parsed.messageThreadId}`}`; } function normalizeTelegramMessagingTarget(raw) { const normalizedBody = normalizeTelegramTargetBody(raw); if (!normalizedBody) return; return `telegram:${normalizedBody}`.toLowerCase(); } function looksLikeTelegramTargetId(raw) { return normalizeTelegramTargetBody(raw) !== void 0; } //#endregion //#region src/channels/plugins/status-issues/telegram.ts function readTelegramAccountStatus(value) { if (!(0, _loggerU3s76KST.b)(value)) return null; return { accountId: value.accountId, enabled: value.enabled, configured: value.configured, allowUnmentionedGroups: value.allowUnmentionedGroups, audit: value.audit }; } function readTelegramGroupMembershipAuditSummary(value) { if (!(0, _loggerU3s76KST.b)(value)) return {}; const unresolvedGroups = typeof value.unresolvedGroups === "number" && Number.isFinite(value.unresolvedGroups) ? value.unresolvedGroups : void 0; const hasWildcardUnmentionedGroups = typeof value.hasWildcardUnmentionedGroups === "boolean" ? value.hasWildcardUnmentionedGroups : void 0; const groupsRaw = value.groups; return { unresolvedGroups, hasWildcardUnmentionedGroups, groups: Array.isArray(groupsRaw) ? groupsRaw.map((entry) => { if (!(0, _loggerU3s76KST.b)(entry)) return null; const chatId = asString(entry.chatId); if (!chatId) return null; return { chatId, ok: typeof entry.ok === "boolean" ? entry.ok : void 0, status: asString(entry.status) ?? null, error: asString(entry.error) ?? null, matchKey: asString(entry.matchKey) ?? void 0, matchSource: asString(entry.matchSource) ?? void 0 }; }).filter(Boolean) : void 0 }; } function collectTelegramStatusIssues(accounts) { const issues = []; for (const entry of accounts) { const account = readTelegramAccountStatus(entry); if (!account) continue; const accountId = resolveEnabledConfiguredAccountId(account); if (!accountId) continue; if (account.allowUnmentionedGroups === true) issues.push({ channel: "telegram", accountId, kind: "config", message: "Config allows unmentioned group messages (requireMention=false). Telegram Bot API privacy mode will block most group messages unless disabled.", fix: "In BotFather run /setprivacy → Disable for this bot (then restart the gateway)." }); const audit = readTelegramGroupMembershipAuditSummary(account.audit); if (audit.hasWildcardUnmentionedGroups === true) issues.push({ channel: "telegram", accountId, kind: "config", message: "Telegram groups config uses \"*\" with requireMention=false; membership probing is not possible without explicit group IDs.", fix: "Add explicit numeric group ids under channels.telegram.groups (or per-account groups) to enable probing." }); if (audit.unresolvedGroups && audit.unresolvedGroups > 0) issues.push({ channel: "telegram", accountId, kind: "config", message: `Some configured Telegram groups are not numeric IDs (unresolvedGroups=${audit.unresolvedGroups}). Membership probe can only check numeric group IDs.`, fix: "Use numeric chat IDs (e.g. -100...) as keys in channels.telegram.groups for requireMention=false groups." }); for (const group of audit.groups ?? []) { if (group.ok === true) continue; const status = group.status ? ` status=${group.status}` : ""; const err = group.error ? `: ${group.error}` : ""; const baseMessage = `Group ${group.chatId} not reachable by bot.${status}${err}`; issues.push({ channel: "telegram", accountId, kind: "runtime", message: appendMatchMetadata(baseMessage, { matchKey: group.matchKey, matchSource: group.matchSource }), fix: "Invite the bot to the group, then DM the bot once (/start) and restart the gateway." }); } } return issues; } //#endregion //#region src/infra/path-safety.ts function resolveSafeBaseDir(rootDir) { const resolved = _nodePath.default.resolve(rootDir); return resolved.endsWith(_nodePath.default.sep) ? resolved : `${resolved}${_nodePath.default.sep}`; } //#endregion //#region src/infra/archive-path.ts function isWindowsDrivePath(value) { return /^[a-zA-Z]:[\\/]/.test(value); } function normalizeArchiveEntryPath(raw) { return raw.replaceAll("\\", "/"); } function validateArchiveEntryPath(entryPath, params) { if (!entryPath || entryPath === "." || entryPath === "./") return; if (isWindowsDrivePath(entryPath)) throw new Error(`archive entry uses a drive path: ${entryPath}`); const normalized = _nodePath.default.posix.normalize(normalizeArchiveEntryPath(entryPath)); const escapeLabel = params?.escapeLabel ?? "destination"; if (normalized === ".." || normalized.startsWith("../")) throw new Error(`archive entry escapes ${escapeLabel}: ${entryPath}`); if (_nodePath.default.posix.isAbsolute(normalized) || normalized.startsWith("//")) throw new Error(`archive entry is absolute: ${entryPath}`); } function stripArchivePath(entryPath, stripComponents) { const raw = normalizeArchiveEntryPath(entryPath); if (!raw || raw === "." || raw === "./") return null; const parts = raw.split("/").filter((part) => part.length > 0 && part !== "."); const strip = Math.max(0, Math.floor(stripComponents)); const stripped = strip === 0 ? parts.join("/") : parts.slice(strip).join("/"); const result = _nodePath.default.posix.normalize(stripped); if (!result || result === "." || result === "./") return null; return result; } function resolveArchiveOutputPath(params) { const safeBase = resolveSafeBaseDir(params.rootDir); const outPath = _nodePath.default.resolve(params.rootDir, params.relPath); const escapeLabel = params.escapeLabel ?? "destination"; if (!outPath.startsWith(safeBase)) throw new Error(`archive entry escapes ${escapeLabel}: ${params.originalPath}`); return outPath; } //#endregion //#region src/infra/archive.ts var ArchiveSecurityError = class extends Error { constructor(code, message, options) { super(message, options); this.code = code; this.name = "ArchiveSecurityError"; } }; const ERROR_ARCHIVE_SIZE_EXCEEDS_LIMIT = "archive size exceeds limit"; const ERROR_ARCHIVE_ENTRY_COUNT_EXCEEDS_LIMIT = "archive entry count exceeds limit"; const ERROR_ARCHIVE_ENTRY_EXTRACTED_SIZE_EXCEEDS_LIMIT = "archive entry extracted size exceeds limit"; const ERROR_ARCHIVE_EXTRACTED_SIZE_EXCEEDS_LIMIT = "archive extracted size exceeds limit"; const ERROR_ARCHIVE_ENTRY_TRAVERSES_SYMLINK = "archive entry traverses symlink in destination"; const SUPPORTS_NOFOLLOW = process.platform !== "win32" && "O_NOFOLLOW" in _nodeFs.constants; const OPEN_WRITE_CREATE_FLAGS = _nodeFs.constants.O_WRONLY | _nodeFs.constants.O_CREAT | _nodeFs.constants.O_EXCL | (SUPPORTS_NOFOLLOW ? _nodeFs.constants.O_NOFOLLOW : 0); const TAR_SUFFIXES = [ ".tgz", ".tar.gz", ".tar"]; function resolveArchiveKind(filePath) { const lower = filePath.toLowerCase(); if (lower.endsWith(".zip")) return "zip"; if (TAR_SUFFIXES.some((suffix) => lower.endsWith(suffix))) return "tar"; return null; } async function withTimeout(promise, timeoutMs, label) { let timeoutId; try { return await Promise.race([promise, new Promise((_, reject) => { timeoutId = setTimeout(() => reject(/* @__PURE__ */new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs); })]); } finally { if (timeoutId) clearTimeout(timeoutId); } } function clampLimit(value) { if (typeof value !== "number" || !Number.isFinite(value)) return; const v = Math.floor(value); return v > 0 ? v : void 0; } function resolveExtractLimits(limits) { return { maxArchiveBytes: clampLimit(limits?.maxArchiveBytes) ?? 268435456, maxEntries: clampLimit(limits?.maxEntries) ?? 5e4, maxExtractedBytes: clampLimit(limits?.maxExtractedBytes) ?? 536870912, maxEntryBytes: clampLimit(limits?.maxEntryBytes) ?? 268435456 }; } function assertArchiveEntryCountWithinLimit(entryCount, limits) { if (entryCount > limits.maxEntries) throw new Error(ERROR_ARCHIVE_ENTRY_COUNT_EXCEEDS_LIMIT); } function createByteBudgetTracker(limits) { let entryBytes = 0; let extractedBytes = 0; const addBytes = (bytes) => { const b = Math.max(0, Math.floor(bytes)); if (b === 0) return; entryBytes += b; if (entryBytes > limits.maxEntryBytes) throw new Error(ERROR_ARCHIVE_ENTRY_EXTRACTED_SIZE_EXCEEDS_LIMIT); extractedBytes += b; if (extractedBytes > limits.maxExtractedBytes) throw new Error(ERROR_ARCHIVE_EXTRACTED_SIZE_EXCEEDS_LIMIT); }; return { startEntry() { entryBytes = 0; }, addBytes, addEntrySize(size) { const s = Math.max(0, Math.floor(size)); if (s > limits.maxEntryBytes) throw new Error(ERROR_ARCHIVE_ENTRY_EXTRACTED_SIZE_EXCEEDS_LIMIT); addBytes(s); } }; } function createExtractBudgetTransform(params) { return new _nodeStream.Transform({ transform(chunk, _encoding, callback) { try { const buf = chunk instanceof Buffer ? chunk : Buffer.from(chunk); params.onChunkBytes(buf.byteLength); callback(null, buf); } catch (err) { callback(err instanceof Error ? err : new Error(String(err))); } } }); } function symlinkTraversalError(originalPath) { return new ArchiveSecurityError("destination-symlink-traversal", `${ERROR_ARCHIVE_ENTRY_TRAVERSES_SYMLINK}: ${originalPath}`); } async function assertDestinationDirReady(destDir) { const stat = await _promises.default.lstat(destDir); if (stat.isSymbolicLink()) throw new ArchiveSecurityError("destination-symlink", "archive destination is a symlink"); if (!stat.isDirectory()) throw new ArchiveSecurityError("destination-not-directory", "archive destination is not a directory"); return await _promises.default.realpath(destDir); } async function assertNoSymlinkTraversal(params) { const parts = params.relPath.split("/").filter(Boolean); let current = _nodePath.default.resolve(params.rootDir); for (const part of parts) { current = _nodePath.default.join(current, part); let stat; try { stat = await _promises.default.lstat(current); } catch (err) { if ((0, _runWithConcurrency2ga3CMk.R)(err)) continue; throw err; } if (stat.isSymbolicLink()) throw symlinkTraversalError(params.originalPath); } } async function assertResolvedInsideDestination(params) { let resolved; try { resolved = await _promises.default.realpath(params.targetPath); } catch (err) { if ((0, _runWithConcurrency2ga3CMk.R)(err)) return; throw err; } if (!(0, _runWithConcurrency2ga3CMk.z)(params.destinationRealDir, resolved)) throw symlinkTraversalError(params.originalPath); } async function openZipOutputFile(params) { try { return await (0, _fsSafeBbZgytb.a)({ rootDir: params.destinationRealDir, relativePath: params.relPath, mkdir: false, mode: 438 }); } catch (err) { if (err instanceof _fsSafeBbZgytb.t && (err.code === "invalid-path" || err.code === "outside-workspace" || err.code === "path-mismatch")) throw symlinkTraversalError(params.originalPath); throw err; } } async function cleanupPartialRegularFile(filePath) { let stat; try { stat = await _promises.default.lstat(filePath); } catch (err) { if ((0, _runWithConcurrency2ga3CMk.R)(err)) return; throw err; } if (stat.isFile()) await _promises.default.unlink(filePath).catch(() => void 0); } function buildArchiveAtomicTempPath(targetPath) { return _nodePath.default.join(_nodePath.default.dirname(targetPath), `.${_nodePath.default.basename(targetPath)}.${process.pid}.${(0, _nodeCrypto.randomUUID)()}.tmp`); } async function verifyZipWriteResult(params) { const opened = await (0, _fsSafeBbZgytb.i)({ rootDir: params.destinationRealDir, relativePath: params.relPath, rejectHardlinks: true }); try { if (!(0, _runWithConcurrency2ga3CMk.N)(opened.stat, params.expectedStat)) throw new _fsSafeBbZgytb.t("path-mismatch", "path changed during zip extract"); return opened.realPath; } finally { await opened.handle.close().catch(() => void 0); } } async function readZipEntryStream(entry) { if (typeof entry.nodeStream === "function") return entry.nodeStream(); const buf = await entry.async("nodebuffer"); return _nodeStream.Readable.from(buf); } function resolveZipOutputPath(params) { validateArchiveEntryPath(params.entryPath); const relPath = stripArchivePath(params.entryPath, params.strip); if (!relPath) return null; validateArchiveEntryPath(relPath); return { relPath, outPath: resolveArchiveOutputPath({ rootDir: params.destinationDir, relPath, originalPath: params.entryPath }) }; } async function prepareZipOutputPath(params) { await assertNoSymlinkTraversal({ rootDir: params.destinationDir, relPath: params.relPath, originalPath: params.originalPath }); if (params.isDirectory) { await _promises.default.mkdir(params.outPath, { recursive: true }); await assertResolvedInsideDestination({ destinationRealDir: params.destinationRealDir, targetPath: params.outPath, originalPath: params.originalPath }); return; } const parentDir = _nodePath.default.dirname(params.outPath); await _promises.default.mkdir(parentDir, { recursive: true }); await assertResolvedInsideDestination({ destinationRealDir: params.destinationRealDir, targetPath: parentDir, originalPath: params.originalPath }); } async function writeZipFileEntry(params) { const opened = await openZipOutputFile({ relPath: params.relPath, originalPath: params.entry.name, destinationRealDir: params.destinationRealDir }); params.budget.startEntry(); const readable = await readZipEntryStream(params.entry); const destinationPath = opened.openedRealPath; const targetMode = opened.openedStat.mode & 511; await opened.handle.close().catch(() => void 0); let tempHandle = null; let tempPath = null; let tempStat = null; let handleClosedByStream = false; try { tempPath = buildArchiveAtomicTempPath(destinationPath); tempHandle = await _promises.default.open(tempPath, OPEN_WRITE_CREATE_FLAGS, targetMode || 438); const writable = tempHandle.createWriteStream(); writable.once("close", () => { handleClosedByStream = true; }); await (0, _promises2.pipeline)(readable, createExtractBudgetTransform({ onChunkBytes: params.budget.addBytes }), writable); tempStat = await _promises.default.stat(tempPath); if (!tempStat) throw new Error("zip temp write did not produce file metadata"); if (!handleClosedByStream) { await tempHandle.close().catch(() => void 0); handleClosedByStream = true; } tempHandle = null; await _promises.default.rename(tempPath, destinationPath); tempPath = null; const verifiedPath = await verifyZipWriteResult({ destinationRealDir: params.destinationRealDir, relPath: params.relPath, expectedStat: tempStat }); if (typeof params.entry.unixPermissions === "number") { const mode = params.entry.unixPermissions & 511; if (mode !== 0) await _promises.default.chmod(verifiedPath, mode).catch(() => void 0); } } catch (err) { if (tempPath) await _promises.default.rm(tempPath, { force: true }).catch(() => void 0);else await cleanupPartialRegularFile(destinationPath).catch(() => void 0); if (err instanceof _fsSafeBbZgytb.t) throw symlinkTraversalError(params.entry.name); throw err; } finally { if (tempHandle && !handleClosedByStream) await tempHandle.close().catch(() => void 0); } } async function extractZip(params) { const limits = resolveExtractLimits(params.limits); const destinationRealDir = await assertDestinationDirReady(params.destDir); if ((await _promises.default.stat(params.archivePath)).size > limits.maxArchiveBytes) throw new Error(ERROR_ARCHIVE_SIZE_EXCEEDS_LIMIT); const buffer = await _promises.default.readFile(params.archivePath); const zip = await _jszip.default.loadAsync(buffer); const entries = Object.values(zip.files); const strip = Math.max(0, Math.floor(params.stripComponents ?? 0)); assertArchiveEntryCountWithinLimit(entries.length, limits); const budget = createByteBudgetTracker(limits); for (const entry of entries) { const output = resolveZipOutputPath({ entryPath: entry.name, strip, destinationDir: params.destDir }); if (!output) continue; await prepareZipOutputPath({ destinationDir: params.destDir, destinationRealDir, relPath: output.relPath, outPath: output.outPath, originalPath: entry.name, isDirectory: entry.dir }); if (entry.dir) continue; await writeZipFileEntry({ entry, relPath: output.relPath, destinationRealDir, budget }); } } const BLOCKED_TAR_ENTRY_TYPES = new Set([ "SymbolicLink", "Link", "BlockDevice", "CharacterDevice", "FIFO", "Socket"] ); function readTarEntryInfo(entry) { return { path: typeof entry === "object" && entry !== null && "path" in entry ? String(entry.path) : "", type: typeof entry === "object" && entry !== null && "type" in entry ? String(entry.type) : "", size: typeof entry === "object" && entry !== null && "size" in entry && typeof entry.size === "number" && Number.isFinite(entry.size) ? Math.max(0, Math.floor(entry.size)) : 0 }; } function createTarEntrySafetyChecker(params) { const strip = Math.max(0, Math.floor(params.stripComponents ?? 0)); const limits = resolveExtractLimits(params.limits); let entryCount = 0; const budget = createByteBudgetTracker(limits); return (entry) => { validateArchiveEntryPath(entry.path, { escapeLabel: params.escapeLabel }); const relPath = stripArchivePath(entry.path, strip); if (!relPath) return; validateArchiveEntryPath(relPath, { escapeLabel: params.escapeLabel }); resolveArchiveOutputPath({ rootDir: params.rootDir, relPath, originalPath: entry.path, escapeLabel: params.escapeLabel }); if (BLOCKED_TAR_ENTRY_TYPES.has(entry.type)) throw new Error(`tar entry is a link: ${entry.path}`); entryCount += 1; assertArchiveEntryCountWithinLimit(entryCount, limits); budget.addEntrySize(entry.size); }; } async function extractArchive(params) { const kind = params.kind ?? resolveArchiveKind(params.archivePath); if (!kind) throw new Error(`unsupported archive: ${params.archivePath}`); const label = kind === "zip" ? "extract zip" : "extract tar"; if (kind === "tar") { const limits = resolveExtractLimits(params.limits); if ((await _promises.default.stat(params.archivePath)).size > limits.maxArchiveBytes) throw new Error(ERROR_ARCHIVE_SIZE_EXCEEDS_LIMIT); const checkTarEntrySafety = createTarEntrySafetyChecker({ rootDir: params.destDir, stripComponents: params.stripComponents, limits }); await withTimeout(tar.x({ file: params.archivePath, cwd: params.destDir, strip: Math.max(0, Math.floor(params.stripComponents ?? 0)), gzip: params.tarGzip, preservePaths: false, strict: true, onReadEntry(entry) { try { checkTarEntrySafety(readTarEntryInfo(entry)); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); this.abort?.(error); } } }), params.timeoutMs, label); return; } await withTimeout(extractZip({ archivePath: params.archivePath, destDir: params.destDir, stripComponents: params.stripComponents, limits: params.limits }), params.timeoutMs, label); } //#endregion //#region src/infra/brew.ts function isExecutable(filePath) { try { _nodeFs.default.accessSync(filePath, _nodeFs.default.constants.X_OK); return true; } catch { return false; } } function normalizePathValue(value) { if (typeof value !== "string") return; const trimmed = value.trim(); return trimmed ? trimmed : void 0; } function resolveBrewExecutable(opts) { const homeDir = opts?.homeDir ?? _nodeOs.default.homedir(); const env = opts?.env ?? process.env; const candidates = []; const brewFile = normalizePathValue(env.HOMEBREW_BREW_FILE); if (brewFile) candidates.push(brewFile); const prefix = normalizePathValue(env.HOMEBREW_PREFIX); if (prefix) candidates.push(_nodePath.default.join(prefix, "bin", "brew")); candidates.push(_nodePath.default.join(homeDir, ".linuxbrew", "bin", "brew")); candidates.push("/home/linuxbrew/.linuxbrew/bin/brew"); candidates.push("/opt/homebrew/bin/brew", "/usr/local/bin/brew"); for (const candidate of candidates) if (isExecutable(candidate)) return candidate; } //#endregion //#region src/commands/signal-install.ts /** @internal Exported for testing. */ async function extractSignalCliArchive(archivePath, installRoot, timeoutMs) { await extractArchive({ archivePath, destDir: installRoot, timeoutMs }); } /** @internal Exported for testing. */ function looksLikeArchive(name) { return name.endsWith(".tar.gz") || name.endsWith(".tgz") || name.endsWith(".zip"); } /** * Pick a native release asset from the official GitHub releases. * * The official signal-cli releases only publish native (GraalVM) binaries for * x86-64 Linux. On architectures where no native asset is available this * returns `undefined` so the caller can fall back to a different install * strategy (e.g. Homebrew). */ /** @internal Exported for testing. */ function pickAsset(assets, platform, arch) { const archives = assets.filter((asset) => Boolean(asset.name && asset.browser_download_url)).filter((a) => looksLikeArchive(a.name.toLowerCase())); const byName = (pattern) => archives.find((asset) => pattern.test(asset.name.toLowerCase())); if (platform === "linux") { if (arch === "x64") return byName(/linux-native/) || byName(/linux/) || archives[0]; return; } if (platform === "darwin") return byName(/macos|osx|darwin/) || archives[0]; if (platform === "win32") return byName(/windows|win/) || archives[0]; return archives[0]; } async function downloadToFile(url, dest, maxRedirects = 5) { await new Promise((resolve, reject) => { const req = (0, _nodeHttps.request)(url, (res) => { if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400) { const location = res.headers.location; if (!location || maxRedirects <= 0) { reject(/* @__PURE__ */new Error("Redirect loop or missing Location header")); return; } const redirectUrl = new URL(location, url).href; resolve(downloadToFile(redirectUrl, dest, maxRedirects - 1)); return; } if (!res.statusCode || res.statusCode >= 400) { reject(/* @__PURE__ */new Error(`HTTP ${res.statusCode ?? "?"} downloading file`)); return; } (0, _promises2.pipeline)(res, (0, _nodeFs.createWriteStream)(dest)).then(resolve).catch(reject); }); req.on("error", reject); req.end(); }); } async function findSignalCliBinary(root) { const candidates = []; const enqueue = async (dir, depth) => { if (depth > 3) return; const entries = await _promises.default.readdir(dir, { withFileTypes: true }).catch(() => []); for (const entry of entries) { const full = _nodePath.default.join(dir, entry.name); if (entry.isDirectory()) await enqueue(full, depth + 1);else if (entry.isFile() && entry.name === "signal-cli") candidates.push(full); } }; await enqueue(root, 0); return candidates[0] ?? null; } async function resolveBrewSignalCliPath(brewExe) { try { const result = await (0, _runWithConcurrency2ga3CMk.D)([ brewExe, "--prefix", "signal-cli"], { timeoutMs: 1e4 }); if (result.code === 0 && result.stdout.trim()) { const prefix = result.stdout.trim(); const candidate = _nodePath.default.join(prefix, "bin", "signal-cli"); try { await _promises.default.access(candidate); return candidate; } catch { return findSignalCliBinary(prefix); } } } catch {} return null; } async function installSignalCliViaBrew(runtime) { const brewExe = resolveBrewExecutable(); if (!brewExe) return { ok: false, error: `No native signal-cli build is available for ${process.arch}. Install Homebrew (https://brew.sh) and try again, or install signal-cli manually.` }; runtime.log(`Installing signal-cli via Homebrew (${brewExe})…`); const result = await (0, _runWithConcurrency2ga3CMk.D)([ brewExe, "install", "signal-cli"], { timeoutMs: 15 * 6e4 }); if (result.code !== 0) return { ok: false, error: `brew install signal-cli failed (exit ${result.code}): ${result.stderr.trim().slice(0, 200)}` }; const cliPath = await resolveBrewSignalCliPath(brewExe); if (!cliPath) return { ok: false, error: "brew install succeeded but signal-cli binary was not found." }; let version; try { version = (await (0, _runWithConcurrency2ga3CMk.D)([cliPath, "--version"], { timeoutMs: 1e4 })).stdout.trim().replace(/^signal-cli\s+/, "") || void 0; } catch {} return { ok: true, cliPath, version }; } async function installSignalCliFromRelease(runtime) { const response = await fetch("https://api.github.com/repos/AsamK/signal-cli/releases/latest", { headers: { "User-Agent": "openclaw", Accept: "application/vnd.github+json" } }); if (!response.ok) return { ok: false, error: `Failed to fetch release info (${response.status})` }; const payload = await response.json(); const version = payload.tag_name?.replace(/^v/, "") ?? "unknown"; const asset = pickAsset(payload.assets ?? [], process.platform, process.arch); if (!asset) return { ok: false, error: "No compatible release asset found for this platform." }; const tmpDir = await _promises.default.mkdtemp(_nodePath.default.join(_nodeOs.default.tmpdir(), "openclaw-signal-")); const archivePath = _nodePath.default.join(tmpDir, asset.name); runtime.log(`Downloading signal-cli ${version} (${asset.name})…`); await downloadToFile(asset.browser_download_url, archivePath); const installRoot = _nodePath.default.join(_loggerU3s76KST.p, "tools", "signal-cli", version); await _promises.default.mkdir(installRoot, { recursive: true }); if (!looksLikeArchive(asset.name.toLowerCase())) return { ok: false, error: `Unsupported archive type: ${asset.name}` }; try { await extractSignalCliArchive(archivePath, installRoot, 6e4); } catch (err) { const message = err instanceof Error ? err.message : String(err); return { ok: false, error: `Failed to extract ${asset.name}: ${message}` }; } const cliPath = await findSignalCliBinary(installRoot); if (!cliPath) return { ok: false, error: `signal-cli binary not found after extracting ${asset.name}` }; await _promises.default.chmod(cliPath, 493).catch(() => {}); return { ok: true, cliPath, version }; } async function installSignalCli(runtime) { if (process.platform === "win32") return { ok: false, error: "Signal CLI auto-install is not supported on Windows yet." }; if (process.platform !== "linux" || process.arch === "x64") return installSignalCliFromRelease(runtime); return installSignalCliViaBrew(runtime); } //#endregion //#region src/channels/plugins/onboarding/signal.ts const channel$1 = "signal"; const MIN_E164_DIGITS = 5; const MAX_E164_DIGITS = 15; const DIGITS_ONLY = /^\d+$/; const INVALID_SIGNAL_ACCOUNT_ERROR = "Invalid E.164 phone number (must start with + and country code, e.g. +15555550123)"; function normalizeSignalAccountInput(value) { const trimmed = value?.trim(); if (!trimmed) return null; const digits = (0, _loggerU3s76KST.C)(trimmed).slice(1); if (!DIGITS_ONLY.test(digits)) return null; if (digits.length < MIN_E164_DIGITS || digits.length > MAX_E164_DIGITS) return null; return `+${digits}`; } function isUuidLike(value) { return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value); } function parseSignalAllowFromEntries(raw) { return parseOnboardingEntriesAllowingWildcard(raw, (entry) => { if (entry.toLowerCase().startsWith("uuid:")) { const id = entry.slice(5).trim(); if (!id) return { error: "Invalid uuid entry" }; return { value: `uuid:${id}` }; } if (isUuidLike(entry)) return { value: `uuid:${entry}` }; const normalized = normalizeSignalAccountInput(entry); if (!normalized) return { error: `Invalid entry: ${entry}` }; return { value: normalized }; }); } async function promptSignalAllowFrom(params) { return promptParsedAllowFromForScopedChannel({ cfg: params.cfg, channel: "signal", accountId: params.accountId, defaultAccountId: (0, _accountsCx0R0Kpq.r)(params.cfg), prompter: params.prompter, noteTitle: "Signal allowlist", noteLines: [ "Allowlist Signal DMs by sender id.", "Examples:", "- +15555550123", "- uuid:123e4567-e89b-12d3-a456-426614174000", "Multiple entries: comma-separated.", `Docs: ${(0, _dispatchF_Zbttj.f)("/signal", "signal")}`], message: "Signal allowFrom (E.164 or uuid)", placeholder: "+15555550123, uuid:123e4567-e89b-12d3-a456-426614174000", parseEntries: parseSignalAllowFromEntries, getExistingAllowFrom: ({ cfg, accountId }) => { return (0, _accountsCx0R0Kpq.i)({ cfg, accountId }).config.allowFrom ?? []; } }); } const signalOnboardingAdapter = exports.signalOnboardingAdapter = { channel: channel$1, getStatus: async ({ cfg }) => { const configured = (0, _accountsCx0R0Kpq.n)(cfg).some((accountId) => (0, _accountsCx0R0Kpq.i)({ cfg, accountId }).configured); const signalCliPath = cfg.channels?.signal?.cliPath ?? "signal-cli"; const signalCliDetected = await (0, _dispatchF_Zbttj.x)(signalCliPath); return { channel: channel$1, configured, statusLines: [`Signal: ${configured ? "configured" : "needs setup"}`, `signal-cli: ${signalCliDetected ? "found" : "missing"} (${signalCliPath})`], selectionHint: signalCliDetected ? "signal-cli found" : "signal-cli missing", quickstartScore: signalCliDetected ? 1 : 0 }; }, configure: async ({ cfg, runtime, prompter, accountOverrides, shouldPromptAccountIds, options }) => { const defaultSignalAccountId = (0, _accountsCx0R0Kpq.r)(cfg); const signalAccountId = await resolveAccountIdForConfigure({ cfg, prompter, label: "Signal", accountOverride: accountOverrides.signal, shouldPromptAccountIds, listAccountIds: _accountsCx0R0Kpq.n, defaultAccountId: defaultSignalAccountId }); let next = cfg; const accountConfig = (0, _accountsCx0R0Kpq.i)({ cfg: next, accountId: signalAccountId }).config; let resolvedCliPath = accountConfig.cliPath ?? "signal-cli"; let cliDetected = await (0, _dispatchF_Zbttj.x)(resolvedCliPath); if (options?.allowSignalInstall) { if (await prompter.confirm({ message: cliDetected ? "signal-cli detected. Reinstall/update now?" : "signal-cli not found. Install now?", initialValue: !cliDetected })) try { const result = await installSignalCli(runtime); if (result.ok && result.cliPath) { cliDetected = true; resolvedCliPath = result.cliPath; await prompter.note(`Installed signal-cli at ${result.cliPath}`, "Signal"); } else if (!result.ok) await prompter.note(result.error ?? "signal-cli install failed.", "Signal"); } catch (err) { await prompter.note(`signal-cli install failed: ${String(err)}`, "Signal"); } } if (!cliDetected) await prompter.note("signal-cli not found. Install it, then rerun this step or set channels.signal.cliPath.", "Signal"); let account = accountConfig.account ?? ""; if (account) { const normalizedExisting = normalizeSignalAccountInput(account); if (!normalizedExisting) { await prompter.note("Existing Signal account isn't a valid E.164 number. Please enter it again.", "Signal"); account = ""; } else { account = normalizedExisting; if (!(await prompter.confirm({ message: `Signal account set (${account}). Keep it?`, initialValue: true }))) account = ""; } } if (!account) account = normalizeSignalAccountInput(String(await prompter.text({ message: "Signal bot number (E.164)", validate: (value) => normalizeSignalAccountInput(String(value ?? "")) ? void 0 : INVALID_SIGNAL_ACCOUNT_ERROR }))) ?? ""; if (account) next = patchChannelConfigForAccount({ cfg: next, channel: "signal", accountId: signalAccountId, patch: { account, cliPath: resolvedCliPath ?? "signal-cli" } }); await prompter.note([ "Link device with: signal-cli link -n \"OpenClaw\"", "Scan QR in Signal → Linked Devices", `Then run: ${(0, _configDiiPndBn.Br)("openclaw gateway call channels.status --params '{\"probe\":true}'")}`, `Docs: ${(0, _dispatchF_Zbttj.f)("/signal", "signal")}`]. join("\n"), "Signal next steps"); return { cfg: next, accountId: signalAccountId }; }, dmPolicy: { label: "Signal", channel: channel$1, policyKey: "channels.signal.dmPolicy", allowFromKey: "channels.signal.allowFrom", getCurrent: (cfg) => cfg.channels?.signal?.dmPolicy ?? "pairing", setPolicy: (cfg, policy) => setChannelDmPolicyWithAllowFrom({ cfg, channel: "signal", dmPolicy: policy }), promptAllowFrom: promptSignalAllowFrom }, disable: (cfg) => setOnboardingChannelEnabled(cfg, channel$1, false) }; //#endregion //#region src/config/merge-config.ts function mergeConfigSection(base, patch, options = {}) { const next = { ...(base ?? void 0) }; for (const [key, value] of Object.entries(patch)) { if (value === void 0) { if (options.unsetOnUndefined?.includes(key)) delete next[key]; continue; } next[key] = value; } return next; } function mergeWhatsAppConfig(cfg, patch, options) { return { ...cfg, channels: { ...cfg.channels, whatsapp: mergeConfigSection(cfg.channels?.whatsapp, patch, options) } }; } //#endregion //#region src/channels/plugins/onboarding/whatsapp.ts const channel = "whatsapp"; function setWhatsAppDmPolicy(cfg, dmPolicy) { return mergeWhatsAppConfig(cfg, { dmPolicy }); } function setWhatsAppAllowFrom(cfg, allowFrom) { return mergeWhatsAppConfig(cfg, { allowFrom }, { unsetOnUndefined: ["allowFrom"] }); } function setWhatsAppSelfChatMode(cfg, selfChatMode) { return mergeWhatsAppConfig(cfg, { selfChatMode }); } async function detectWhatsAppLinked(cfg, accountId) { const { authDir } = (0, _accountsBFBjizxh.a)({ cfg, accountId }); return await (0, _loggerU3s76KST.w)(_nodePath.default.join(authDir, "creds.json")); } async function promptWhatsAppOwnerAllowFrom(params) { const { prompter, existingAllowFrom } = params; await prompter.note("We need the sender/owner number so OpenClaw can allowlist you.", "WhatsApp number"); const entry = await prompter.text({ message: "Your personal WhatsApp number (the phone you will message from)", placeholder: "+15555550123", initialValue: existingAllowFrom[0], validate: (value) => { const raw = String(value ?? "").trim(); if (!raw) return "Required"; if (!(0, _loggerU3s76KST.C)(raw)) return `Invalid number: ${raw}`; } }); const normalized = (0, _loggerU3s76KST.C)(String(entry).trim()); if (!normalized) throw new Error("Invalid WhatsApp owner number (expected E.164 after validation)."); return { normalized, allowFrom: normalizeAllowFromEntries([...existingAllowFrom.filter((item) => item !== "*"), normalized], _loggerU3s76KST.C) }; } async function applyWhatsAppOwnerAllowlist(params) { const { normalized, allowFrom } = await promptWhatsAppOwnerAllowFrom({ prompter: params.prompter, existingAllowFrom: params.existingAllowFrom }); let next = setWhatsAppSelfChatMode(params.cfg, true); next = setWhatsAppDmPolicy(next, "allowlist"); next = setWhatsAppAllowFrom(next, allowFrom); await params.prompter.note([...params.messageLines, `- allowFrom includes ${normalized}`].join("\n"), params.title); return next; } function parseWhatsAppAllowFromEntries(raw) { const parts = splitOnboardingEntries(raw); if (parts.length === 0) return { entries: [] }; const entries = []; for (const part of parts) { if (part === "*") { entries.push("*"); continue; } const normalized = (0, _loggerU3s76KST.C)(part); if (!normalized) return { entries: [], invalidEntry: part }; entries.push(normalized); } return { entries: normalizeAllowFromEntries(entries, _loggerU3s76KST.C) }; } async function promptWhatsAppAllowFrom(cfg, _runtime, prompter, options) { const existingPolicy = cfg.channels?.whatsapp?.dmPolicy ?? "pairing"; const existingAllowFrom = cfg.channels?.whatsapp?.allowFrom ?? []; const existingLabel = existingAllowFrom.length > 0 ? existingAllowFrom.join(", ") : "unset"; if (options?.forceAllowlist) return await applyWhatsAppOwnerAllowlist({ cfg, prompter, existingAllowFrom, title: "WhatsApp allowlist", messageLines: ["Allowlist mode enabled."] }); await prompter.note([ "WhatsApp direct chats are gated by `channels.whatsapp.dmPolicy` + `channels.whatsapp.allowFrom`.", "- pairing (default): unknown senders get a pairing code; owner approves", "- allowlist: unknown senders are blocked", "- open: public inbound DMs (requires allowFrom to include \"*\")", "- disabled: ignore WhatsApp DMs", "", `Current: dmPolicy=${existingPolicy}, allowFrom=${existingLabel}`, `Docs: ${(0, _dispatchF_Zbttj.f)("/whatsapp", "whatsapp")}`]. join("\n"), "WhatsApp DM access"); if ((await prompter.select({ message: "WhatsApp phone setup", options: [{ value: "personal", label: "This is my personal phone number" }, { value: "separate", label: "Separate phone just for OpenClaw" }] })) === "personal") return await applyWhatsAppOwnerAllowlist({ cfg, prompter, existingAllowFrom, title: "WhatsApp personal phone", messageLines: ["Personal phone mode enabled.", "- dmPolicy set to allowlist (pairing skipped)"] }); const policy = await prompter.select({ message: "WhatsApp DM policy", options: [ { value: "pairing", label: "Pairing (recommended)" }, { value: "allowlist", label: "Allowlist only (block unknown senders)" }, { value: "open", label: "Open (public inbound DMs)" }, { value: "disabled", label: "Disabled (ignore WhatsApp DMs)" }] }); let next = setWhatsAppSelfChatMode(cfg, false); next = setWhatsAppDmPolicy(next, policy); if (policy === "open") { const allowFrom = normalizeAllowFromEntries(["*", ...existingAllowFrom], _loggerU3s76KST.C); next = setWhatsAppAllowFrom(next, allowFrom.length > 0 ? allowFrom : ["*"]); return next; } if (policy === "disabled") return next; const allowOptions = existingAllowFrom.length > 0 ? [ { value: "keep", label: "Keep current allowFrom" }, { value: "unset", label: "Unset allowFrom (use pairing approvals only)" }, { value: "list", label: "Set allowFrom to specific numbers" }] : [{ value: "unset", label: "Unset allowFrom (default)" }, { value: "list", label: "Set allowFrom to specific numbers" }]; const mode = await prompter.select({ message: "WhatsApp allowFrom (optional pre-allowlist)", options: allowOptions.map((opt) => ({ value: opt.value, label: opt.label })) }); if (mode === "keep") {} else if (mode === "unset") next = setWhatsAppAllowFrom(next, void 0);else { const allowRaw = await prompter.text({ message: "Allowed sender numbers (comma-separated, E.164)", placeholder: "+15555550123, +447700900123", validate: (value) => { const raw = String(value ?? "").trim(); if (!raw) return "Required"; const parsed = parseWhatsAppAllowFromEntries(raw); if (parsed.entries.length === 0 && !parsed.invalidEntry) return "Required"; if (parsed.invalidEntry) return `Invalid number: ${parsed.invalidEntry}`; } }); const parsed = parseWhatsAppAllowFromEntries(String(allowRaw)); next = setWhatsAppAllowFrom(next, parsed.entries); } return next; } const whatsappOnboardingAdapter = exports.whatsappOnboardingAdapter = { channel, getStatus: async ({ cfg, accountOverrides }) => { const defaultAccountId = (0, _accountsBFBjizxh.r)(cfg); const accountId = resolveOnboardingAccountId({ accountId: accountOverrides.whatsapp, defaultAccountId }); const linked = await detectWhatsAppLinked(cfg, accountId); return { channel, configured: linked, statusLines: [`WhatsApp (${accountId === "default" ? "default" : accountId}): ${linked ? "linked" : "not linked"}`], selectionHint: linked ? "linked" : "not linked", quickstartScore: linked ? 5 : 4 }; }, configure: async ({ cfg, runtime, prompter, options, accountOverrides, shouldPromptAccountIds, forceAllowFrom }) => { const accountId = await resolveAccountIdForConfigure({ cfg, prompter, label: "WhatsApp", accountOverride: accountOverrides.whatsapp, shouldPromptAccountIds: Boolean(shouldPromptAccountIds || options?.promptWhatsAppAccountId), listAccountIds: _accountsBFBjizxh.n, defaultAccountId: (0, _accountsBFBjizxh.r)(cfg) }); let next = cfg; if (accountId !== "default") next = { ...next, channels: { ...next.channels, whatsapp: { ...next.channels?.whatsapp, accounts: { ...next.channels?.whatsapp?.accounts, [accountId]: { ...next.channels?.whatsapp?.accounts?.[accountId], enabled: next.channels?.whatsapp?.accounts?.[accountId]?.enabled ?? true } } } } }; const linked = await detectWhatsAppLinked(next, accountId); const { authDir } = (0, _accountsBFBjizxh.a)({ cfg: next, accountId }); if (!linked) await prompter.note([ "Scan the QR with WhatsApp on your phone.", `Credentials are stored under ${authDir}/ for future runs.`, `Docs: ${(0, _dispatchF_Zbttj.f)("/whatsapp", "whatsapp")}`]. join("\n"), "WhatsApp linking"); if (await prompter.confirm({ message: linked ? "WhatsApp already linked. Re-link now?" : "Link WhatsApp now (QR)?", initialValue: !linked })) try { await (0, _loginC7cFTFMn.t)(false, void 0, runtime, accountId); } catch (err) { runtime.error(`WhatsApp login failed: ${String(err)}`); await prompter.note(`Docs: ${(0, _dispatchF_Zbttj.f)("/whatsapp", "whatsapp")}`, "WhatsApp help"); } else if (!linked) await prompter.note(`Run \`${(0, _configDiiPndBn.Br)("openclaw channels login")}\` later to link WhatsApp.`, "WhatsApp"); next = await promptWhatsAppAllowFrom(next, runtime, prompter, { forceAllowlist: forceAllowFrom }); return { cfg: next, accountId }; }, onAccountRecorded: (accountId, options) => { options?.onWhatsAppAccountId?.(accountId); } }; //#endregion //#region src/channels/plugins/status-issues/whatsapp.ts function readWhatsAppAccountStatus(value) { if (!(0, _loggerU3s76KST.b)(value)) return null; return { accountId: value.accountId, enabled: value.enabled, linked: value.linked, connected: value.connected, running: value.running, reconnectAttempts: value.reconnectAttempts, lastError: value.lastError }; } function collectWhatsAppStatusIssues(accounts) { return collectIssuesForEnabledAccounts({ accounts, readAccount: readWhatsAppAccountStatus, collectIssues: ({ account, accountId, issues }) => { const linked = account.linked === true; const running = account.running === true; const connected = account.connected === true; const reconnectAttempts = typeof account.reconnectAttempts === "number" ? account.reconnectAttempts : null; const lastError = asString(account.lastError); if (!linked) { issues.push({ channel: "whatsapp", accountId, kind: "auth", message: "Not linked (no WhatsApp Web session).", fix: `Run: ${(0, _configDiiPndBn.Br)("openclaw channels login")} (scan QR on the gateway host).` }); return; } if (running && !connected) issues.push({ channel: "whatsapp", accountId, kind: "runtime", message: `Linked but disconnected${reconnectAttempts != null ? ` (reconnectAttempts=${reconnectAttempts})` : ""}${lastError ? `: ${lastError}` : "."}`, fix: `Run: ${(0, _configDiiPndBn.Br)("openclaw doctor")} (or restart the gateway). If it persists, relink via channels login and check logs.` }); } }); } //#endregion //#region src/channels/plugins/status-issues/bluebubbles.ts function readBlueBubblesAccountStatus(value) { if (!(0, _loggerU3s76KST.b)(value)) return null; return { accountId: value.accountId, enabled: value.enabled, configured: value.configured, running: value.running, baseUrl: value.baseUrl, lastError: value.lastError, probe: value.probe }; } function readBlueBubblesProbeResult(value) { if (!(0, _loggerU3s76KST.b)(value)) return null; return { ok: typeof value.ok === "boolean" ? value.ok : void 0, status: typeof value.status === "number" ? value.status : null, error: asString(value.error) ?? null }; } function collectBlueBubblesStatusIssues(accounts) { return collectIssuesForEnabledAccounts({ accounts, readAccount: readBlueBubblesAccountStatus, collectIssues: ({ account, accountId, issues }) => { const configured = account.configured === true; const running = account.running === true; const lastError = asString(account.lastError); const probe = readBlueBubblesProbeResult(account.probe); if (!configured) { issues.push({ channel: "bluebubbles", accountId, kind: "config", message: "Not configured (missing serverUrl or password).", fix: "Run: openclaw channels add bluebubbles --http-url --password " }); return; } if (probe && probe.ok === false) { const errorDetail = probe.error ? `: ${probe.error}` : probe.status ? ` (HTTP ${probe.status})` : ""; issues.push({ channel: "bluebubbles", accountId, kind: "runtime", message: `BlueBubbles server unreachable${errorDetail}`, fix: "Check that the BlueBubbles server is running and accessible. Verify serverUrl and password in your config." }); } if (running && lastError) issues.push({ channel: "bluebubbles", accountId, kind: "runtime", message: `Channel error: ${lastError}`, fix: "Check gateway logs for details. If the webhook is failing, verify the webhook URL is configured in BlueBubbles server settings." }); } }); } //#endregion //#region src/line/config-schema.ts const DmPolicySchema$1 = _zod.z.enum([ "open", "allowlist", "pairing", "disabled"] ); const GroupPolicySchema$1 = _zod.z.enum([ "open", "allowlist", "disabled"] ); const LineCommonConfigSchema = _zod.z.object({ enabled: _zod.z.boolean().optional(), channelAccessToken: _zod.z.string().optional(), channelSecret: _zod.z.string().optional(), tokenFile: _zod.z.string().optional(), secretFile: _zod.z.string().optional(), name: _zod.z.string().optional(), allowFrom: _zod.z.array(_zod.z.union([_zod.z.string(), _zod.z.number()])).optional(), groupAllowFrom: _zod.z.array(_zod.z.union([_zod.z.string(), _zod.z.number()])).optional(), dmPolicy: DmPolicySchema$1.optional().default("pairing"), groupPolicy: GroupPolicySchema$1.optional().default("allowlist"), responsePrefix: _zod.z.string().optional(), mediaMaxMb: _zod.z.number().optional(), webhookPath: _zod.z.string().optional() }); const LineGroupConfigSchema = _zod.z.object({ enabled: _zod.z.boolean().optional(), allowFrom: _zod.z.array(_zod.z.union([_zod.z.string(), _zod.z.number()])).optional(), requireMention: _zod.z.boolean().optional(), systemPrompt: _zod.z.string().optional(), skills: _zod.z.array(_zod.z.string()).optional() }).strict(); const LineAccountConfigSchema = LineCommonConfigSchema.extend({ groups: _zod.z.record(_zod.z.string(), LineGroupConfigSchema.optional()).optional() }).strict(); const LineConfigSchema = exports.LineConfigSchema = LineCommonConfigSchema.extend({ accounts: _zod.z.record(_zod.z.string(), LineAccountConfigSchema.optional()).optional(), defaultAccount: _zod.z.string().optional(), groups: _zod.z.record(_zod.z.string(), LineGroupConfigSchema.optional()).optional() }).strict(); //#endregion /* v9-37f9b428312c5eae */