import { a as normalizeLowercaseStringOrEmpty, c as normalizeOptionalString, l as normalizeOptionalStringifiedId } from "./string-coerce-DW4mBlAt.js";
import { r as createLazyRuntimeModule } from "./lazy-runtime-B-Fc-m0I.js";
import { o as isRecord } from "./record-coerce-DHZ4bFlT.js";
import { n as normalizeAtHashSlug } from "./string-normalization-CRyoFBPt.js";
import { r as formatErrorMessage } from "./errors-DMsu67n4.js";
import { s as sleepWithAbort } from "./src-DKBD8PDy.js";
import { t as DEFAULT_ACCOUNT_ID } from "./account-id-C7N4Rwku.js";
import "./string-coerce-runtime-DsF17V0Z.js";
import { n as resolveTargetsWithOptionalToken } from "./target-resolvers-C4bHUKEV.js";
import "./error-runtime-de_uj14m.js";
import "./runtime-env-DyN3Yn8v.js";
import { d as resolveScopeRequireMention, f as resolveScopeToolsPolicy, p as scopeKey } from "./channel-policy-PlwZT1KM.js";
import { n as createChannelDirectoryAdapter } from "./directory-runtime-Jh5LzMXd.js";
import { t as createRuntimeDirectoryLiveAdapter } from "./runtime-forwarders-Dxil5z45.js";
import { i as createChatChannelPlugin } from "./core-Vq_PHglM.js";
import { n as createApproverRestrictedNativeApprovalCapability } from "./approval-delivery-helpers-C0tKqA2W.js";
import { n as createLazyChannelApprovalNativeRuntimeAdapter } from "./approval-handler-adapter-runtime-DjbKLbMW.js";
import { n as resolveApprovalRequestSessionConversation } from "./exec-approval-session-target-C6hOm9P-.js";
import { n as createChannelApproverDmTargetResolver, r as createChannelNativeOriginTargetResolver } from "./approval-native-helpers-DcUv5CxN.js";
import "./approval-native-runtime-QAVdQvNg.js";
import { c as resolveConfiguredFromCredentialStatuses, i as projectCredentialSnapshotFields } from "./account-snapshot-fields-BeI_EUui.js";
import { f as createChannelMessageAdapterFromOutbound } from "./channel-outbound-DB2gO0FM.js";
import { c as createNestedAllowlistOverrideResolver, o as createAccountScopedAllowlistNameResolver, r as buildLegacyDmAccountAllowlistAdapter } from "./allowlist-config-edit-BFyOWbYq.js";
import { t as PAIRING_APPROVED_MESSAGE } from "./pairing-message-DNhqI-OE.js";
import { _ as asString, b as resolveEnabledConfiguredAccountId, d as createDefaultChannelRuntimeState, g as appendMatchMetadata, o as buildTokenChannelStatusSummary, p as readAccountStatusSnapshot, u as createComputedAccountStatusAdapter } from "./status-helpers-qb1hhp-k.js";
import "./channel-core-B4dqPmDe.js";
import { i as createPairingPrefixStripper } from "./channel-pairing-CG6IyTEs.js";
import { c as resolveDiscordAccountAllowFrom, i as listEnabledDiscordAccounts, o as resolveDefaultDiscordAccountId, r as listDiscordAccountIds, s as resolveDiscordAccount } from "./accounts-D8p2O3Mr.js";
import { t as getDiscordRuntime } from "./runtime-n11XewvP.js";
import { t as parseDiscordTarget } from "./target-parsing-3ckHML6_.js";
import { n as looksLikeDiscordTargetId, r as normalizeDiscordMessagingTarget } from "./normalize-CqGlfyY_.js";
import "./channel-api-BN5iE5qT.js";
import { t as resolveDiscordOutboundSessionRoute } from "./outbound-session-route-DBBtpb6g.js";
import { u as withAbortTimeout } from "./timeouts-te9wpHJo.js";
import { i as shouldSuppressLocalDiscordExecApprovalPrompt, n as isDiscordExecApprovalApprover, r as isDiscordExecApprovalClientEnabled, t as getDiscordExecApprovalApprovers } from "./exec-approvals-DN3P53WF.js";
import { t as shouldHandleDiscordApprovalRequest } from "./approval-shared-CCrHtwoU.js";
import { r as resolveRequiredDiscordChannelPermissions } from "./audit-core-DUfgT0Fx.js";
import { t as discordMessageActions$1 } from "./channel-actions-58SKbGFJ.js";
import { n as resolveDiscordCurrentConversationIdentity } from "./conversation-identity-hW-9sBAG.js";
import { r as openDiscordCommandDeployHashStore } from "./command-deploy-store-DFkBTViB.js";
import { n as setThreadBindingMaxAgeBySessionKey, t as setThreadBindingIdleTimeoutBySessionKey } from "./thread-bindings.session-updates-CRyYmLU8.js";
import { n as discordOutbound } from "./outbound-adapter-DuYoDkLf.js";
import { i as discordSecurityAdapter, n as discordConfigAdapter, r as discordSetupAdapter, t as createDiscordPluginBase } from "./shared-LdLaScvL.js";
import { t as normalizeExplicitDiscordSessionKey } from "./session-key-normalization-DjX1x-cC.js";
import { t as defaultTopLevelPlacement } from "./thread-binding-api-BDZJD4na.js";
//#region extensions/discord/src/approval-native.ts
function extractDiscordSessionKind(sessionKey) {
	if (!sessionKey) return null;
	const match = sessionKey.match(/discord:(?:[^:]+:)?(channel|group|dm|direct):/);
	if (!match) return null;
	const raw = match[1];
	if (raw === "direct") return "dm";
	return raw === "channel" || raw === "group" || raw === "dm" ? raw : null;
}
function normalizeDiscordOriginChannelId(value) {
	if (!value) return null;
	const trimmed = value.trim();
	if (!trimmed) return null;
	const prefixed = trimmed.match(/^(?:channel|group):(\d+)$/i);
	if (prefixed) return prefixed[1] ?? null;
	return /^\d+$/.test(trimmed) ? trimmed : null;
}
function normalizeDiscordThreadId(value) {
	if (typeof value === "number") return Number.isFinite(value) ? String(value) : void 0;
	if (typeof value !== "string") return;
	const normalized = value.trim();
	return /^\d+$/.test(normalized) ? normalized : void 0;
}
function createDiscordOriginTargetResolver(configOverride) {
	return createChannelNativeOriginTargetResolver({
		channel: "discord",
		shouldHandleRequest: ({ cfg, accountId, request }) => shouldHandleDiscordApprovalRequest({
			cfg,
			accountId,
			request,
			configOverride
		}),
		resolveTurnSourceTarget: (request) => {
			const sessionConversation = resolveApprovalRequestSessionConversation({
				request,
				channel: "discord",
				bundledFallback: false
			});
			const sessionKind = extractDiscordSessionKind(normalizeOptionalString(request.request.sessionKey) ?? null);
			const turnSourceChannel = normalizeLowercaseStringOrEmpty(request.request.turnSourceChannel);
			const rawTurnSourceTo = normalizeOptionalString(request.request.turnSourceTo) ?? "";
			const turnSourceTo = normalizeDiscordOriginChannelId(rawTurnSourceTo);
			const threadId = normalizeDiscordThreadId(request.request.turnSourceThreadId) ?? normalizeDiscordThreadId(sessionConversation?.threadId) ?? void 0;
			const hasExplicitOriginTarget = /^(?:channel|group):/i.test(rawTurnSourceTo);
			if (turnSourceChannel !== "discord" || !turnSourceTo || sessionKind === "dm") return null;
			return hasExplicitOriginTarget || sessionKind === "channel" || sessionKind === "group" ? {
				to: turnSourceTo,
				threadId
			} : null;
		},
		resolveSessionTarget: (sessionTarget, request) => {
			const sessionConversation = resolveApprovalRequestSessionConversation({
				request,
				channel: "discord",
				bundledFallback: false
			});
			if (extractDiscordSessionKind(request.request.sessionKey?.trim() || null) === "dm") return null;
			const targetTo = normalizeDiscordOriginChannelId(sessionTarget.to);
			return targetTo ? {
				to: targetTo,
				threadId: normalizeDiscordThreadId(sessionTarget.threadId) ?? normalizeDiscordThreadId(sessionConversation?.threadId) ?? void 0
			} : null;
		},
		resolveFallbackTarget: (request) => {
			const sessionConversation = resolveApprovalRequestSessionConversation({
				request,
				channel: "discord",
				bundledFallback: false
			});
			if (extractDiscordSessionKind(request.request.sessionKey?.trim() || null) === "dm") return null;
			const fallbackChannelId = normalizeDiscordOriginChannelId(sessionConversation?.id);
			return fallbackChannelId ? {
				to: fallbackChannelId,
				threadId: normalizeDiscordThreadId(sessionConversation?.threadId) ?? void 0
			} : null;
		}
	});
}
function createDiscordApproverDmTargetResolver(configOverride) {
	return createChannelApproverDmTargetResolver({
		shouldHandleRequest: ({ cfg, accountId, request }) => shouldHandleDiscordApprovalRequest({
			cfg,
			accountId,
			request,
			configOverride
		}),
		resolveApprovers: ({ cfg, accountId }) => getDiscordExecApprovalApprovers({
			cfg,
			accountId,
			configOverride
		}),
		mapApprover: (approver) => ({ to: approver })
	});
}
function createDiscordApprovalCapability(configOverride) {
	return createApproverRestrictedNativeApprovalCapability({
		channel: "discord",
		channelLabel: "Discord",
		describeExecApprovalSetup: ({ accountId }) => {
			const prefix = accountId && accountId !== "default" ? `channels.discord.accounts.${accountId}` : "channels.discord";
			return `Approve it from the Web UI or terminal UI for now. Discord supports native exec approvals for this account. Configure \`${prefix}.execApprovals.approvers\` or \`commands.ownerAllowFrom\`; set \`${prefix}.execApprovals.enabled\` to \`auto\` or \`true\`.`;
		},
		listAccountIds: listDiscordAccountIds,
		hasApprovers: ({ cfg, accountId }) => getDiscordExecApprovalApprovers({
			cfg,
			accountId,
			configOverride
		}).length > 0,
		isExecAuthorizedSender: ({ cfg, accountId, senderId }) => isDiscordExecApprovalApprover({
			cfg,
			accountId,
			senderId,
			configOverride
		}),
		isNativeDeliveryEnabled: ({ cfg, accountId }) => isDiscordExecApprovalClientEnabled({
			cfg,
			accountId,
			configOverride
		}),
		resolveNativeDeliveryMode: ({ cfg, accountId }) => configOverride?.target ?? resolveDiscordAccount({
			cfg,
			accountId
		}).config.execApprovals?.target ?? "dm",
		resolveOriginTarget: createDiscordOriginTargetResolver(configOverride),
		resolveApproverDmTargets: createDiscordApproverDmTargetResolver(configOverride),
		notifyOriginWhenDmOnly: true,
		nativeRuntime: createLazyChannelApprovalNativeRuntimeAdapter({
			eventKinds: ["exec", "plugin"],
			isConfigured: ({ cfg, accountId }) => isDiscordExecApprovalClientEnabled({
				cfg,
				accountId,
				configOverride
			}),
			shouldHandle: ({ cfg, accountId, request }) => shouldHandleDiscordApprovalRequest({
				cfg,
				accountId,
				request,
				configOverride
			}),
			load: async () => (await import("./approval-handler.runtime-BYw3K0tk.js")).discordApprovalNativeRuntime
		})
	});
}
let cachedDiscordApprovalCapability;
function getDiscordApprovalCapability() {
	cachedDiscordApprovalCapability ??= createDiscordApprovalCapability();
	return cachedDiscordApprovalCapability;
}
//#endregion
//#region extensions/discord/src/channel.conversation.ts
function resolveDiscordAttachedOutboundTarget(params) {
	if (params.threadId == null) return params.to;
	const threadId = normalizeOptionalStringifiedId(params.threadId) ?? "";
	return threadId ? `channel:${threadId}` : params.to;
}
function buildDiscordCrossContextPresentation(params) {
	return {
		tone: "neutral",
		blocks: [...params.message.trim() ? [{
			type: "text",
			text: params.message
		}, { type: "divider" }] : [], {
			type: "context",
			text: `From ${params.originLabel}`
		}]
	};
}
function normalizeDiscordAcpConversationId(conversationId) {
	const normalized = conversationId.trim();
	return normalized ? { conversationId: normalized } : null;
}
function matchDiscordAcpConversation(params) {
	if (params.bindingConversationId === params.conversationId) return {
		conversationId: params.conversationId,
		matchPriority: 2
	};
	if (params.parentConversationId && params.parentConversationId !== params.conversationId && params.bindingConversationId === params.parentConversationId) return {
		conversationId: params.parentConversationId,
		matchPriority: 1
	};
	return null;
}
function resolveDiscordConversationIdFromTargets(targets) {
	for (const raw of targets) {
		const trimmed = raw?.trim();
		if (!trimmed) continue;
		try {
			const target = parseDiscordTarget(trimmed, { defaultKind: "channel" });
			if (target?.normalized) return target.normalized;
		} catch {
			const mentionMatch = trimmed.match(/^<#(\d+)>$/);
			if (mentionMatch?.[1]) return `channel:${mentionMatch[1]}`;
			if (/^\d{6,}$/.test(trimmed)) return normalizeDiscordMessagingTarget(trimmed);
		}
	}
}
function parseDiscordParentChannelFromSessionKey(raw) {
	const sessionKey = normalizeLowercaseStringOrEmpty(raw);
	if (!sessionKey) return;
	const match = sessionKey.match(/(?:^|:)channel:([^:]+)$/);
	return match?.[1] ? `channel:${match[1]}` : void 0;
}
function resolveDiscordCommandConversation(params) {
	const threadConversation = resolveDiscordThreadConversationRef(params);
	if (threadConversation) return threadConversation;
	const conversationId = resolveDiscordCurrentConversationIdentity({
		from: params.from,
		chatType: params.chatType,
		originatingTo: params.originatingTo,
		commandTo: params.commandTo,
		fallbackTo: params.fallbackTo
	});
	return conversationId ? { conversationId } : null;
}
function resolveDiscordThreadConversationRef(params) {
	const threadId = normalizeOptionalStringifiedId(params.threadId);
	if (!threadId) return null;
	const targets = [
		params.originatingTo ?? params.to,
		params.commandTo,
		params.fallbackTo ?? params.conversationId
	];
	const parentConversationId = normalizeDiscordMessagingTarget(normalizeOptionalStringifiedId(params.threadParentId) ?? "") || parseDiscordParentChannelFromSessionKey(params.parentSessionKey) || resolveDiscordConversationIdFromTargets(targets);
	return {
		conversationId: threadId,
		...parentConversationId && parentConversationId !== threadId ? { parentConversationId } : {}
	};
}
function resolveDiscordInboundConversation(params) {
	const threadConversation = resolveDiscordThreadConversationRef({
		to: params.to,
		conversationId: params.conversationId,
		threadId: params.threadId,
		threadParentId: params.threadParentId
	});
	if (threadConversation) return threadConversation;
	const conversationId = resolveDiscordCurrentConversationIdentity({
		from: params.from,
		chatType: params.isGroup ? "group" : "direct",
		originatingTo: params.to,
		fallbackTo: params.conversationId
	});
	return conversationId ? { conversationId } : null;
}
//#endregion
//#region extensions/discord/src/channel.loaders.ts
const loadDiscordDirectoryConfigModule = createLazyRuntimeModule(() => import("./directory-config-x_ntj-LB.js"));
const loadDiscordResolveChannelsModule = createLazyRuntimeModule(() => import("./resolve-channels-Dh1Z9Oqi.js"));
const loadDiscordResolveUsersModule = createLazyRuntimeModule(() => import("./resolve-users-B7zgZXXD.js"));
const loadDiscordThreadBindingsManagerModule = createLazyRuntimeModule(() => import("./thread-bindings.manager-B4SbmGIs.js"));
const loadDiscordTargetResolverModule = createLazyRuntimeModule(() => import("./target-resolver-BalR1ps1.js"));
const loadDiscordProviderRuntime = createLazyRuntimeModule(() => import("./provider.runtime.js"));
const loadDiscordProbeRuntime = createLazyRuntimeModule(() => import("./probe.runtime-CoV9vp03.js"));
async function probeDiscordStatusAccount(params) {
	const startedAtMs = Date.now();
	const runtime = await loadDiscordProbeRuntime();
	const remainingMs = Math.max(1, params.timeoutMs - Math.max(0, Date.now() - startedAtMs));
	return await runtime.probeDiscord(params.token, remainingMs, { includeApplication: true });
}
const loadDiscordAuditModule = createLazyRuntimeModule(() => import("./audit-CWLWwobk.js"));
const loadDiscordSendModule = createLazyRuntimeModule(() => import("./send-BphjQWwR.js"));
const loadDiscordDirectoryLiveModule = createLazyRuntimeModule(() => import("./directory-live-BrgrOtxW.js"));
//#endregion
//#region extensions/discord/src/group-policy.ts
function normalizeDiscordSlug(value) {
	return normalizeAtHashSlug(value);
}
const guildScopeKey = (guildKey) => scopeKey(["guild", guildKey]);
const channelScopeKey = (guildKey, channelKey) => scopeKey(["guild", guildKey], ["channel", channelKey]);
function resolveDiscordGuildKey(guilds, groupSpace) {
	if (!guilds || Object.keys(guilds).length === 0) return;
	const space = normalizeOptionalString(groupSpace) ?? "";
	if (space && guilds[space]) return space;
	const normalized = normalizeDiscordSlug(space);
	if (normalized && guilds[normalized]) return normalized;
	if (normalized) {
		const match = Object.entries(guilds).find(([, entry]) => normalizeDiscordSlug(entry?.slug ?? void 0) === normalized);
		if (match) return match[0];
	}
	return guilds["*"] ? "*" : void 0;
}
function resolveDiscordChannelKey(channelEntries, params) {
	if (!channelEntries || Object.keys(channelEntries).length === 0) return;
	const groupChannel = params.groupChannel;
	const channelSlug = normalizeDiscordSlug(groupChannel);
	if (params.groupId && channelEntries[params.groupId]) return params.groupId;
	if (channelSlug && channelEntries[channelSlug]) return channelSlug;
	if (channelSlug && channelEntries[`#${channelSlug}`]) return `#${channelSlug}`;
	const normalizedGroupChannel = groupChannel ? normalizeDiscordSlug(groupChannel) : void 0;
	return normalizedGroupChannel !== void 0 && channelEntries[normalizedGroupChannel] ? normalizedGroupChannel : void 0;
}
function buildDiscordPolicyTree(guilds) {
	const scopes = {};
	for (const [guildKey, guild] of Object.entries(guilds ?? {})) {
		scopes[guildScopeKey(guildKey)] = {
			requireMention: guild.requireMention,
			tools: guild.tools,
			toolsBySender: guild.toolsBySender
		};
		for (const [channelKey, channel] of Object.entries(guild.channels ?? {})) scopes[channelScopeKey(guildKey, channelKey)] = {
			requireMention: channel.requireMention,
			tools: channel.tools,
			toolsBySender: channel.toolsBySender
		};
	}
	return { scopes };
}
function resolveDiscordPolicyScope(params) {
	const guilds = (params.accountId ? params.cfg.channels?.discord?.accounts?.[params.accountId]?.guilds : void 0) ?? params.cfg.channels?.discord?.guilds;
	const tree = buildDiscordPolicyTree(guilds);
	const guildKey = resolveDiscordGuildKey(guilds, params.groupSpace);
	if (!guildKey) return {
		tree,
		path: []
	};
	const channelKey = resolveDiscordChannelKey(guilds?.[guildKey]?.channels, params);
	return {
		tree,
		path: [guildScopeKey(guildKey), ...channelKey !== void 0 ? [channelScopeKey(guildKey, channelKey)] : []]
	};
}
function resolveDiscordGroupRequireMention(params) {
	return resolveScopeRequireMention(resolveDiscordPolicyScope(params));
}
function resolveDiscordGroupToolPolicy(params) {
	return resolveScopeToolsPolicy({
		...resolveDiscordPolicyScope(params),
		senderId: params.senderId,
		senderName: params.senderName,
		senderUsername: params.senderUsername,
		senderE164: params.senderE164
	});
}
//#endregion
//#region extensions/discord/src/status-issues.ts
function readDiscordApplicationSummary(value) {
	if (!isRecord(value)) return {};
	const intentsRaw = value.intents;
	if (!isRecord(intentsRaw)) return {};
	return { intents: { messageContent: intentsRaw.messageContent === "enabled" || intentsRaw.messageContent === "limited" || intentsRaw.messageContent === "disabled" ? intentsRaw.messageContent : void 0 } };
}
function readDiscordPermissionsAuditSummary(value) {
	if (!isRecord(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 (!isRecord(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 = readAccountStatusSnapshot(entry, [
			"healthState",
			"application",
			"audit"
		]);
		if (!account) continue;
		const accountId = resolveEnabledConfiguredAccountId(account);
		if (!accountId) continue;
		const running = account.running === true;
		const healthState = asString(account.healthState);
		if (healthState === "stale-socket" || healthState === "stuck" || healthState === "disconnected" || healthState === "not-running") {
			const runningLabel = running ? "running" : "not running";
			issues.push({
				channel: "discord",
				accountId,
				kind: "runtime",
				message: `Discord gateway transport is degraded (${healthState}; account is ${runningLabel}).`,
				fix: "Check gateway event-loop health and Discord connectivity, then restart the Discord channel or gateway if the transport does not recover."
			});
		} else if (running && account.connected === false) issues.push({
			channel: "discord",
			accountId,
			kind: "runtime",
			message: "Discord gateway transport is running but disconnected.",
			fix: "Check gateway logs for Discord websocket errors and wait for reconnect; restart the Discord channel or gateway if it does not recover."
		});
		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 extensions/discord/src/channel.ts
const DISCORD_ACCOUNT_STARTUP_STAGGER_MS = 1e4;
const discordMessageAdapter = createChannelMessageAdapterFromOutbound({
	id: "discord",
	outbound: discordOutbound,
	live: {
		capabilities: {
			draftPreview: true,
			previewFinalization: true,
			progressUpdates: true
		},
		finalizer: { capabilities: {
			finalEdit: false,
			normalFallback: true,
			discardPending: true
		} }
	}
});
function startDiscordStartupProbe(params) {
	(async () => {
		try {
			const probe = await (await loadDiscordProbeRuntime()).probeDiscord(params.token, 2500, { includeApplication: true });
			if (params.abortSignal.aborted) return;
			params.setStatus({
				accountId: params.accountId,
				bot: probe.bot,
				application: probe.application
			});
			if (probe.ok) {
				const username = probe.bot?.username?.trim();
				if (username) params.log?.info?.(`[${params.accountId}] Discord bot probe resolved @${username}`);
			} else if (getDiscordRuntime().logging.shouldLogVerbose()) params.log?.debug?.(`[${params.accountId}] bot probe degraded: ${probe.error ?? `status ${probe.status ?? "unknown"}`}`);
			const messageContent = probe.application?.intents?.messageContent;
			if (messageContent === "disabled") params.log?.warn?.(`[${params.accountId}] Discord Message Content Intent is disabled; bot may not respond to channel messages. Enable it in Discord Dev Portal (Bot → Privileged Gateway Intents) or require mentions.`);
			else if (messageContent === "limited") params.log?.info?.(`[${params.accountId}] Discord Message Content Intent is limited; bots under 100 servers can use it without verification.`);
		} catch (err) {
			if (!params.abortSignal.aborted) params.setStatus({
				accountId: params.accountId,
				bot: void 0,
				application: void 0
			});
			if (getDiscordRuntime().logging.shouldLogVerbose()) params.log?.debug?.(`[${params.accountId}] bot probe failed: ${String(err)}`);
		}
	})();
}
function shouldTreatDiscordDeliveredTextAsVisible(params) {
	return params.kind === "block" && typeof params.text === "string" && params.text.trim().length > 0;
}
function resolveRuntimeDiscordMessageActions() {
	try {
		return getDiscordRuntime().channel?.discord?.messageActions ?? null;
	} catch {
		return null;
	}
}
const discordMessageActions = {
	resolveExecutionMode: (ctx) => resolveRuntimeDiscordMessageActions()?.resolveExecutionMode?.(ctx) ?? discordMessageActions$1.resolveExecutionMode?.(ctx) ?? "local",
	describeMessageTool: (ctx) => resolveRuntimeDiscordMessageActions()?.describeMessageTool?.(ctx) ?? discordMessageActions$1.describeMessageTool?.(ctx) ?? null,
	extractToolSend: (ctx) => resolveRuntimeDiscordMessageActions()?.extractToolSend?.(ctx) ?? discordMessageActions$1.extractToolSend?.(ctx) ?? null,
	prepareSendPayload: (ctx) => resolveRuntimeDiscordMessageActions()?.prepareSendPayload?.(ctx) ?? discordMessageActions$1.prepareSendPayload?.(ctx) ?? null,
	handleAction: async (ctx) => {
		const runtimeHandleAction = resolveRuntimeDiscordMessageActions()?.handleAction;
		if (runtimeHandleAction) return await runtimeHandleAction(ctx);
		if (!discordMessageActions$1.handleAction) throw new Error("Discord message actions not available");
		return await discordMessageActions$1.handleAction(ctx);
	}
};
function resolveDiscordStartupAccountIds(cfg) {
	const startupAccountIds = listEnabledDiscordAccounts(cfg).filter((candidate) => resolveConfiguredFromCredentialStatuses(candidate) ?? Boolean(normalizeOptionalString(candidate.token))).map((candidate) => candidate.accountId);
	const defaultAccountId = resolveDefaultDiscordAccountId(cfg);
	if (!startupAccountIds.includes(defaultAccountId)) return startupAccountIds;
	return [defaultAccountId, ...startupAccountIds.filter((candidateId) => candidateId !== defaultAccountId)];
}
function resolveDiscordStartupDelayMs(cfg, accountId) {
	const startupIndex = resolveDiscordStartupAccountIds(cfg).findIndex((candidateId) => candidateId === accountId);
	return startupIndex <= 0 ? 0 : startupIndex * DISCORD_ACCOUNT_STARTUP_STAGGER_MS;
}
function formatDiscordIntents(intents) {
	if (!intents) return "unknown";
	return [
		`messageContent=${intents.messageContent ?? "unknown"}`,
		`guildMembers=${intents.guildMembers ?? "unknown"}`,
		`presence=${intents.presence ?? "unknown"}`
	].join(" ");
}
const resolveDiscordAllowlistGroupOverrides = createNestedAllowlistOverrideResolver({
	resolveRecord: (account) => account.config.guilds,
	outerLabel: (guildKey) => `guild ${guildKey}`,
	resolveOuterEntries: (guildCfg) => guildCfg?.users,
	resolveChildren: (guildCfg) => guildCfg?.channels,
	innerLabel: (guildKey, channelKey) => `guild ${guildKey} / channel ${channelKey}`,
	resolveInnerEntries: (channelCfg) => channelCfg?.users
});
const resolveDiscordAllowlistNames = createAccountScopedAllowlistNameResolver({
	resolveAccount: resolveDiscordAccount,
	resolveToken: (account) => account.token,
	resolveNames: async ({ token, entries }) => (await loadDiscordResolveUsersModule()).resolveDiscordUserAllowlist({
		token,
		entries
	})
});
function toConversationLifecycleBinding(binding) {
	return {
		boundAt: binding.boundAt,
		lastActivityAt: typeof binding.lastActivityAt === "number" ? binding.lastActivityAt : binding.boundAt,
		idleTimeoutMs: typeof binding.idleTimeoutMs === "number" ? binding.idleTimeoutMs : void 0,
		maxAgeMs: typeof binding.maxAgeMs === "number" ? binding.maxAgeMs : void 0
	};
}
const discordPlugin = createChatChannelPlugin({
	base: {
		...createDiscordPluginBase({ setup: discordSetupAdapter }),
		allowlist: {
			...buildLegacyDmAccountAllowlistAdapter({
				channelId: "discord",
				resolveAccount: resolveDiscordAccount,
				normalize: ({ cfg, accountId, values }) => discordConfigAdapter.formatAllowFrom({
					cfg,
					accountId,
					allowFrom: values
				}),
				resolveDmAllowFrom: (account, { cfg }) => resolveDiscordAccountAllowFrom({
					cfg,
					accountId: account.accountId
				}),
				resolveGroupPolicy: (account) => account.config.groupPolicy,
				resolveGroupOverrides: resolveDiscordAllowlistGroupOverrides
			}),
			resolveNames: resolveDiscordAllowlistNames
		},
		groups: {
			resolveRequireMention: resolveDiscordGroupRequireMention,
			resolveToolPolicy: resolveDiscordGroupToolPolicy
		},
		mentions: { stripPatterns: () => ["<@!?\\d+>"] },
		agentPrompt: { messageToolHints: () => [
			"- Discord mentions: use canonical outbound syntax: users `<@USER_ID>`, channels `<#CHANNEL_ID>`, and roles `<@&ROLE_ID>`. Plain `@name` text only pings when a configured `mentionAliases` entry rewrites it; do not use the legacy `<@!USER_ID>` nickname form.",
			"- Discord components: set `components` when sending messages to include buttons, selects, or v2 containers.",
			"- Forms: add `components.modal` (title, fields). OpenClaw adds a trigger button and routes submissions as new messages."
		] },
		messaging: {
			targetPrefixes: ["discord"],
			directTargetStyle: "user-prefixed",
			targetIdComparison: "lowercase",
			normalizeTarget: normalizeDiscordMessagingTarget,
			resolveInboundConversation: ({ from, to, conversationId, threadId, threadParentId, isGroup }) => resolveDiscordInboundConversation({
				from,
				to,
				conversationId,
				threadId,
				threadParentId,
				isGroup
			}),
			normalizeExplicitSessionKey: ({ sessionKey, ctx }) => normalizeExplicitDiscordSessionKey(sessionKey, ctx),
			resolveSessionTarget: ({ id }) => normalizeDiscordMessagingTarget(`channel:${id}`),
			inferTargetChatType: ({ to }) => {
				try {
					const parsed = parseDiscordTarget(to, { defaultKind: "channel" });
					if (!parsed) return;
					return parsed?.kind === "user" ? "direct" : "channel";
				} catch {
					return;
				}
			},
			buildCrossContextPresentation: buildDiscordCrossContextPresentation,
			resolveOutboundSessionRoute: (params) => resolveDiscordOutboundSessionRoute(params),
			targetResolver: {
				looksLikeId: looksLikeDiscordTargetId,
				hint: "<channelId|user:ID|channel:ID>",
				resolveTarget: async ({ cfg, accountId, input, normalized, preferredKind }) => {
					const defaultKind = preferredKind === "user" || normalized.startsWith("user:") ? "user" : preferredKind === "channel" || preferredKind === "group" || normalized.startsWith("channel:") ? "channel" : void 0;
					const resolved = await (await loadDiscordTargetResolverModule()).resolveDiscordTarget(input, {
						cfg,
						accountId
					}, defaultKind ? { defaultKind } : {});
					if (!resolved) return null;
					if (!looksLikeDiscordTargetId(resolved.normalized)) return null;
					if (!looksLikeDiscordTargetId(input) && defaultKind === "channel" && resolved.kind === "user") return null;
					return {
						to: resolved.normalized,
						kind: resolved.kind === "user" ? "user" : "channel",
						display: resolved.raw,
						source: resolved.normalized === normalized ? "normalized" : "directory"
					};
				}
			}
		},
		approvalCapability: getDiscordApprovalCapability(),
		directory: createChannelDirectoryAdapter({
			listPeers: async (params) => (await loadDiscordDirectoryConfigModule()).listDiscordDirectoryPeersFromConfig(params),
			listGroups: async (params) => (await loadDiscordDirectoryConfigModule()).listDiscordDirectoryGroupsFromConfig(params),
			...createRuntimeDirectoryLiveAdapter({
				getRuntime: loadDiscordDirectoryLiveModule,
				listPeersLive: (runtime) => runtime.listDiscordDirectoryPeersLive,
				listGroupsLive: (runtime) => runtime.listDiscordDirectoryGroupsLive
			})
		}),
		message: discordMessageAdapter,
		resolver: { resolveTargets: async ({ cfg, accountId, inputs, kind }) => {
			const account = resolveDiscordAccount({
				cfg,
				accountId
			});
			if (kind === "group") return resolveTargetsWithOptionalToken({
				token: account.token,
				inputs,
				missingTokenNote: "missing Discord token",
				resolveWithToken: async ({ token, inputs: inputsValue }) => (await loadDiscordResolveChannelsModule()).resolveDiscordChannelAllowlist({
					token,
					entries: inputsValue
				}),
				mapResolved: (entry) => ({
					input: entry.input,
					resolved: entry.resolved,
					id: entry.channelId ?? entry.guildId,
					name: entry.channelName ?? entry.guildName ?? (entry.guildId && !entry.channelId ? entry.guildId : void 0),
					note: entry.note
				})
			});
			return resolveTargetsWithOptionalToken({
				token: account.token,
				inputs,
				missingTokenNote: "missing Discord token",
				resolveWithToken: async ({ token, inputs: inputsLocal }) => (await loadDiscordResolveUsersModule()).resolveDiscordUserAllowlist({
					token,
					entries: inputsLocal
				}),
				mapResolved: (entry) => ({
					input: entry.input,
					resolved: entry.resolved,
					id: entry.id,
					name: entry.name,
					note: entry.note
				})
			});
		} },
		actions: discordMessageActions,
		bindings: {
			compileConfiguredBinding: ({ conversationId }) => normalizeDiscordAcpConversationId(conversationId),
			matchInboundConversation: ({ compiledBinding, conversationId, parentConversationId }) => matchDiscordAcpConversation({
				bindingConversationId: compiledBinding.conversationId,
				conversationId,
				parentConversationId
			}),
			resolveCommandConversation: ({ threadId, threadParentId, parentSessionKey, from, chatType, originatingTo, commandTo, fallbackTo }) => resolveDiscordCommandConversation({
				threadId,
				threadParentId,
				parentSessionKey,
				from,
				chatType,
				originatingTo,
				commandTo,
				fallbackTo
			})
		},
		conversationBindings: {
			supportsCurrentConversationBinding: true,
			defaultTopLevelPlacement,
			createManager: async ({ cfg, accountId }) => (await loadDiscordThreadBindingsManagerModule()).createThreadBindingManager({
				cfg,
				accountId: accountId ?? void 0,
				persist: false,
				enableSweeper: false
			}),
			setIdleTimeoutBySessionKey: ({ targetSessionKey, accountId, idleTimeoutMs }) => setThreadBindingIdleTimeoutBySessionKey({
				targetSessionKey,
				accountId: accountId ?? void 0,
				idleTimeoutMs
			}).map(toConversationLifecycleBinding),
			setMaxAgeBySessionKey: ({ targetSessionKey, accountId, maxAgeMs }) => setThreadBindingMaxAgeBySessionKey({
				targetSessionKey,
				accountId: accountId ?? void 0,
				maxAgeMs
			}).map(toConversationLifecycleBinding)
		},
		heartbeat: { sendTyping: async ({ cfg, to, accountId, threadId }) => {
			const target = parseDiscordTarget(resolveDiscordAttachedOutboundTarget({
				to,
				threadId
			}), { defaultKind: "channel" });
			if (!target || target.kind !== "channel") return;
			await (await loadDiscordSendModule()).sendTypingDiscord(target.id, {
				cfg,
				accountId: accountId ?? void 0
			});
		} },
		status: createComputedAccountStatusAdapter({
			defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID, {
				connected: false,
				reconnectAttempts: 0,
				lastConnectedAt: null,
				lastDisconnect: null,
				lastEventAt: null
			}),
			collectStatusIssues: collectDiscordStatusIssues,
			buildChannelSummary: ({ snapshot }) => buildTokenChannelStatusSummary(snapshot, { includeMode: false }),
			probeAccount: async ({ account, timeoutMs }) => await probeDiscordStatusAccount({
				token: account.token,
				timeoutMs
			}),
			formatCapabilitiesProbe: ({ probe }) => {
				const discordProbe = probe;
				const lines = [];
				if (discordProbe?.bot?.username) {
					const botId = discordProbe.bot.id ? ` (${discordProbe.bot.id})` : "";
					lines.push({ text: `Bot: @${discordProbe.bot.username}${botId}` });
				}
				if (discordProbe?.application?.intents) lines.push({ text: `Intents: ${formatDiscordIntents(discordProbe.application.intents)}` });
				return lines;
			},
			buildCapabilitiesDiagnostics: async ({ account, target, timeoutMs }) => {
				if (!target?.trim()) return;
				const parsedTarget = parseDiscordTarget(target.trim(), { defaultKind: "channel" });
				const details = { target: {
					raw: target,
					normalized: parsedTarget?.normalized,
					kind: parsedTarget?.kind,
					channelId: parsedTarget?.kind === "channel" ? parsedTarget.id : void 0
				} };
				if (!parsedTarget || parsedTarget.kind !== "channel") return {
					details,
					lines: [{
						text: "Permissions: Target looks like a DM user; pass channel:<id> to audit channel permissions.",
						tone: "error"
					}]
				};
				const token = account.token?.trim();
				if (!token) return {
					details,
					lines: [{
						text: "Permissions: Discord bot token missing for permission audit.",
						tone: "error"
					}]
				};
				const statusCfg = { channels: { discord: { accounts: { [account.accountId]: {
					...account.config,
					token
				} } } } };
				try {
					const sendModule = await loadDiscordSendModule();
					const perms = await withAbortTimeout({
						timeoutMs,
						createTimeoutError: () => /* @__PURE__ */ new Error(`Capabilities diagnostic timed out after ${timeoutMs}ms`),
						run: async (signal) => await sendModule.fetchChannelPermissionsDiscord(parsedTarget.id, {
							cfg: statusCfg,
							token,
							accountId: account.accountId ?? void 0,
							signal,
							timeoutMs
						})
					});
					const missingRequired = resolveRequiredDiscordChannelPermissions(perms.channelType).filter((permission) => !perms.permissions.includes(permission));
					details.permissions = {
						channelId: perms.channelId,
						guildId: perms.guildId,
						isDm: perms.isDm,
						channelType: perms.channelType,
						permissions: perms.permissions,
						missingRequired,
						raw: perms.raw
					};
					return {
						details,
						lines: [{ text: `Permissions (${perms.channelId}): ${perms.permissions.length ? perms.permissions.join(", ") : "none"}` }, missingRequired.length > 0 ? {
							text: `Missing required: ${missingRequired.join(", ")}`,
							tone: "warn"
						} : {
							text: "Missing required: none",
							tone: "success"
						}]
					};
				} catch (err) {
					const message = formatErrorMessage(err);
					details.permissions = {
						channelId: parsedTarget.id,
						error: message
					};
					return {
						details,
						lines: [{
							text: `Permissions: ${message}`,
							tone: "error"
						}]
					};
				}
			},
			auditAccount: async ({ account, timeoutMs, cfg }) => {
				const { auditDiscordChannelPermissions, collectDiscordAuditChannelIds } = await loadDiscordAuditModule();
				const { channelIds, unresolvedChannels } = collectDiscordAuditChannelIds({
					cfg,
					accountId: account.accountId
				});
				if (!channelIds.length && unresolvedChannels === 0) return;
				const botToken = account.token?.trim();
				if (!botToken) return {
					ok: unresolvedChannels === 0,
					checkedChannels: 0,
					unresolvedChannels,
					channels: [],
					elapsedMs: 0
				};
				return {
					...await auditDiscordChannelPermissions({
						cfg,
						token: botToken,
						accountId: account.accountId,
						channelIds,
						timeoutMs
					}),
					unresolvedChannels
				};
			},
			resolveAccountSnapshot: ({ account, runtime, probe, audit }) => {
				const configured = resolveConfiguredFromCredentialStatuses(account) ?? Boolean(account.token?.trim());
				const app = runtime?.application ?? probe?.application;
				const bot = runtime?.bot ?? probe?.bot;
				return {
					accountId: account.accountId,
					name: account.name,
					enabled: account.enabled,
					configured,
					extra: {
						...projectCredentialSnapshotFields(account),
						connected: runtime?.connected ?? false,
						reconnectAttempts: runtime?.reconnectAttempts,
						lastConnectedAt: runtime?.lastConnectedAt ?? null,
						lastDisconnect: runtime?.lastDisconnect ?? null,
						lastEventAt: runtime?.lastEventAt ?? null,
						application: app ?? void 0,
						bot: bot ?? void 0,
						audit
					}
				};
			}
		}),
		gateway: { startAccount: async (ctx) => {
			const account = ctx.account;
			if (account.tokenStatus === "configured_unavailable") throw new Error(`Discord bot token configured for account "${account.accountId}" is unavailable; resolve SecretRefs against the active runtime snapshot before using this account.`);
			const startupDelayMs = resolveDiscordStartupDelayMs(ctx.cfg, account.accountId);
			if (startupDelayMs > 0) {
				ctx.log?.info(`[${account.accountId}] delaying provider startup ${Math.round(startupDelayMs / 1e3)}s to reduce Discord startup rate limits`);
				try {
					await sleepWithAbort(startupDelayMs, ctx.abortSignal);
				} catch {
					return;
				}
			}
			const token = account.token.trim();
			startDiscordStartupProbe({
				accountId: account.accountId,
				token,
				abortSignal: ctx.abortSignal,
				setStatus: ctx.setStatus,
				log: ctx.log
			});
			ctx.log?.info(`[${account.accountId}] starting provider`);
			let commandDeployHashStore;
			try {
				commandDeployHashStore = openDiscordCommandDeployHashStore(getDiscordRuntime().state.openKeyedStore);
			} catch (error) {
				ctx.log?.warn?.(`[${account.accountId}] Discord command deploy cache unavailable; continuing without persistence: ${formatErrorMessage(error)}`);
			}
			return (await loadDiscordProviderRuntime()).monitorDiscordProvider({
				token,
				accountId: account.accountId,
				config: ctx.cfg,
				runtime: ctx.runtime,
				channelRuntime: ctx.channelRuntime,
				abortSignal: ctx.abortSignal,
				mediaMaxMb: account.config.mediaMaxMb,
				historyLimit: account.config.historyLimit,
				setStatus: (patch) => ctx.setStatus({
					accountId: account.accountId,
					...patch
				}),
				commandDeployHashStore
			});
		} }
	},
	pairing: { text: {
		idLabel: "discordUserId",
		message: PAIRING_APPROVED_MESSAGE,
		normalizeAllowEntry: createPairingPrefixStripper(/^(discord|user):/i),
		notify: async ({ cfg, id, message, accountId }) => {
			await (await loadDiscordSendModule()).sendMessageDiscord(`user:${id}`, message, {
				cfg,
				...accountId ? { accountId } : {}
			});
		}
	} },
	security: discordSecurityAdapter,
	threading: {
		scopedAccountReplyToMode: {
			resolveAccount: (cfg, accountId) => resolveDiscordAccount({
				cfg,
				accountId
			}),
			resolveReplyToMode: (account) => account.config.replyToMode,
			fallback: "off"
		},
		buildToolContext: ({ context, hasRepliedRef }) => {
			const currentMessagingTarget = normalizeOptionalString(context.To);
			const currentChatType = context.ChatType === "direct" || context.ChatType === "group" || context.ChatType === "channel" ? context.ChatType : void 0;
			return {
				currentChannelId: normalizeOptionalString(context.NativeChannelId) ?? currentMessagingTarget,
				currentChatType,
				currentMessagingTarget,
				currentMessageId: context.CurrentMessageId,
				hasRepliedRef
			};
		}
	},
	outbound: {
		...discordOutbound,
		preferFinalAssistantVisibleText: true,
		shouldTreatDeliveredTextAsVisible: shouldTreatDiscordDeliveredTextAsVisible,
		shouldSuppressLocalPayloadPrompt: ({ cfg, accountId, payload, hint }) => shouldSuppressLocalDiscordExecApprovalPrompt({
			cfg,
			accountId,
			payload,
			hint
		})
	}
});
//#endregion
export { resolveDiscordGroupToolPolicy as i, collectDiscordStatusIssues as n, resolveDiscordGroupRequireMention as r, discordPlugin as t };
