Live video on the AT Protocol
1export interface SlashCommandResult {
2 handled: boolean;
3 error?: string;
4}
5
6export type SlashCommandHandler = (
7 args: string[],
8 rawInput: string,
9) => Promise<SlashCommandResult>;
10
11export interface SlashCommand {
12 name: string;
13 description: string;
14 usage: string;
15 handler: SlashCommandHandler;
16}
17
18const commands = new Map<string, SlashCommand>();
19
20export function registerSlashCommand(command: SlashCommand) {
21 commands.set(command.name, command);
22}
23
24export function unregisterSlashCommand(name: string) {
25 commands.delete(name);
26}
27
28export async function handleSlashCommand(
29 input: string,
30): Promise<SlashCommandResult> {
31 const trimmed = input.trim();
32 if (!trimmed.startsWith("/")) {
33 return { handled: false };
34 }
35
36 const parts = trimmed.slice(1).split(/\s+/);
37 const commandName = parts[0]?.toLowerCase();
38 const args = parts.slice(1);
39
40 if (!commandName) {
41 return { handled: false };
42 }
43
44 const command = commands.get(commandName);
45 if (!command) {
46 return {
47 // for now - return false
48 handled: false,
49 error: `Unknown command: /${commandName}`,
50 };
51 }
52
53 try {
54 return await command.handler(args, trimmed);
55 } catch (err) {
56 return {
57 handled: true,
58 error: err instanceof Error ? err.message : "Command failed",
59 };
60 }
61}
62
63export function getRegisteredCommands(): SlashCommand[] {
64 return Array.from(commands.values());
65}