openclaw/extensions/slack/src/exec-approvals.ts

82 lines
2.9 KiB
TypeScript

import {
createChannelExecApprovalProfile,
doesApprovalRequestMatchChannelAccount,
isChannelExecApprovalTargetRecipient,
resolveApprovalApprovers,
} from "openclaw/plugin-sdk/approval-runtime";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
import { resolveSlackAccount } from "./accounts.js";
export function normalizeSlackApproverId(value: string | number): string | undefined {
const trimmed = String(value).trim();
if (!trimmed) {
return undefined;
}
const prefixed = trimmed.match(/^(?:slack|user):([A-Z0-9]+)$/i);
if (prefixed?.[1]) {
return prefixed[1];
}
const mention = trimmed.match(/^<@([A-Z0-9]+)>$/i);
if (mention?.[1]) {
return mention[1];
}
return /^[UW][A-Z0-9]+$/i.test(trimmed) ? trimmed : undefined;
}
function resolveSlackOwnerApprovers(cfg: OpenClawConfig): string[] {
const ownerAllowFrom = cfg.commands?.ownerAllowFrom;
if (!Array.isArray(ownerAllowFrom) || ownerAllowFrom.length === 0) {
return [];
}
return resolveApprovalApprovers({
explicit: ownerAllowFrom,
normalizeApprover: normalizeSlackApproverId,
});
}
export function getSlackExecApprovalApprovers(params: {
cfg: OpenClawConfig;
accountId?: string | null;
}): string[] {
const account = resolveSlackAccount(params).config;
return resolveApprovalApprovers({
explicit: account.execApprovals?.approvers ?? resolveSlackOwnerApprovers(params.cfg),
normalizeApprover: normalizeSlackApproverId,
});
}
export function isSlackExecApprovalTargetRecipient(params: {
cfg: OpenClawConfig;
senderId?: string | null;
accountId?: string | null;
}): boolean {
return isChannelExecApprovalTargetRecipient({
...params,
channel: "slack",
normalizeSenderId: normalizeSlackApproverId,
matchTarget: ({ target, normalizedSenderId }) =>
normalizeSlackApproverId(target.to) === normalizedSenderId,
});
}
const slackExecApprovalProfile = createChannelExecApprovalProfile({
resolveConfig: (params) => resolveSlackAccount(params).config.execApprovals,
resolveApprovers: getSlackExecApprovalApprovers,
normalizeSenderId: normalizeSlackApproverId,
isTargetRecipient: isSlackExecApprovalTargetRecipient,
matchesRequestAccount: (params) =>
doesApprovalRequestMatchChannelAccount({
cfg: params.cfg,
request: params.request,
channel: "slack",
accountId: params.accountId,
}),
});
export const isSlackExecApprovalClientEnabled = slackExecApprovalProfile.isClientEnabled;
export const isSlackExecApprovalApprover = slackExecApprovalProfile.isApprover;
export const isSlackExecApprovalAuthorizedSender = slackExecApprovalProfile.isAuthorizedSender;
export const resolveSlackExecApprovalTarget = slackExecApprovalProfile.resolveTarget;
export const shouldHandleSlackExecApprovalRequest = slackExecApprovalProfile.shouldHandleRequest;
export const shouldSuppressLocalSlackExecApprovalPrompt =
slackExecApprovalProfile.shouldSuppressLocalPrompt;