import { ButtonStyle } from "discord-api-types/v10"; import type { ApprovalActionView, ChannelApprovalCapabilityHandlerContext, ExecApprovalExpiredView, ExecApprovalPendingView, ExecApprovalResolvedView, PendingApprovalView, PluginApprovalExpiredView, PluginApprovalPendingView, PluginApprovalResolvedView, } from "openclaw/plugin-sdk/approval-handler-runtime"; import { createChannelApprovalNativeRuntimeAdapter } from "openclaw/plugin-sdk/approval-handler-runtime"; import type { ExecApprovalDecision } from "openclaw/plugin-sdk/approval-runtime"; import type { DiscordExecApprovalConfig, OpenClawConfig, } from "openclaw/plugin-sdk/config-contracts"; import { logDebug, logError } from "openclaw/plugin-sdk/logging-core"; import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime"; import { shouldHandleDiscordApprovalRequest } from "./approval-shared.js"; import { isDiscordExecApprovalClientEnabled } from "./exec-approvals.js"; import { Button, createChannelMessage, createUserDmChannel, deleteChannelMessage, editChannelMessage, Row, Separator, TextDisplay, serializePayload, type MessagePayloadObject, type TopLevelComponents, } from "./internal/discord.js"; import { createDiscordClient, stripUndefinedFields } from "./send.shared.js"; import { DiscordUiContainer } from "./ui.js"; type PendingApproval = { discordMessageId: string; discordChannelId: string; }; type DiscordPendingDelivery = { body: ReturnType; }; type PreparedDeliveryTarget = { discordChannelId: string; recipientUserId?: string; }; type DecisionApprovalActionView = ApprovalActionView & { decision: ExecApprovalDecision; }; export type DiscordApprovalHandlerContext = { token: string; config: DiscordExecApprovalConfig; }; function isDecisionApprovalAction( action: ApprovalActionView, ): action is DecisionApprovalActionView { return ( action.kind === "decision" && (action.decision === "allow-once" || action.decision === "allow-always" || action.decision === "deny") ); } function resolveHandlerContext(params: ChannelApprovalCapabilityHandlerContext): { accountId: string; context: DiscordApprovalHandlerContext; } | null { const context = params.context as DiscordApprovalHandlerContext | undefined; const accountId = normalizeOptionalString(params.accountId) ?? ""; if (!context?.token || !accountId) { return null; } return { accountId, context }; } class ExecApprovalContainer extends DiscordUiContainer { constructor(params: { cfg: OpenClawConfig; accountId: string; title: string; description?: string; commandPreview: string; commandSecondaryPreview?: string | null; metadataLines?: string[]; actionRow?: Row