import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { c as isRecord } from "./record-coerce-DItp3I4t.js";
import { u as normalizeStringEntries } from "./string-normalization-e_fvmxMf.js";
import { s as statRegularFileSync } from "./regular-file-Dwz6p59y.js";
import { o as getReplyPayloadTtsSupplement } from "./reply-payload-DdgNSoVn.js";
import "./channel-outbound-u6Z36jMs.js";
import { t as createMessageReceiptFromOutboundResults } from "./receipt-CLIbZ0pA.js";
import { x as resolveLegacyInteractiveTextFallback } from "./payload-C7E4iMOo.js";
import { S as createReplyToFanout, d as resolvePayloadMediaUrls, h as sendPayloadMediaSequenceAndFinalize, y as sendTextMediaPayload } from "./reply-payload-w2719fAs.js";
import { c as resolveTextChunkLimit, s as resolveChunkMode } from "./chunk-X-54kK9K.js";
import "./string-coerce-runtime-C8jKEm3h.js";
import { t as convertMarkdownTables } from "./tables-BHWmSjiH.js";
import { i as isChannelPartialDeliveryError } from "./delivery-result-CWGwB9sQ.js";
import { t as resolveMarkdownTableMode } from "./markdown-tables-uWN3O1dZ.js";
import "./reply-chunking-C9M0265M.js";
import "./channel-inbound-CxNf-7n7.js";
import "./text-chunking-6CyoCsRp.js";
import "./security-runtime--v54nkpJ.js";
import "./markdown-table-runtime-BuXYnIO5.js";
import { i as createAttachedChannelResultAdapter, t as attachChannelToResult } from "./channel-send-result-BFAnsv6z.js";
import { c as listDirectoryUserEntriesFromAllowFrom, l as listDirectoryUserEntriesFromAllowFromAndMapKeys, s as listDirectoryGroupEntriesFromMapKeysAndAllowFrom, t as applyDirectoryQueryAndLimit } from "./directory-config-helpers-CWfb67CM.js";
import "./directory-runtime-CkX42l9E.js";
import { s as resolveFeishuAccount } from "./accounts-DpChUvpS.js";
import { r as normalizeFeishuTarget } from "./targets-CGcN9qP-.js";
import { $ as sanitizeNativeFeishuCard, A as buildFeishuMediaFallbackText, M as resolveFeishuIdentityHeaderTitle, N as deliverCommentThreadText, Q as resolveFeishuCardTemplate, S as sendStructuredCardFeishu, V as cleanupAmbientCommentTypingReaction, X as parseFeishuCommentTarget, Z as readNativeFeishuCardJson, a as assertFeishuCardWithinEnvelope, b as sendCardFeishu, c as buildFeishuPresentationFallback, ct as isFeishuGroupReadAllowed, d as resolveFeishuRichReply, et as chunkFeishuMarkdown, g as chunkFeishuCardMarkdown, h as shouldSuppressFeishuTextForVoiceMedia, l as isFeishuCardWithinEnvelope, n as createFeishuReplyDeliveryResult, nt as materializeFeishuPostMarkdownSoftBreaks, p as sendMediaFeishu, s as buildFeishuPresentationCardElements, t as createFeishuPartialReplyDeliveryError, tt as chunkFeishuPostMarkdown, u as renderFeishuPresentationFallbackText, x as sendMessageFeishu } from "./reply-delivery-result-C9oZpxZb.js";
import { n as createFeishuClient } from "./client-Cd7pyJe-.js";
import path from "node:path";
//#region extensions/feishu/src/directory.static.ts
function toFeishuDirectoryPeers(ids) {
	return ids.map((id) => ({
		kind: "user",
		id
	}));
}
function toFeishuDirectoryGroups(ids) {
	return ids.map((id) => ({
		kind: "group",
		id
	}));
}
async function listFeishuDirectoryPeers(params) {
	const account = resolveFeishuAccount({
		cfg: params.cfg,
		accountId: params.accountId
	});
	return toFeishuDirectoryPeers(listDirectoryUserEntriesFromAllowFromAndMapKeys({
		allowFrom: account.config.allowFrom,
		map: account.config.dms,
		query: params.query,
		limit: params.limit,
		normalizeAllowFromId: (entry) => normalizeFeishuTarget(entry) ?? entry,
		normalizeMapKeyId: (entry) => normalizeFeishuTarget(entry) ?? entry
	}).map((entry) => entry.id));
}
async function listFeishuDirectoryGroups(params) {
	const account = resolveFeishuAccount({
		cfg: params.cfg,
		accountId: params.accountId
	});
	return toFeishuDirectoryGroups(listDirectoryGroupEntriesFromMapKeysAndAllowFrom({
		groups: account.config.groups,
		allowFrom: account.config.groupAllowFrom,
		query: params.query,
		limit: params.limit
	}).map((entry) => entry.id));
}
async function listAuthorizedFeishuDirectoryPeers(params) {
	return toFeishuDirectoryPeers(listDirectoryUserEntriesFromAllowFrom({
		allowFrom: resolveFeishuAccount({
			cfg: params.cfg,
			accountId: params.accountId
		}).config.allowFrom,
		query: params.query,
		limit: params.limit,
		normalizeId: (entry) => normalizeFeishuTarget(entry) ?? entry
	}).map((entry) => entry.id));
}
async function listAuthorizedFeishuDirectoryGroups(params) {
	const account = resolveFeishuAccount({
		cfg: params.cfg,
		accountId: params.accountId
	});
	return toFeishuDirectoryGroups(applyDirectoryQueryAndLimit(listDirectoryGroupEntriesFromMapKeysAndAllowFrom({
		groups: Object.fromEntries(Object.entries(account.config.groups ?? {}).filter(([, group]) => group?.enabled !== false)),
		allowFrom: account.config.groupAllowFrom
	}).filter((entry) => isFeishuGroupReadAllowed(params.cfg, account, entry.id, false)).map((entry) => entry.id), params));
}
//#endregion
//#region extensions/feishu/src/outbound.ts
const RENDERED_FEISHU_CARD = Symbol("openclaw.renderedFeishuCard");
const FEISHU_PRESENTATION_FALLBACK_MARKER = "__openclawPresentationFallback";
const FEISHU_PROPAGATE_MEDIA_UPLOAD_FAILURE_MARKER = "__openclawPropagateMediaUploadFailure";
const FEISHU_TEXT_CHUNK_LIMIT = 4e3;
function normalizePossibleLocalImagePath(text) {
	const raw = text?.trim();
	if (!raw) return null;
	if (/\s/.test(raw)) return null;
	if (/^(https?:\/\/|data:|file:\/\/)/i.test(raw)) return null;
	const ext = normalizeLowercaseStringOrEmpty(path.extname(raw));
	if (![
		".jpg",
		".jpeg",
		".png",
		".gif",
		".webp",
		".bmp",
		".ico",
		".heic",
		".tif",
		".tiff"
	].includes(ext)) return null;
	if (!path.isAbsolute(raw)) return null;
	try {
		if (statRegularFileSync(raw).missing) return null;
	} catch {
		return null;
	}
	return raw;
}
function shouldUseCard(text) {
	return /```[\s\S]*?```/.test(text) || /\|.+\|[\r\n]+\|[-:| ]+\|/.test(text);
}
function markRenderedFeishuCard(card) {
	Object.defineProperty(card, RENDERED_FEISHU_CARD, {
		value: true,
		enumerable: false
	});
	return card;
}
function readNativeFeishuCard(payload) {
	const feishuData = payload.channelData?.feishu;
	if (!isRecord(feishuData)) return;
	const card = feishuData.card ?? feishuData.interactiveCard;
	if (!isRecord(card)) return;
	if (card[RENDERED_FEISHU_CARD] === true) return card;
	const sanitizedCard = sanitizeNativeFeishuCard(card);
	return sanitizedCard ? markRenderedFeishuCard(sanitizedCard) : void 0;
}
function toFeishuOutboundResult(result) {
	const { chatId, ...delivery } = result;
	return {
		...delivery,
		target: {
			kind: "chat",
			id: chatId
		}
	};
}
async function reportFeishuOutboundDelivery(result, onDeliveryResult) {
	await onDeliveryResult?.(attachChannelToResult("feishu", toFeishuOutboundResult(result)));
	return result;
}
function aggregateFeishuSendResult(result, results) {
	return {
		...result,
		receipt: {
			...createMessageReceiptFromOutboundResults({ results }),
			primaryPlatformMessageId: result.messageId
		}
	};
}
function partialFeishuSendError(error, results) {
	if (results.length === 0 && error instanceof Error) return error;
	const accepted = isChannelPartialDeliveryError(error) ? error.deliveryResult : void 0;
	return createFeishuPartialReplyDeliveryError(error, {
		...accepted,
		...createFeishuReplyDeliveryResult({
			results: [...results, accepted],
			visibleReplySent: results.length > 0 || accepted !== void 0
		})
	});
}
function consumeFeishuPresentationFallbackMarker(payload) {
	const feishuData = isRecord(payload.channelData?.feishu) ? payload.channelData.feishu : void 0;
	const presentationFallback = feishuData?.[FEISHU_PRESENTATION_FALLBACK_MARKER];
	if (!isRecord(presentationFallback) || typeof presentationFallback.hasVisibleContent !== "boolean") return { payload };
	const nextFeishuData = { ...feishuData };
	delete nextFeishuData[FEISHU_PRESENTATION_FALLBACK_MARKER];
	const nextChannelData = { ...payload.channelData };
	if (Object.keys(nextFeishuData).length > 0) nextChannelData.feishu = nextFeishuData;
	else delete nextChannelData.feishu;
	return {
		payload: {
			...payload,
			channelData: Object.keys(nextChannelData).length > 0 ? nextChannelData : void 0
		},
		presentationFallback: { hasVisibleContent: presentationFallback.hasVisibleContent }
	};
}
function readFeishuPropagateMediaUploadFailure(payload) {
	return (isRecord(payload.channelData?.feishu) ? payload.channelData.feishu : void 0)?.[FEISHU_PROPAGATE_MEDIA_UPLOAD_FAILURE_MARKER] === true;
}
function buildFeishuPropagationOnlyChannelData(payload) {
	if ((isRecord(payload.channelData?.feishu) ? payload.channelData.feishu : void 0)?.["__openclawPropagateMediaUploadFailure"] !== true) return;
	return { feishu: { [FEISHU_PROPAGATE_MEDIA_UPLOAD_FAILURE_MARKER]: true } };
}
function buildFeishuPayloadCard(params) {
	const nativeCard = readNativeFeishuCard(params.payload);
	if (nativeCard) {
		assertFeishuCardWithinEnvelope(nativeCard, "Feishu native card");
		return nativeCard;
	}
	const rawText = params.text ?? params.payload.text;
	const textCard = readNativeFeishuCardJson(rawText);
	const { interactive, presentation } = resolveFeishuRichReply(params.payload);
	if (!presentation) {
		if (!textCard) return;
		assertFeishuCardWithinEnvelope(textCard, "Feishu native card");
		return markRenderedFeishuCard(textCard);
	}
	const elements = buildFeishuPresentationCardElements({
		presentation,
		fallbackText: textCard ? void 0 : resolveLegacyInteractiveTextFallback({
			text: rawText,
			interactive
		})
	});
	const identityTitle = resolveFeishuIdentityHeaderTitle(params.identity);
	const title = presentation?.title ?? identityTitle;
	const template = resolveFeishuCardTemplate(presentation?.tone === "danger" ? "red" : presentation?.tone === "warning" ? "orange" : presentation?.tone === "success" ? "green" : "blue");
	const card = markRenderedFeishuCard({
		schema: "2.0",
		config: { width_mode: "fill" },
		...title ? { header: {
			title: {
				tag: "plain_text",
				content: title
			},
			template: template ?? "blue"
		} } : {},
		body: { elements }
	});
	return isFeishuCardWithinEnvelope(card) ? card : void 0;
}
function renderFeishuPresentationPayload({ payload, presentation, ctx }) {
	const { fallbackText, fallbackHasCommand } = buildFeishuPresentationFallback({
		text: readNativeFeishuCardJson(payload.text) ? void 0 : payload.text,
		presentation,
		textFormat: parseFeishuCommentTarget(ctx.to) ? "plain" : "markdown"
	});
	const card = buildFeishuPayloadCard({
		payload,
		text: payload.text,
		identity: ctx.identity
	});
	const existingFeishuData = isRecord(payload.channelData?.feishu) ? payload.channelData.feishu : void 0;
	if (!card) return {
		...payload,
		text: fallbackText,
		channelData: {
			...payload.channelData,
			feishu: {
				...existingFeishuData,
				[FEISHU_PRESENTATION_FALLBACK_MARKER]: { hasVisibleContent: Boolean(renderFeishuPresentationFallbackText({ presentation }).trim()) },
				...fallbackHasCommand ? { fallbackHasCommand: true } : {}
			}
		}
	};
	return {
		...payload,
		text: fallbackText,
		channelData: {
			...payload.channelData,
			feishu: {
				...existingFeishuData,
				card,
				...fallbackHasCommand ? { fallbackHasCommand: true } : {}
			}
		}
	};
}
function resolveFeishuReplyMode(params) {
	const replyToMessageId = params.replyToId?.trim();
	if (replyToMessageId) return {
		normalizedReplyToId: replyToMessageId,
		replyToMessageId,
		replyInThread: false
	};
	const threadId = params.threadId == null ? void 0 : String(params.threadId).trim();
	return threadId ? {
		normalizedReplyToId: void 0,
		replyToMessageId: threadId,
		replyInThread: true
	} : {
		normalizedReplyToId: void 0,
		replyToMessageId: void 0,
		replyInThread: false
	};
}
async function sendCommentThreadReply(params) {
	const target = parseFeishuCommentTarget(params.to);
	if (!target) return null;
	const client = createFeishuClient(resolveFeishuAccount({
		cfg: params.cfg,
		accountId: params.accountId
	}));
	const replyId = params.replyId?.trim();
	try {
		const result = await deliverCommentThreadText(client, {
			file_token: target.fileToken,
			file_type: target.fileType,
			comment_id: target.commentId,
			content: params.text
		});
		return {
			messageId: (result.delivery_mode === "reply_comment" ? result.reply_id : result.comment_id) ?? "",
			chatId: target.commentId,
			result
		};
	} finally {
		if (replyId) cleanupAmbientCommentTypingReaction({
			client,
			deliveryContext: {
				channel: "feishu",
				to: params.to,
				threadId: replyId
			}
		});
	}
}
async function sendOutboundText(params) {
	const { cfg, to, text, accountId, replyToMessageId, replyInThread, onDeliveryResult } = params;
	const commentResult = await sendCommentThreadReply({
		cfg,
		to,
		text,
		replyId: replyToMessageId,
		accountId
	});
	if (commentResult) return await reportFeishuOutboundDelivery(commentResult, onDeliveryResult);
	const renderMode = resolveFeishuAccount({
		cfg,
		accountId
	}).config?.renderMode ?? "auto";
	const useCard = renderMode === "card" || renderMode === "auto" && shouldUseCard(text);
	const tableMode = resolveMarkdownTableMode({
		cfg,
		channel: "feishu"
	});
	const normalizedText = useCard ? text : materializeFeishuPostMarkdownSoftBreaks(convertMarkdownTables(text, tableMode));
	const chunkOptions = {
		text: normalizedText,
		limit: resolveTextChunkLimit(cfg, "feishu", accountId, { fallbackLimit: FEISHU_TEXT_CHUNK_LIMIT }),
		mode: resolveChunkMode(cfg, "feishu", accountId)
	};
	const subChunks = useCard ? chunkFeishuCardMarkdown({
		...chunkOptions,
		header: params.header
	}) : chunkFeishuPostMarkdown(chunkOptions);
	const results = [];
	const preserveThread = replyInThread === true;
	const nextReplyToMessageId = createReplyToFanout({
		replyToId: replyToMessageId,
		replyToIdSource: params.replyToIdSource,
		replyToMode: params.replyToMode ?? "first"
	});
	for (const [i, chunk] of (subChunks.length ? subChunks : [normalizedText]).entries()) try {
		const sendParams = {
			cfg,
			to,
			text: chunk,
			accountId,
			replyToMessageId: preserveThread ? replyToMessageId : nextReplyToMessageId(),
			replyInThread: preserveThread ? true : i === 0 ? replyInThread : void 0
		};
		const result = useCard ? await sendStructuredCardFeishu({
			...sendParams,
			header: params.header
		}) : await sendMessageFeishu({
			...sendParams,
			preparedPostText: true
		});
		results.push(result);
		await reportFeishuOutboundDelivery(result, onDeliveryResult);
	} catch (error) {
		throw partialFeishuSendError(error, results);
	}
	return aggregateFeishuSendResult(results.at(-1), results);
}
async function sendFeishuFallbackPayload(params) {
	const propagateMediaUploadFailure = readFeishuPropagateMediaUploadFailure(params.payload);
	const ctx = {
		...params.ctx,
		payload: params.payload
	};
	const mediaUrls = normalizeStringEntries(resolvePayloadMediaUrls(params.payload));
	const text = params.payload.text ?? "";
	const textChunks = text ? chunkFeishuMarkdown(text, FEISHU_TEXT_CHUNK_LIMIT) : [];
	if (!(mediaUrls.length > 0 && (propagateMediaUploadFailure || params.separateMediaAndText === true || textChunks.length > 1))) return await sendTextMediaPayload({
		channel: "feishu",
		ctx,
		adapter: feishuOutbound
	});
	const { normalizedReplyToId } = resolveFeishuReplyMode({
		replyToId: ctx.replyToId,
		threadId: ctx.threadId
	});
	const nextReplyToId = createReplyToFanout({
		replyToId: normalizedReplyToId,
		replyToIdSource: ctx.replyToIdSource,
		replyToMode: ctx.replyToMode
	});
	const sendMedia = feishuOutbound.sendMedia;
	const sendText = feishuOutbound.sendText;
	if (!sendMedia || !sendText) throw new Error("Feishu fallback delivery is not available.");
	let lastResult;
	for (const mediaUrl of mediaUrls) lastResult = await sendMedia({
		...ctx,
		text: "",
		mediaUrl,
		replyToId: nextReplyToId(),
		audioAsVoice: params.payload.audioAsVoice ?? ctx.audioAsVoice,
		...propagateMediaUploadFailure ? { propagateMediaUploadFailure: true } : {}
	});
	for (const chunk of textChunks) lastResult = await sendText({
		...ctx,
		text: chunk,
		replyToId: nextReplyToId()
	});
	return lastResult;
}
async function sendFeishuTtsSupplementPayload(params) {
	const sendMedia = feishuOutbound.sendMedia;
	const sendText = feishuOutbound.sendText;
	if (!sendMedia || !sendText) throw new Error("Feishu TTS supplement delivery is not available.");
	const { normalizedReplyToId } = resolveFeishuReplyMode({
		replyToId: params.ctx.replyToId,
		threadId: params.ctx.threadId
	});
	const nextReplyToId = createReplyToFanout({
		replyToId: normalizedReplyToId,
		replyToIdSource: params.ctx.replyToIdSource,
		replyToMode: params.ctx.replyToMode
	});
	const ctx = {
		...params.ctx,
		payload: params.payload
	};
	let lastResult;
	if (params.sendVisiblePayload) {
		lastResult = await params.sendVisiblePayload(nextReplyToId());
		await ctx.onDeliveryResult?.(lastResult);
	} else if (params.hasVisiblePresentationFallback || params.supplement.visibleTextAlreadyDelivered !== true) {
		const text = params.payload.text?.trim() ? params.payload.text : params.supplement.spokenText;
		for (const chunk of chunkFeishuMarkdown(text, FEISHU_TEXT_CHUNK_LIMIT)) lastResult = await sendText({
			...ctx,
			text: chunk,
			replyToId: nextReplyToId()
		});
	}
	for (const mediaUrl of normalizeStringEntries(resolvePayloadMediaUrls(params.payload))) lastResult = await sendMedia({
		...ctx,
		text: "",
		mediaUrl,
		replyToId: nextReplyToId(),
		audioAsVoice: params.payload.audioAsVoice ?? ctx.audioAsVoice
	});
	return lastResult ?? {
		channel: "feishu",
		messageId: ""
	};
}
const feishuOutbound = {
	deliveryMode: "direct",
	chunker: chunkFeishuMarkdown,
	chunkerMode: "markdown",
	textChunkLimit: FEISHU_TEXT_CHUNK_LIMIT,
	presentationCapabilities: {
		supported: true,
		buttons: true,
		selects: false,
		context: true,
		divider: true,
		limits: {
			actions: {
				maxActions: 20,
				maxActionsPerRow: 5,
				maxLabelLength: 40,
				maxValueBytes: 1024
			},
			text: {
				maxLength: FEISHU_TEXT_CHUNK_LIMIT,
				encoding: "characters",
				markdownDialect: "markdown"
			}
		}
	},
	renderPresentation: renderFeishuPresentationPayload,
	sendPayload: async (ctx) => {
		const { payload, presentationFallback } = consumeFeishuPresentationFallbackMarker(ctx.payload);
		const ttsSupplement = getReplyPayloadTtsSupplement(payload);
		if (parseFeishuCommentTarget(ctx.to)) {
			const { presentation } = resolveFeishuRichReply(payload);
			const textCard = readNativeFeishuCardJson(payload.text);
			const { commentText: text, fallbackText } = buildFeishuPresentationFallback({
				text: textCard ? void 0 : payload.text,
				presentation,
				fallbackHasCommand: isRecord(payload.channelData?.feishu) && payload.channelData.feishu.fallbackHasCommand === true
			});
			const hasFallbackMedia = normalizeStringEntries(resolvePayloadMediaUrls(payload)).length > 0;
			if (!fallbackText.trim() && !hasFallbackMedia && (textCard || readNativeFeishuCard(payload))) throw new Error("Feishu native cards cannot be sent to document comments without a text or media fallback.");
			return await sendFeishuFallbackPayload({
				ctx,
				payload: {
					...payload,
					text,
					interactive: void 0,
					presentation: void 0,
					channelData: buildFeishuPropagationOnlyChannelData(payload)
				},
				separateMediaAndText: true
			});
		}
		const card = buildFeishuPayloadCard({
			payload,
			text: ctx.text,
			identity: ctx.identity
		});
		if (!card) {
			const { presentation } = resolveFeishuRichReply(payload);
			const fallbackPayload = presentation ? {
				...payload,
				text: renderFeishuPresentationFallbackText({
					text: readNativeFeishuCardJson(payload.text) ? void 0 : payload.text,
					presentation
				}, "markdown"),
				presentation: void 0,
				interactive: void 0
			} : payload;
			if (ttsSupplement) return await sendFeishuTtsSupplementPayload({
				ctx,
				payload: fallbackPayload,
				supplement: ttsSupplement,
				hasVisiblePresentationFallback: presentationFallback?.hasVisibleContent ?? Boolean(renderFeishuPresentationFallbackText({ presentation }).trim())
			});
			return await sendFeishuFallbackPayload({
				ctx,
				payload: fallbackPayload,
				separateMediaAndText: presentationFallback !== void 0 || presentation !== void 0
			});
		}
		if (ttsSupplement) return await sendFeishuTtsSupplementPayload({
			ctx,
			payload,
			supplement: ttsSupplement,
			sendVisiblePayload: async (replyToId) => {
				const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
					replyToId,
					threadId: ctx.threadId
				});
				return attachChannelToResult("feishu", toFeishuOutboundResult(await sendCardFeishu({
					cfg: ctx.cfg,
					to: ctx.to,
					card,
					replyToMessageId,
					replyInThread,
					accountId: ctx.accountId ?? void 0
				})));
			}
		});
		const { normalizedReplyToId } = resolveFeishuReplyMode({
			replyToId: ctx.replyToId,
			threadId: ctx.threadId
		});
		const nextReplyToId = createReplyToFanout({
			replyToId: normalizedReplyToId,
			replyToIdSource: ctx.replyToIdSource,
			replyToMode: ctx.replyToMode
		});
		const nextReplyMode = () => resolveFeishuReplyMode({
			replyToId: nextReplyToId(),
			threadId: ctx.threadId
		});
		const mediaUrls = normalizeStringEntries(resolvePayloadMediaUrls(payload));
		return attachChannelToResult("feishu", toFeishuOutboundResult(await sendPayloadMediaSequenceAndFinalize({
			text: payload.text ?? "",
			mediaUrls,
			onResult: async (deliveryResult) => {
				await ctx.onDeliveryResult?.(attachChannelToResult("feishu", toFeishuOutboundResult(deliveryResult)));
			},
			send: async ({ mediaUrl }) => {
				const { replyToMessageId, replyInThread } = nextReplyMode();
				return await sendMediaFeishu({
					cfg: ctx.cfg,
					to: ctx.to,
					mediaUrl,
					accountId: ctx.accountId ?? void 0,
					mediaAccess: ctx.mediaAccess,
					mediaLocalRoots: ctx.mediaLocalRoots,
					mediaReadFile: ctx.mediaReadFile,
					replyToMessageId,
					replyInThread,
					...payload.audioAsVoice === true || ctx.audioAsVoice === true ? { audioAsVoice: true } : {}
				});
			},
			finalize: async () => {
				const { replyToMessageId, replyInThread } = nextReplyMode();
				return await sendCardFeishu({
					cfg: ctx.cfg,
					to: ctx.to,
					card,
					replyToMessageId,
					replyInThread,
					accountId: ctx.accountId ?? void 0
				});
			}
		})));
	},
	...createAttachedChannelResultAdapter({
		channel: "feishu",
		sendText: async ({ cfg, to, text, accountId, replyToId, replyToIdSource, replyToMode, threadId, mediaAccess, mediaLocalRoots, mediaReadFile, identity, onDeliveryResult }) => {
			const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
				replyToId,
				threadId
			});
			const deliveryOptions = {
				replyToIdSource,
				replyToMode,
				onDeliveryResult
			};
			const localImagePath = normalizePossibleLocalImagePath(text);
			if (localImagePath) {
				let mediaResult;
				try {
					mediaResult = await sendMediaFeishu({
						cfg,
						to,
						mediaUrl: localImagePath,
						accountId: accountId ?? void 0,
						replyToMessageId,
						replyInThread,
						mediaAccess,
						mediaLocalRoots,
						mediaReadFile
					});
				} catch (err) {
					if (isChannelPartialDeliveryError(err)) throw err;
					console.error(`[feishu] local image path auto-send failed:`, err);
					return toFeishuOutboundResult(await sendOutboundText({
						cfg,
						to,
						text: await buildFeishuMediaFallbackText({}),
						accountId: accountId ?? void 0,
						replyToMessageId,
						replyInThread,
						...deliveryOptions
					}));
				}
				return toFeishuOutboundResult(await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult));
			}
			if (parseFeishuCommentTarget(to)) return toFeishuOutboundResult(await sendOutboundText({
				cfg,
				to,
				text,
				accountId: accountId ?? void 0,
				replyToMessageId,
				replyInThread,
				...deliveryOptions
			}));
			const card = readNativeFeishuCardJson(text);
			if (card) {
				assertFeishuCardWithinEnvelope(card, "Feishu native card");
				return toFeishuOutboundResult(await reportFeishuOutboundDelivery(await sendCardFeishu({
					cfg,
					to,
					card: markRenderedFeishuCard(card),
					accountId: accountId ?? void 0,
					replyToMessageId,
					replyInThread
				}), onDeliveryResult));
			}
			const title = identity ? resolveFeishuIdentityHeaderTitle(identity) : void 0;
			return toFeishuOutboundResult(await sendOutboundText({
				cfg,
				to,
				text,
				accountId: accountId ?? void 0,
				replyToMessageId,
				replyInThread,
				header: title ? {
					title,
					template: "blue"
				} : void 0,
				...deliveryOptions
			}));
		},
		sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, accountId, mediaAccess, mediaLocalRoots, mediaReadFile, replyToId, replyToIdSource, replyToMode, threadId, onDeliveryResult, propagateMediaUploadFailure = false }) => {
			const { normalizedReplyToId } = resolveFeishuReplyMode({
				replyToId,
				threadId
			});
			const nextReplyToId = createReplyToFanout({
				replyToId: normalizedReplyToId,
				replyToIdSource,
				replyToMode
			});
			const nextReplyMode = () => {
				const { replyToMessageId, replyInThread } = resolveFeishuReplyMode({
					replyToId: nextReplyToId(),
					threadId
				});
				return {
					replyToMessageId,
					replyInThread
				};
			};
			const deliveryOptions = {
				replyToIdSource,
				replyToMode,
				onDeliveryResult
			};
			if (parseFeishuCommentTarget(to)) return toFeishuOutboundResult(await sendOutboundText({
				cfg,
				to,
				text: mediaUrl?.trim() ? await buildFeishuMediaFallbackText({
					text,
					mediaUrl,
					mediaLinkStyle: "plain"
				}) : text?.trim() ?? "",
				accountId: accountId ?? void 0,
				...nextReplyMode(),
				...deliveryOptions
			}));
			if (!mediaUrl) return toFeishuOutboundResult(await sendOutboundText({
				cfg,
				to,
				text: text ?? "",
				accountId: accountId ?? void 0,
				...nextReplyMode(),
				...deliveryOptions
			}));
			const suppressTextForVoiceMedia = shouldSuppressFeishuTextForVoiceMedia({
				mediaUrl,
				audioAsVoice
			});
			let captionResult;
			if (text?.trim() && !suppressTextForVoiceMedia) captionResult = await sendOutboundText({
				cfg,
				to,
				text,
				accountId: accountId ?? void 0,
				...nextReplyMode(),
				...deliveryOptions
			});
			const results = captionResult ? [captionResult] : [];
			let mediaResult;
			const mediaReplyMode = nextReplyMode();
			try {
				mediaResult = await sendMediaFeishu({
					cfg,
					to,
					mediaUrl,
					accountId: accountId ?? void 0,
					mediaAccess,
					mediaLocalRoots,
					mediaReadFile,
					...mediaReplyMode,
					...audioAsVoice === true ? { audioAsVoice: true } : {}
				});
			} catch (err) {
				if (isChannelPartialDeliveryError(err)) throw partialFeishuSendError(err, results);
				if (propagateMediaUploadFailure) {
					if (captionResult) throw partialFeishuSendError(err, results);
					throw new Error(`Feishu send could not deliver the requested media attachment: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
				}
				console.error(`[feishu] sendMediaFeishu failed:`, err);
				const fallbackText = await buildFeishuMediaFallbackText({
					text: captionResult ? void 0 : text,
					mediaUrl
				});
				try {
					const fallbackResult = await sendOutboundText({
						cfg,
						to,
						text: fallbackText,
						accountId: accountId ?? void 0,
						...captionResult ? nextReplyMode() : mediaReplyMode,
						...deliveryOptions
					});
					return toFeishuOutboundResult(aggregateFeishuSendResult(fallbackResult, [...results, fallbackResult]));
				} catch (error) {
					throw partialFeishuSendError(error, results);
				}
			}
			results.push(mediaResult);
			try {
				await reportFeishuOutboundDelivery(mediaResult, onDeliveryResult);
				if (mediaResult.voiceIntentDegradedToFile && text?.trim()) results.push(await sendOutboundText({
					cfg,
					to,
					text,
					accountId: accountId ?? void 0,
					...nextReplyMode(),
					...deliveryOptions
				}));
			} catch (error) {
				throw partialFeishuSendError(error, results);
			}
			return toFeishuOutboundResult(aggregateFeishuSendResult(mediaResult, results));
		}
	})
};
//#endregion
export { listAuthorizedFeishuDirectoryPeers as a, listAuthorizedFeishuDirectoryGroups as i, feishuOutbound as n, listFeishuDirectoryGroups as o, resolveFeishuReplyMode as r, listFeishuDirectoryPeers as s, FEISHU_PROPAGATE_MEDIA_UPLOAD_FAILURE_MARKER as t };
