@marshmallow-stoat/mally 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,15 +38,13 @@ Make sure to enable decorators in your `tsconfig.json`:
38
38
  import 'reflect-metadata';
39
39
  import { Client } from 'stoat.js';
40
40
  import { MallyHandler } from '@marshmallow-stoat/mally';
41
- import { join } from 'path';
42
41
 
43
42
  const client = new Client();
44
43
 
45
44
  const handler = new MallyHandler({
46
45
  client,
47
46
  prefix: '!',
48
- owners: ['your-user-id'],
49
- commandsDir: join(__dirname, "commands")
47
+ owners: ['your-user-id']
50
48
  });
51
49
 
52
50
  await handler.init();
@@ -78,7 +76,7 @@ export class GeneralCommands {
78
76
  }
79
77
  ```
80
78
 
81
- That's it! No manual imports needed - commands are auto-discovered.
79
+ That's it! No manual imports needed - decorated command classes are auto-discovered.
82
80
 
83
81
  ## Decorators
84
82
 
@@ -165,12 +163,20 @@ interface Context {
165
163
  ```typescript
166
164
  interface MallyHandlerOptions {
167
165
  client: Client;
168
- commandsDir: string; // Directory to scan for commands
166
+ commandsDir?: string; // Legacy mode: explicitly scan this directory
167
+ discovery?: {
168
+ roots?: string[]; // Default: [process.cwd()]
169
+ include?: string[]; // Glob patterns per root
170
+ ignore?: string[]; // Additional ignore globs
171
+ };
169
172
  prefix: string | ((ctx: { serverId?: string }) => string | Promise<string>);
170
173
  owners?: string[]; // Owner user IDs
171
- extensions?: string[]; // File extensions (default: ['.js', '.ts'])
174
+ extensions?: string[]; // File extensions (default: ['.js', '.mjs', '.cjs'])
172
175
  disableMentionPrefix?: boolean; // Disable @bot prefix
173
176
  }
177
+
178
+ // Default auto-discovery is discordx-like: scans broadly under process.cwd(),
179
+ // then registers only files that look like decorated command modules.
174
180
  ```
175
181
 
176
182
  ## Dynamic Prefix
@@ -178,32 +184,35 @@ interface MallyHandlerOptions {
178
184
  ```typescript
179
185
  const handler = new MallyHandler({
180
186
  client,
181
- commandsDir: join(__dirname, 'commands'),
182
187
  prefix: async ({ serverId }) => {
183
188
  // Fetch from database, etc.
184
189
  return serverId ? await getServerPrefix(serverId) : '!';
185
190
  },
186
191
  });
187
- ```
188
-
189
- ## Legacy Class-Based Commands
190
-
191
- You can also use the class-based approach:
192
192
 
193
- ```typescript
194
- import { Command, BaseCommand, Context } from '@marshmallow-stoat/mally';
193
+ // Optional: constrain auto-discovery to specific roots/patterns
194
+ const scopedHandler = new MallyHandler({
195
+ client,
196
+ prefix: '!',
197
+ discovery: {
198
+ roots: [process.cwd()],
199
+ include: ['apps/bot/dist/commands/**/*.js'],
200
+ },
201
+ });
195
202
 
