Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import { Button, type ButtonInteraction, type ComponentData } from "@buape/carbon";
import { ButtonStyle } from "discord-api-types/v10";
import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime";
import type { DiscordExecApprovalConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import type {
ExecApprovalDecision,
ExecApprovalRequest,
ExecApprovalResolved,
PluginApprovalRequest,
PluginApprovalResolved,
} from "openclaw/plugin-sdk/infra-runtime";
export { buildExecApprovalCustomId } from "../approval-handler.runtime.js";
import { getDiscordExecApprovalApprovers } from "../exec-approvals.js";
export { extractDiscordChannelId } from "../approval-native.js";
export type {
ExecApprovalRequest,
ExecApprovalResolved,
PluginApprovalRequest,
PluginApprovalResolved,
} from "openclaw/plugin-sdk/infra-runtime";
function decodeCustomIdValue(value: string): string {
try {
return decodeURIComponent(value);
} catch {
return value;
}
}
export function parseExecApprovalData(
data: ComponentData,
): { approvalId: string; action: ExecApprovalDecision } | null {
if (!data || typeof data !== "object") {
return null;
}
const coerce = (value: unknown) =>
typeof value === "string" || typeof value === "number" ? String(value) : "";
const rawId = coerce(data.id);
const rawAction = coerce(data.action);
if (!rawId || !rawAction) {
return null;
}
const action = rawAction as ExecApprovalDecision;
if (action !== "allow-once" && action !== "allow-always" && action !== "deny") {
return null;
}
return {
approvalId: decodeCustomIdValue(rawId),
action,
};
}
export type ExecApprovalButtonContext = {
getApprovers: () => string[];
resolveApproval: (approvalId: string, decision: ExecApprovalDecision) => Promise<boolean>;
};
export class ExecApprovalButton extends Button {
label = "execapproval";
customId = "execapproval:seed=1";
style = ButtonStyle.Primary;
constructor(private readonly ctx: ExecApprovalButtonContext) {
super();
}
async run(interaction: ButtonInteraction, data: ComponentData): Promise<void> {
const parsed = parseExecApprovalData(data);
if (!parsed) {
try {
await interaction.reply({
content: "This approval is no longer valid.",
ephemeral: true,
});
} catch {}
return;
}
const approvers = this.ctx.getApprovers();
const userId = interaction.userId;
if (!approvers.some((id) => id === userId)) {
try {
await interaction.reply({
content: "⛔ You are not authorized to approve exec requests.",
ephemeral: true,
});
} catch {}
return;
}
const decisionLabel =
parsed.action === "allow-once"
? "Allowed (once)"
: parsed.action === "allow-always"
? "Allowed (always)"
: "Denied";
try {
await interaction.acknowledge();
} catch {}
const ok = await this.ctx.resolveApproval(parsed.approvalId, parsed.action);
if (!ok) {
try {
await interaction.followUp({
content: `Failed to submit approval decision for **${decisionLabel}**. The request may have expired or already been resolved.`,
ephemeral: true,
});
} catch {}
}
}
}
export function createExecApprovalButton(ctx: ExecApprovalButtonContext): Button {
return new ExecApprovalButton(ctx);
}
export function createDiscordExecApprovalButtonContext(params: {
cfg: OpenClawConfig;
accountId: string;
config: DiscordExecApprovalConfig;
gatewayUrl?: string;
}): ExecApprovalButtonContext {
return {
getApprovers: () =>
getDiscordExecApprovalApprovers({
cfg: params.cfg,
accountId: params.accountId,
configOverride: params.config,
}),
resolveApproval: async (approvalId, decision) => {
try {
await resolveApprovalOverGateway({
cfg: params.cfg,
approvalId,
decision,
gatewayUrl: params.gatewayUrl,
clientDisplayName: `Discord approval (${params.accountId})`,
});
return true;
} catch {
return false;
}
},
};
}
¤ Dauer der Verarbeitung: 0.0 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland