Commands
Register console and chat commands with command / command.server / command.admin from the @s2script/sdk barrel — the spelling s2s create scaffolds:
import { command, ADMFLAG, HookResult } from '@s2script/sdk';
import type { Command, HookResultValue } from '@s2script/sdk';
export function OnPluginStart(): void {
command('hello', (cmd) => {
cmd.reply(`hi from slot ${cmd.callerSlot}`);
return HookResult.Handled;
});
command.server('sm_reloadmap', (cmd) => {
cmd.reply('reloading');
return HookResult.Handled;
});
command.admin('sm_kick', ADMFLAG.KICK, kick);
}
function kick(cmd: Command): HookResultValue {
if (cmd.argCount < 1) {
cmd.reply('Usage: sm_kick <target>');
return HookResult.Handled; // usage errors still consume the command
}
return HookResult.Handled;
} command— anyone / console (SourceModRegConsoleCmd)command.server— server console only (callerSlot < 0; SourceModRegServerCmd)command.admin— flag-gated via the host admin cache (SourceModRegAdminCmd)command.onClientCommand— observe an existing CLIENT command by name (SourceModAddCommandListener)
command is load-window only — it throws after settle. Call it from OnPluginStart. CS2 types stay on @s2script/cs2; @s2script/sdk/unsafe and @s2script/sdk/console stay subpaths (not re-exported on the barrel).
Return values
A command you own is a SourceMod Action callback; ours is HookResult. Return HookResult.Handled (Plugin_Handled) on every path, including usage errors — the command was still consumed. Omit the return (void) to continue — the same as returning HookResult.Continue.
Chat listeners that must pass through — basetriggers, or a bare rtv / nominate word — return HookResult.Continue so the player’s line still broadcasts:
export function OnClientSayCommand(slot: number, text: string, teamonly: boolean): HookResultValue {
if (text.trim().toLowerCase() === 'rtv') {
requestRtv(slot);
}
return HookResult.Continue; // never suppress — the trigger word still shows
} The cmd invocation is engine-generic (callerSlot, args, argString, reply). Command on @s2script/sdk is an alias for CommandInvocation. Chat ! / / triggers reach the same registry. Player replies are deferred one frame so they land after the chat line (SourceMod parity).
cmd.replyT(key, …args) replies in the caller’s language (SourceMod’s %t). Load the phrase files first — see Translations. The key is checked at build against those files; a plugin that loads none widens it to string. A missing file or an unloaded @s2script/translations degrades to the raw key.
Cookbook recipes in the SDK repo are copy-pasteable named-public plugins: export function OnPluginStart plus any other publics they need (OnGameFrame, OnClientConnected, …).
See the commands module and admin module.