Files
openclaw/extensions/device-pair/pair-command-approve.ts
2026-04-04 19:55:04 +09:00

70 lines
2.4 KiB
TypeScript

import { approveDevicePairing, listDevicePairing } from "./api.js";
import { formatPendingRequests } from "./notify.js";
type PendingPairingEntry = Awaited<ReturnType<typeof listDevicePairing>>["pending"][number];
type ApprovePairingResult = Awaited<ReturnType<typeof approveDevicePairing>>;
type ApprovedPairingEntry = Exclude<ApprovePairingResult, null | { status: "forbidden" }>;
function buildMultiplePendingApprovalReply(pending: PendingPairingEntry[]): { text: string } {
return {
text:
`${formatPendingRequests(pending)}\n\n` +
"Multiple pending requests found. Approve one explicitly:\n" +
"/pair approve <requestId>\n" +
"Or approve the most recent:\n" +
"/pair approve latest",
};
}
export function selectPendingApprovalRequest(params: {
pending: PendingPairingEntry[];
requested?: string;
}): { pending?: PendingPairingEntry; reply?: { text: string } } {
if (params.pending.length === 0) {
return { reply: { text: "No pending device pairing requests." } };
}
if (!params.requested) {
return params.pending.length === 1
? { pending: params.pending[0] }
: { reply: buildMultiplePendingApprovalReply(params.pending) };
}
if (params.requested.toLowerCase() === "latest") {
return {
pending: [...params.pending].toSorted((a, b) => (b.ts ?? 0) - (a.ts ?? 0))[0],
};
}
return {
pending: params.pending.find((entry) => entry.requestId === params.requested),
reply: undefined,
};
}
function formatApprovedPairingReply(approved: ApprovedPairingEntry): { text: string } {
const label = approved.device.displayName?.trim() || approved.device.deviceId;
const platform = approved.device.platform?.trim();
const platformLabel = platform ? ` (${platform})` : "";
return { text: `✅ Paired ${label}${platformLabel}.` };
}
export async function approvePendingPairingRequest(params: {
requestId: string;
callerScopes?: readonly string[];
}): Promise<{ text: string }> {
const approved =
params.callerScopes === undefined
? await approveDevicePairing(params.requestId)
: await approveDevicePairing(params.requestId, { callerScopes: params.callerScopes });
if (!approved) {
return { text: "Pairing request not found." };
}
if (approved.status === "forbidden") {
return {
text: `⚠️ This command requires ${approved.missingScope} to approve this pairing request.`,
};
}
return formatApprovedPairingReply(approved);
}