196
- @Command({
197
- name: 'ping',
198
- description: 'Ping command',
199
- })
200
- export class PingCommand extends BaseCommand {
201
- async run(ctx: Context) {
202
- await ctx.reply('Pong!');
203
- }
204
- }
203
+ // TypeScript source discovery is opt-in and requires a TS runtime loader (tsx/ts-node)
204
+ const tsRuntimeHandler = new MallyHandler({
205
+ client,
206
+ prefix: '!',
207
+ extensions: ['.ts'],
208
+ discovery: {
209
+ include: ['apps/bot/src/commands/**/*.ts'],
210
+ },
211
+ });
205
212
  ```
206
213
 
214
+ All commands are defined through `@Stoat()` classes and `@SimpleCommand()` methods.
215
+
207
216
  ## License
208
217
 
209
218
  AGPL-3.0-or-later
package/dist/index.d.mts CHANGED
@@ -4,27 +4,6 @@ import { Client, Message } from 'stoat.js';
4
4
  * Permission types for commands
5
5
  */
6
6
  type Permission = "SendMessages" | "ManageMessages" | "ManageChannels" | "ManageServer" | "KickMembers" | "BanMembers" | "Administrator" | (string & {});
7
- /**
8
- * Command metadata options passed to @Command decorator
9
- */
10
- interface CommandOptions {
11
- /** Command name (defaults to class name without 'Command' suffix) */
12
- name?: string;
13
- /** Command description */
14
- description?: string;
15
- /** Command aliases */
16
- aliases?: string[];
17
- /** Required permissions to run the command */
18
- permissions?: Permission[];
19
- /** Command category (auto-detected from directory if not provided) */
20
- category?: string;
21
- /** Cooldown in milliseconds */
22
- cooldown?: number;
23
- /** Whether the command is NSFW only */
24
- nsfw?: boolean;
25
- /** Whether the command is owner only */
26
- ownerOnly?: boolean;
27
- }
28
7
  /**
29
8
  * Simple command options passed to @SimpleCommand decorator
30
9
  * Used with @Stoat() decorated classes for method-based commands
@@ -86,20 +65,12 @@ interface CommandContext {
86
65
  message: Message;
87
66
  }
88
67
  /**
89
- * Interface that all command classes must implement
68
+ * Optional lifecycle hooks for @Stoat() class instances
90
69
  */
91
- interface MallyCommand {
92
- /** Command metadata (injected by registry) */
93
- metadata: CommandMetadata;
94
- /**
95
- * Execute the command
96
- */
97
- run(ctx: CommandContext): Promise<void>;
98
- /**
99
- * Optional: Called when an error occurs during command execution
100
- */
70
+ interface StoatLifecycle {
71
+ /** Optional: Called when an error occurs during command execution */
101
72
  onError?(ctx: CommandContext, error: Error): Promise<void>;
102
- guardFail?(ctx: CommandContext): Promise<void>;
73
+ /** Optional: Called when a cooldown is active */
103
74
  onCooldown?(ctx: CommandContext, remaining: number): Promise<void>;
104
75
  }
105
76
  interface MallyGuard {
@@ -107,53 +78,33 @@ interface MallyGuard {
107
78
  guardFail?(ctx: CommandContext): Promise<void> | void;
108
79
  }
109
80
  /**
110
- * Abstract base class for commands.
111
- * Extend this class to create commands without boilerplate.
112
- *
113
- * @example
114
- * ```ts
115
- * @Command({ name: 'ping', description: 'Replies with Pong!' })
116
- * export class PingCommand extends BaseCommand {
117
- * async run(ctx) {
118
- * await ctx.reply('Pong!');
119
- * }
120
- * }
121
- * ```
81
+ * Discovery options for automatic command module loading
122
82
  */
123
- declare abstract class BaseCommand implements MallyCommand {
124
- /** Command metadata (injected by registry) */
125
- metadata: CommandMetadata;
126
- /** Typed context for use in subclasses */
127
- protected ctx: CommandContext;
128
- /**
129
- * Execute the command - must be implemented by subclasses
130
- */
131
- abstract run(ctx: CommandContext): Promise<void>;
132
- /**
133
- * Optional: Called when an error occurs during command execution.
134
- * Override this method to provide custom error handling.
135
- */
136
- onError(ctx: CommandContext, error: Error): Promise<void>;
83
+ interface MallyDiscoveryOptions {
84
+ /** Root directories to scan (default: [process.cwd()]) */
85
+ roots?: string[];
86
+ /** Glob patterns relative to each root */
87
+ include?: string[];
88
+ /** Additional ignore patterns */
89
+ ignore?: string[];
137
90
  }
138
- /**
139
- * Constructor type for command classes
140
- */
141
- type CommandConstructor = new () => MallyCommand;
142
91
  /**
143
92
  * Handler options
144
93
  */
145
94
  interface MallyHandlerOptions {
146
95
  /** The client instance */
147
96
  client: Client;
148
- /** Directory to scan for commands (absolute path) */
149
- commandsDir: string;
97
+ /** Directory to scan for command modules (absolute path) */
98
+ commandsDir?: string;
99
+ /** Auto-discovery options used when commandsDir is not provided */
100
+ discovery?: MallyDiscoveryOptions;
150
101
  /** Command prefix or prefix resolver function */
151
102
  prefix: string | ((ctx: {
152
103
  serverId?: string;
153
104
  }) => string | Promise<string>);
154
105
  /** Owner IDs for owner-only commands */
155
106
  owners?: string[];
156
- /** File extensions to load (default: ['.js', '.ts']) */
107
+ /** File extensions to load (default: ['.js', '.mjs', '.cjs']) */
157
108
  extensions?: string[];
158
109
  /** Disable mention prefix support (default: false) */
159
110
  disableMentionPrefix?: boolean;
@@ -221,49 +172,11 @@ declare function SimpleCommand(options?: SimpleCommandOptions): MethodDecorator;
221
172
  */
222
173
  declare function getSimpleCommands(target: Function): SimpleCommandDefinition[];
223
174
 
224
- /**
225
- * @Command
226
- * Marks a class as a command and attaches metadata.
227
- * This is the legacy/class-based approach where each command is a separate class.
228
- *
229
- * @example
230
- * ```ts
231
- * import { Command, MallyCommand, CommandContext } from '@marshmallow/mally';
232
- *
233
- * @Command({
234
- * description: 'Ban a user from the server',
235
- * aliases: ['b'],
236
- * permissions: ['BanMembers']
237
- * })
238
- * export class BanCommand implements MallyCommand {
239
- * metadata!: CommandMetadata;
240
- *
241
- * async run(ctx: CommandContext) {
242
- * const userId = ctx.args[0];
243
- * await ctx.reply(`Banned user ${userId}`);
244
- * }
245
- * }
246
- * ```
247
- */
248
- declare function Command(options?: CommandOptions): ClassDecorator;
249
- /**
250
- * Check if a class is decorated with @Command
251
- */
252
- declare function isCommand(target: Function): boolean;
253
- /**
254
- * Get command options from a decorated class
255
- */
256
- declare function getCommandOptions(target: Function): CommandOptions | undefined;
257
- /**
258
- * Build complete CommandMetadata from options and class name
259
- */
260
- declare function buildCommandMetadata(target: Function, options: CommandOptions, category?: string): CommandMetadata;
261
-
262
175
  /**
263
176
  * @Guard
264
177
  * Runs before a command to check if it should execute.
265
178
  * Should return true to allow execution, false to block.
266
- * Can be applied to both @Command classes and @Stoat classes.
179
+ * Applied on @Stoat classes to guard all contained @SimpleCommand methods.
267
180
  *
268
181
  * @example
269
182
  * ```ts
