Files
openclaw/src/auto-reply/skill-commands-base.ts
Vincent Koc 041f0b87ec perf(inbound): trim cold startup import graph (#52082)
* perf(inbound): trim cold startup import graph

* chore(reply): drop redundant inline action type import

* fix(inbound): restore warning and maintenance seams

* fix(reply): restore type seam and secure forked transcripts
2026-03-21 22:32:21 -07:00

97 lines
2.7 KiB
TypeScript

import type { SkillCommandSpec } from "../agents/skills.js";
import { getChatCommands } from "./commands-registry.data.js";
export function listReservedChatSlashCommandNames(extraNames: string[] = []): Set<string> {
const reserved = new Set<string>();
for (const command of getChatCommands()) {
if (command.nativeName) {
reserved.add(command.nativeName.toLowerCase());
}
for (const alias of command.textAliases) {
const trimmed = alias.trim();
if (!trimmed.startsWith("/")) {
continue;
}
reserved.add(trimmed.slice(1).toLowerCase());
}
}
for (const name of extraNames) {
const trimmed = name.trim().toLowerCase();
if (trimmed) {
reserved.add(trimmed);
}
}
return reserved;
}
function normalizeSkillCommandLookup(value: string): string {
return value
.trim()
.toLowerCase()
.replace(/[\s_]+/g, "-");
}
function findSkillCommand(
skillCommands: SkillCommandSpec[],
rawName: string,
): SkillCommandSpec | undefined {
const trimmed = rawName.trim();
if (!trimmed) {
return undefined;
}
const lowered = trimmed.toLowerCase();
const normalized = normalizeSkillCommandLookup(trimmed);
return skillCommands.find((entry) => {
if (entry.name.toLowerCase() === lowered) {
return true;
}
if (entry.skillName.toLowerCase() === lowered) {
return true;
}
return (
normalizeSkillCommandLookup(entry.name) === normalized ||
normalizeSkillCommandLookup(entry.skillName) === normalized
);
});
}
export function resolveSkillCommandInvocation(params: {
commandBodyNormalized: string;
skillCommands: SkillCommandSpec[];
}): { command: SkillCommandSpec; args?: string } | null {
const trimmed = params.commandBodyNormalized.trim();
if (!trimmed.startsWith("/")) {
return null;
}
const match = trimmed.match(/^\/([^\s]+)(?:\s+([\s\S]+))?$/);
if (!match) {
return null;
}
const commandName = match[1]?.trim().toLowerCase();
if (!commandName) {
return null;
}
if (commandName === "skill") {
const remainder = match[2]?.trim();
if (!remainder) {
return null;
}
const skillMatch = remainder.match(/^([^\s]+)(?:\s+([\s\S]+))?$/);
if (!skillMatch) {
return null;
}
const skillCommand = findSkillCommand(params.skillCommands, skillMatch[1] ?? "");
if (!skillCommand) {
return null;
}
const args = skillMatch[2]?.trim();
return { command: skillCommand, args: args || undefined };
}
const command = params.skillCommands.find((entry) => entry.name.toLowerCase() === commandName);
if (!command) {
return null;
}
const args = match[2]?.trim();
return { command, args: args || undefined };
}