Files
openclaw/src/plugin-sdk/telegram-command-config.ts
2026-04-07 11:18:18 +01:00

123 lines
3.8 KiB
TypeScript

import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
export type TelegramCustomCommandInput = {
command?: string | null;
description?: string | null;
};
export type TelegramCustomCommandIssue = {
index: number;
field: "command" | "description";
message: string;
};
const TELEGRAM_COMMAND_NAME_PATTERN_VALUE = /^[a-z0-9_]{1,32}$/;
function normalizeTelegramCommandNameImpl(value: string): string {
const trimmed = value.trim();
if (!trimmed) {
return "";
}
const withoutSlash = trimmed.startsWith("/") ? trimmed.slice(1) : trimmed;
return normalizeLowercaseStringOrEmpty(withoutSlash).replace(/-/g, "_");
}
function normalizeTelegramCommandDescriptionImpl(value: string): string {
return value.trim();
}
function resolveTelegramCustomCommandsImpl(params: {
commands?: TelegramCustomCommandInput[] | null;
reservedCommands?: Set<string>;
checkReserved?: boolean;
checkDuplicates?: boolean;
}): {
commands: Array<{ command: string; description: string }>;
issues: TelegramCustomCommandIssue[];
} {
const entries = Array.isArray(params.commands) ? params.commands : [];
const reserved = params.reservedCommands ?? new Set<string>();
const checkReserved = params.checkReserved !== false;
const checkDuplicates = params.checkDuplicates !== false;
const seen = new Set<string>();
const resolved: Array<{ command: string; description: string }> = [];
const issues: TelegramCustomCommandIssue[] = [];
for (let index = 0; index < entries.length; index += 1) {
const entry = entries[index];
const normalized = normalizeTelegramCommandNameImpl(String(entry?.command ?? ""));
if (!normalized) {
issues.push({
index,
field: "command",
message: "Telegram custom command is missing a command name.",
});
continue;
}
if (!TELEGRAM_COMMAND_NAME_PATTERN_VALUE.test(normalized)) {
issues.push({
index,
field: "command",
message: `Telegram custom command "/${normalized}" is invalid (use a-z, 0-9, underscore; max 32 chars).`,
});
continue;
}
if (checkReserved && reserved.has(normalized)) {
issues.push({
index,
field: "command",
message: `Telegram custom command "/${normalized}" conflicts with a native command.`,
});
continue;
}
if (checkDuplicates && seen.has(normalized)) {
issues.push({
index,
field: "command",
message: `Telegram custom command "/${normalized}" is duplicated.`,
});
continue;
}
const description = normalizeTelegramCommandDescriptionImpl(String(entry?.description ?? ""));
if (!description) {
issues.push({
index,
field: "description",
message: `Telegram custom command "/${normalized}" is missing a description.`,
});
continue;
}
if (checkDuplicates) {
seen.add(normalized);
}
resolved.push({ command: normalized, description });
}
return { commands: resolved, issues };
}
export function getTelegramCommandNamePattern(): RegExp {
return TELEGRAM_COMMAND_NAME_PATTERN_VALUE;
}
export const TELEGRAM_COMMAND_NAME_PATTERN = TELEGRAM_COMMAND_NAME_PATTERN_VALUE;
export function normalizeTelegramCommandName(value: string): string {
return normalizeTelegramCommandNameImpl(value);
}
export function normalizeTelegramCommandDescription(value: string): string {
return normalizeTelegramCommandDescriptionImpl(value);
}
export function resolveTelegramCustomCommands(params: {
commands?: TelegramCustomCommandInput[] | null;
reservedCommands?: Set<string>;
checkReserved?: boolean;
checkDuplicates?: boolean;
}): {
commands: Array<{ command: string; description: string }>;
issues: TelegramCustomCommandIssue[];
} {
return resolveTelegramCustomCommandsImpl(params);
}