@@ -305,23 +218,26 @@ declare function buildSimpleCommandMetadata(options: SimpleCommandOptions, metho
305
218
  * Metadata keys used by decorators
306
219
  */
307
220
  declare const METADATA_KEYS: {
308
- readonly COMMAND_OPTIONS: symbol;
309
- readonly IS_COMMAND: symbol;
310
221
  readonly IS_STOAT_CLASS: symbol;
311
222
  readonly SIMPLE_COMMANDS: symbol;
312
223
  readonly GUARDS: "mally:command:guards";
313
224
  };
314
225
 
226
+ interface AutoDiscoveryOptions {
227
+ roots?: string[];
228
+ include?: string[];
229
+ ignore?: string[];
230
+ }
315
231
  /**
316
- * Stored command entry (supports both class-based and method-based commands)
232
+ * Stored command entry from @Stoat/@SimpleCommand registration.
317
233
  */
318
234
  interface RegisteredCommand {
319
- /** Instance of the command class */
320
- instance: MallyCommand | object;
235
+ /** Instance of the @Stoat class */
236
+ instance: object;
321
237
  /** Command metadata */
322
238
  metadata: CommandMetadata;
323
- /** Method name to call (for @SimpleCommand methods) */
324
- methodName?: string;
239
+ /** Method name to call */
240
+ methodName: string;
325
241
  /** The original class constructor (for guard validation) */
326
242
  classConstructor: Function;
327
243
  }
@@ -338,9 +254,11 @@ interface RegisteredCommand {
338
254
  * ```
339
255
  */
340
256
  declare class CommandRegistry {
257
+ private static readonly DEFAULT_AUTO_DISCOVERY_IGNORES;
341
258
  private readonly commands;
342
259
  private readonly aliases;
343
260
  private readonly extensions;
261
+ private readonly processedStoatClasses;
344
262
  constructor(extensions?: string[]);
345
263
  /**
346
264
  * Get the number of registered commands
@@ -350,10 +268,16 @@ declare class CommandRegistry {
350
268
  * Load commands from a directory using glob pattern matching
351
269
  */
352
270
  loadFromDirectory(directory: string): Promise<void>;
271
+ /**
272
+ * Auto-discover command files across one or more roots.
273
+ */
274
+ autoDiscover(options?: AutoDiscoveryOptions): Promise<void>;
275
+ private getDefaultAutoDiscoveryPatterns;
276
+ private isLikelyCommandModule;
353
277
  /**
354
278
  * Register a command instance
355
279
  */
356
- register(instance: MallyCommand | object, metadata: CommandMetadata, classConstructor: Function, methodName?: string): void;
280
+ register(instance: object, metadata: CommandMetadata, classConstructor: Function, methodName: string): void;
357
281
  /**
358
282
  * Get a command by name or alias
359
283
  */
@@ -397,17 +321,11 @@ declare class CommandRegistry {
397
321
  * @private
398
322
  */
399
323
  private validateGuards;
400
- /**
401
- * Validate that commands with cooldowns implement the onCooldown method
402
- * @param instance
403
- * @param metadata
404
- * @private
405
- */
406
- private validateCooldown;
407
324
  /**
408
325
  * Load commands from a single file
409
326
  */
410
327
  private loadFile;
328
+ private registerStoatClassCommands;
411
329
  /**
412
330
  * Derive category from file path relative to base directory
413
331
  */
@@ -428,7 +346,6 @@ declare class CommandRegistry {
428
346
  *
429
347
  * const handler = new MallyHandler({
430
348
  * client,
431
- * commandsDir: path.join(__dirname, 'commands'),
432
349
  * prefix: '!',
433
350
  * owners: ['owner-user-id'],
434
351
  * });
@@ -441,7 +358,8 @@ declare class CommandRegistry {
441
358
  * ```
442
359
  */
443
360
  declare class MallyHandler {
444
- private readonly commandsDir;
361
+ private readonly commandsDir?;
362
+ private readonly discoveryOptions?;
445
363
  private readonly prefixResolver;
446
364
  private readonly owners;
447
365
  private readonly registry;
@@ -546,4 +464,4 @@ declare class MallyHandler {
546
464
  private setCooldown;
547
465
  }
548
466
 
549
- export { BaseCommand, Command, type CommandConstructor, type CommandContext, type CommandMetadata, type CommandOptions, CommandRegistry, type CommandContext as Context, Guard, METADATA_KEYS, type MallyCommand, type MallyGuard, MallyHandler, type MallyHandlerOptions, type Permission, type RegisteredCommand, SimpleCommand, type SimpleCommandDefinition, type SimpleCommandOptions, Stoat, buildCommandMetadata, buildSimpleCommandMetadata, getCommandOptions, getGuards, getSimpleCommands, isCommand, isStoatClass };
467
+ export { type CommandContext, type CommandMetadata, CommandRegistry, type CommandContext as Context, Guard, METADATA_KEYS, type MallyDiscoveryOptions, type MallyGuard, MallyHandler, type MallyHandlerOptions, type Permission, type RegisteredCommand, SimpleCommand, type SimpleCommandDefinition, type SimpleCommandOptions, Stoat, type StoatLifecycle, buildSimpleCommandMetadata, getGuards, getSimpleCommands, isStoatClass };
package/dist/index.d.ts CHANGED
@@ -4,27 +4,6 @@ import { Client, Message } from 'stoat.js';
4
4
  * Permission types for commands
5
5
  */
6
6
  type Permission = "SendMessages" | "ManageMessages" | "ManageChannels" | "ManageServer" | "KickMembers" | "BanMembers" | "Administrator" | (string & {});
7
- /**
8
- * Command metadata options passed to @Command decorator
9
- */
10
- interface CommandOptions {
11
- /** Command name (defaults to class name without 'Command' suffix) */
12
- name?: string;
13
- /** Command description */
14
- description?: string;
15
- /** Command aliases */
16
- aliases?: string[];
17
- /** Required permissions to run the command */
18
- permissions?: Permission[];
19
- /** Command category (auto-detected from directory if not provided) */
20
- category?: string;
21
- /** Cooldown in milliseconds */
22
- cooldown?: number;
23
- /** Whether the command is NSFW only */
24
- nsfw?: boolean;
25
- /** Whether the command is owner only */
26
- ownerOnly?: boolean;
27
- }
28
7
  /**
29
8
  * Simple command options passed to @SimpleCommand decorator
30
9
  * Used with @Stoat() decorated classes for method-based commands
@@ -86,20 +65,12 @@ interface CommandContext {
86
65
  message: Message;
87
66
  }
88
67
  /**
89
- * Interface that all command classes must implement
68
+ * Optional lifecycle hooks for @Stoat() class instances
90
69
  */
91
- interface MallyCommand {
92
- /** Command metadata (injected by registry) */
93
- metadata: CommandMetadata;
94
- /**
95
- * Execute the command
96
- */
97
- run(ctx: CommandContext): Promise<void>;
98
- /**
99
- * Optional: Called when an error occurs during command execution
100
- */
70
+ interface StoatLifecycle {
71
+ /** Optional: Called when an error occurs during command execution */
101
72
  onError?(ctx: CommandContext, error: Error): Promise<void>;
102
- guardFail?(ctx: CommandContext): Promise<void>;
73
+ /** Optional: Called when a cooldown is active */
103
74
  onCooldown?(ctx: CommandContext, remaining: number): Promise<void>;
104
75
  }
105
76
  interface MallyGuard {
@@ -107,53 +78,33 @@ interface MallyGuard {
107
78
  guardFail?(ctx: CommandContext): Promise<void> | void;
108
79
  }
109
80
  /**
110
- * Abstract base class for commands.
111
- * Extend this class to create commands without boilerplate.
112
- *
113
- * @example
114
- * ```ts
115
- * @Command({ name: 'ping', description: 'Replies with Pong!' })
116
- * export class PingCommand extends BaseCommand {
117
- * async run(ctx) {
118
- * await ctx.reply('Pong!');
119
- * }
120
- * }
121
- * ```
81
+ * Discovery options for automatic command module loading
122
82
  */
123
- declare abstract class BaseCommand implements MallyCommand {
124
- /** Command metadata (injected by registry) */
125
- metadata: CommandMetadata;
126
- /** Typed context for use in subclasses */
127
- protected ctx: CommandContext;
128
- /**
129
- * Execute the command - must be implemented by subclasses
130
- */
131
- abstract run(ctx: CommandContext): Promise<void>;
132
- /**
133
- * Optional: Called when an error occurs during command execution.
134
- * Override this method to provide custom error handling.
135
- */
136
- onError(ctx: CommandContext, error: Error): Promise<void>;
83
+ interface MallyDiscoveryOptions {
84
+ /** Root directories to scan (default: [process.cwd()]) */
85
+ roots?: string[];
86
+ /** Glob patterns relative to each root */
87
+ include?: string[];
88
+ /** Additional ignore patterns */
89
+ ignore?: string[];
137
90
  }
138
- /**
139
- * Constructor type for command classes
140
- */
141
- type CommandConstructor = new () => MallyCommand;
142
91
  /**
143
92
  * Handler options
144
93
  */
145
94
  interface MallyHandlerOptions {
146
95
  /** The client instance */
147
96
  client: Client;
148
- /** Directory to scan for commands (absolute path) */
149
- commandsDir: string;
97
+ /** Directory to scan for command modules (absolute path) */
98
+ commandsDir?: string;
99
+ /** Auto-discovery options used when commandsDir is not provided */
100
+ discovery?: MallyDiscoveryOptions;
150
101
  /** Command prefix or prefix resolver function */
151
102
  prefix: string | ((ctx: {
152
103
  serverId?: string;
153
104
  }) => string | Promise<string>);
154
105
  /** Owner IDs for owner-only commands */
155
106
  owners?: string[];
156
- /** File extensions to load (default: ['.js', '.ts']) */
107
+ /** File extensions to load (default: ['.js', '.mjs', '.cjs']) */
157
108
  extensions?: string[];
158
109
  /** Disable mention prefix support (default: false) */
159
110
  disableMentionPrefix?: boolean;
@@ -221,49 +172,11 @@ declare function SimpleCommand(options?: SimpleCommandOptions): MethodDecorator;
221
172
  */
222
173
  declare function getSimpleCommands(target: Function): SimpleCommandDefinition[];
223
174
 
224
- /**
225
- * @Command
226
- * Marks a class as a command and attaches metadata.
227
- * This is the legacy/class-based approach where each command is a separate class.
228
- *
229
- * @example
230
- * ```ts
231
- * import { Command, MallyCommand, CommandContext } from '@marshmallow/mally';
232
- *
233
- * @Command({
234
- * description: 'Ban a user from the server',
235
- * aliases: ['b'],
236
- * permissions: ['BanMembers']
237
- * })
238
- * export class BanCommand implements MallyCommand {
239
- * metadata!: CommandMetadata;
240
- *
241
- * async run(ctx: CommandContext) {
242
- * const userId = ctx.args[0];
243
- * await ctx.reply(`Banned user ${userId}`);
244
- * }
245
- * }
246
- * ```
247
- */
248
- declare function Command(options?: CommandOptions): ClassDecorator;
249
- /**
250
- * Check if a class is decorated with @Command
251
- */
252
- declare function isCommand(target: Function): boolean;
253
- /**
254
- * Get command options from a decorated class
255
- */
256
- declare function getCommandOptions(target: Function): CommandOptions | undefined;
257
- /**
258
- * Build complete CommandMetadata from options and class name
259
- */
260
- declare function buildCommandMetadata(target: Function, options: CommandOptions, category?: string): CommandMetadata;
261
-
262
175
  /**
263
176
  * @Guard
264
177
  * Runs before a command to check if it should execute.
265
178
  * Should return true to allow execution, false to block.
266
- * Can be applied to both @Command classes and @Stoat classes.
179
+ * Applied on @Stoat classes to guard all contained @SimpleCommand methods.
267
180
  *
268
181
  * @example
269
182
  * ```ts
@@ -305,23 +218,26 @@ declare function buildSimpleCommandMetadata(options: SimpleCommandOptions, metho
305
218
  * Metadata keys used by decorators
306
219
  */
307
220
  declare const METADATA_KEYS: {
308
- readonly COMMAND_OPTIONS: symbol;
309
- readonly IS_COMMAND: symbol;
310
221
  readonly IS_STOAT_CLASS: symbol;
311
222
  readonly SIMPLE_COMMANDS: symbol;
312
223
  readonly GUARDS: "mally:command:guards";
313
224
  };
314
225
 
226
+ interface AutoDiscoveryOptions {
227
+ roots?: string[];
228
+ include?: string[];
229
+ ignore?: string[];
230
+ }
315
231
  /**
316
- * Stored command entry (supports both class-based and method-based commands)
232
+ * Stored command entry from @Stoat/@SimpleCommand registration.
317
233
  */
318
234
  interface RegisteredCommand {
319
- /** Instance of the command class */
320
- instance: MallyCommand | object;
235
+ /** Instance of the @Stoat class */
236
+ instance: object;
321
237
  /** Command metadata */
322
238
  metadata: CommandMetadata;
323
- /** Method name to call (for @SimpleCommand methods) */
324
- methodName?: string;
239
+ /** Method name to call */
240
+ methodName: string;
325
241
  /** The original class constructor (for guard validation) */
326
242
  classConstructor: Function;
327
243
  }
@@ -338,9 +254,11 @@ interface RegisteredCommand {
338
254
  * ```
339
255
  */
340
256
  declare class CommandRegistry {
257
+ private static readonly DEFAULT_AUTO_DISCOVERY_IGNORES;
341
258
  private readonly commands;
342
259
  private readonly aliases;
343
260
  private readonly extensions;
261
+ private readonly processedStoatClasses;
344
262
  constructor(extensions?: string[]);
345
263
  /**
346
264
  * Get the number of registered commands
@@ -350,10 +268,16 @@ declare class CommandRegistry {
350
268
  * Load commands from a directory using glob pattern matching
351
269
  */
352
270
  loadFromDirectory(directory: string): Promise<void>;
271
+ /**
272
+ * Auto-discover command files across one or more roots.
273
+ */
274
+ autoDiscover(options?: AutoDiscoveryOptions): Promise<void>;
275
+ private getDefaultAutoDiscoveryPatterns;
276
+ private isLikelyCommandModule;
353
277
  /**
354
278
  * Register a command instance
355
279
  */
356
- register(instance: MallyCommand | object, metadata: CommandMetadata, classConstructor: Function, methodName?: string): void;
280
+ register(instance: object, metadata: CommandMetadata, classConstructor: Function, methodName: string): void;
357
281
  /**
358
282
  * Get a command by name or alias
359
283
  */
@@ -397,17 +321,11 @@ declare class CommandRegistry {
397
321
  * @private
398
322
  */
399
323
  private validateGuards;
400
- /**
401
- * Validate that commands with cooldowns implement the onCooldown method
402
- * @param instance
403
- * @param metadata
404
- * @private
405
- */
406
- private validateCooldown;
407
324
  /**
408
325
  * Load commands from a single file
409
326
  */
410
327
  private loadFile;
328
+ private registerStoatClassCommands;
411
329
  /**
412
330
  * Derive category from file path relative to base directory
413
331
  */
@@ -428,7 +346,6 @@ declare class CommandRegistry {
428
346
  *
429
347
  * const handler = new MallyHandler({
430
348
  * client,
431
- * commandsDir: path.join(__dirname, 'commands'),
432
349
  * prefix: '!',
433
350
  * owners: ['owner-user-id'],
434
351
  * });
@@ -441,7 +358,8 @@ declare class CommandRegistry {
441
358
  * ```
442
359
  */
443
360
  declare class MallyHandler {
444
- private readonly commandsDir;
361
+ private readonly commandsDir?;
362
+ private readonly discoveryOptions?;
445
363
  private readonly prefixResolver;
446
364
  private readonly owners;
447
365
  private readonly registry;
@@ -546,4 +464,4 @@ declare class MallyHandler {
546
464
  private setCooldown;
547
465
  }
548
466
 
549
- export { BaseCommand, Command, type CommandConstructor, type CommandContext, type CommandMetadata, type CommandOptions, CommandRegistry, type CommandContext as Context, Guard, METADATA_KEYS, type MallyCommand, type MallyGuard, MallyHandler, type MallyHandlerOptions, type Permission, type RegisteredCommand, SimpleCommand, type SimpleCommandDefinition, type SimpleCommandOptions, Stoat, buildCommandMetadata, buildSimpleCommandMetadata, getCommandOptions, getGuards, getSimpleCommands, isCommand, isStoatClass };
467
+ export { type CommandContext, type CommandMetadata, CommandRegistry, type CommandContext as Context, Guard, METADATA_KEYS, type MallyDiscoveryOptions, type MallyGuard, MallyHandler, type MallyHandlerOptions, type Permission, type RegisteredCommand, SimpleCommand, type SimpleCommandDefinition, type SimpleCommandOptions, Stoat, type StoatLifecycle, buildSimpleCommandMetadata, getGuards, getSimpleCommands, isStoatClass };