Files and folders
How file discovery, names, and compiled paths fit together.
SWAGcommands discovers files recursively in the directories you pass to SWAG.create(). Each file exports one definition as its default export. Command names come from filenames; subcommand roots come from their immediate folder names.
src/
├── commands/
│ ├── ping.ts → /ping
│ └── utility/echo.ts → /echo
├── subcommands/
│ └── admin/ → /admin
│ ├── index.ts → root settings
│ └── ban.ts → /admin ban
├── context-menus/
│ ├── User Information.ts → User Information
│ └── Report Message.ts → Report Message
├── preconditions/
│ └── MinimumLevel.ts
├── features/
│ └── reports/daily.ts
└── events/
└── messageCreate/
└── log.tsNormal command names are lowercased for lookup. Message aliases can live on the command object. Context-menu names preserve the filename's spaces and casing. Keep filenames unique where they produce the same command name or identity.
Point to runtime files
The loader uses Node's require() to load .js or .ts files. In a compiled TypeScript project, point to dist, not src:
await SWAG.create({
client,
commandsDir: "./dist/commands",
subcommandsDir: "./dist/subcommands",
contextMenusDir: "./dist/context-menus",
preconditionsDir: "./dist/preconditions",
featuresDir: "./dist/features",
events: { dir: "./dist/events" },
});The paths are relative to the process working directory. Starting your bot from another folder changes what ./dist/commands means, so use a stable working directory or absolute paths in deployment environments. Only provide folders that actually exist.
Definition modules execute when loaded. Keep top-level code light; put async setup in a command's init, a feature, or your own bootstrap.