@sylphx/flow 1.8.0 → 1.8.2
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/CHANGELOG.md +72 -0
- package/assets/output-styles/silent.md +145 -8
- package/assets/rules/core.md +19 -2
- package/package.json +2 -12
- package/src/commands/flow/execute.ts +470 -0
- package/src/commands/flow/index.ts +11 -0
- package/src/commands/flow/prompt.ts +35 -0
- package/src/commands/flow/setup.ts +312 -0
- package/src/commands/flow/targets.ts +18 -0
- package/src/commands/flow/types.ts +47 -0
- package/src/commands/flow-command.ts +18 -967
- package/src/commands/flow-orchestrator.ts +14 -5
- package/src/commands/hook-command.ts +1 -1
- package/src/commands/init-core.ts +12 -3
- package/src/commands/run-command.ts +1 -1
- package/src/config/rules.ts +1 -1
- package/src/core/error-handling.ts +1 -1
- package/src/core/loop-controller.ts +1 -1
- package/src/core/state-detector.ts +1 -1
- package/src/core/target-manager.ts +1 -1
- package/src/index.ts +1 -1
- package/src/shared/files/index.ts +1 -1
- package/src/shared/processing/index.ts +1 -1
- package/src/targets/claude-code.ts +3 -3
- package/src/targets/opencode.ts +3 -3
- package/src/utils/agent-enhancer.ts +2 -2
- package/src/utils/{mcp-config.ts → config/mcp-config.ts} +4 -4
- package/src/utils/{paths.ts → config/paths.ts} +1 -1
- package/src/utils/{settings.ts → config/settings.ts} +1 -1
- package/src/utils/{target-config.ts → config/target-config.ts} +5 -5
- package/src/utils/{target-utils.ts → config/target-utils.ts} +3 -3
- package/src/utils/display/banner.ts +25 -0
- package/src/utils/display/status.ts +55 -0
- package/src/utils/{file-operations.ts → files/file-operations.ts} +2 -2
- package/src/utils/files/jsonc.ts +36 -0
- package/src/utils/{sync-utils.ts → files/sync-utils.ts} +3 -3
- package/src/utils/index.ts +42 -61
- package/src/utils/version.ts +47 -0
- package/src/components/benchmark-monitor.tsx +0 -331
- package/src/components/reindex-progress.tsx +0 -261
- package/src/composables/functional/index.ts +0 -14
- package/src/composables/functional/useEnvironment.ts +0 -171
- package/src/composables/functional/useFileSystem.ts +0 -139
- package/src/composables/index.ts +0 -4
- package/src/composables/useEnv.ts +0 -13
- package/src/composables/useRuntimeConfig.ts +0 -27
- package/src/core/ai-sdk.ts +0 -603
- package/src/core/app-factory.ts +0 -381
- package/src/core/builtin-agents.ts +0 -9
- package/src/core/command-system.ts +0 -550
- package/src/core/config-system.ts +0 -550
- package/src/core/connection-pool.ts +0 -390
- package/src/core/di-container.ts +0 -155
- package/src/core/headless-display.ts +0 -96
- package/src/core/interfaces/index.ts +0 -22
- package/src/core/interfaces/repository.interface.ts +0 -91
- package/src/core/interfaces/service.interface.ts +0 -133
- package/src/core/interfaces.ts +0 -96
- package/src/core/result.ts +0 -351
- package/src/core/service-config.ts +0 -252
- package/src/core/session-service.ts +0 -121
- package/src/core/storage-factory.ts +0 -115
- package/src/core/stream-handler.ts +0 -288
- package/src/core/type-utils.ts +0 -427
- package/src/core/unified-storage.ts +0 -456
- package/src/core/validation/limit.ts +0 -46
- package/src/core/validation/query.ts +0 -20
- package/src/db/auto-migrate.ts +0 -322
- package/src/db/base-database-client.ts +0 -144
- package/src/db/cache-db.ts +0 -218
- package/src/db/cache-schema.ts +0 -75
- package/src/db/database.ts +0 -70
- package/src/db/index.ts +0 -252
- package/src/db/memory-db.ts +0 -153
- package/src/db/memory-schema.ts +0 -29
- package/src/db/schema.ts +0 -289
- package/src/db/session-repository.ts +0 -733
- package/src/domains/index.ts +0 -6
- package/src/domains/utilities/index.ts +0 -6
- package/src/domains/utilities/time/index.ts +0 -5
- package/src/domains/utilities/time/tools.ts +0 -291
- package/src/services/agent-service.ts +0 -273
- package/src/services/evaluation-service.ts +0 -271
- package/src/services/functional/evaluation-logic.ts +0 -296
- package/src/services/functional/file-processor.ts +0 -273
- package/src/services/functional/index.ts +0 -12
- package/src/services/memory.service.ts +0 -476
- package/src/types/api/batch.ts +0 -108
- package/src/types/api/errors.ts +0 -118
- package/src/types/api/index.ts +0 -55
- package/src/types/api/requests.ts +0 -76
- package/src/types/api/responses.ts +0 -180
- package/src/types/api/websockets.ts +0 -85
- package/src/types/benchmark.ts +0 -49
- package/src/types/database.types.ts +0 -510
- package/src/types/memory-types.ts +0 -63
- package/src/utils/advanced-tokenizer.ts +0 -191
- package/src/utils/ai-model-fetcher.ts +0 -19
- package/src/utils/async-file-operations.ts +0 -516
- package/src/utils/audio-player.ts +0 -345
- package/src/utils/codebase-helpers.ts +0 -211
- package/src/utils/console-ui.ts +0 -79
- package/src/utils/database-errors.ts +0 -140
- package/src/utils/debug-logger.ts +0 -49
- package/src/utils/file-scanner.ts +0 -259
- package/src/utils/help.ts +0 -20
- package/src/utils/immutable-cache.ts +0 -106
- package/src/utils/jsonc.ts +0 -158
- package/src/utils/memory-tui.ts +0 -414
- package/src/utils/models-dev.ts +0 -91
- package/src/utils/parallel-operations.ts +0 -487
- package/src/utils/process-manager.ts +0 -155
- package/src/utils/prompts.ts +0 -120
- package/src/utils/search-tool-builder.ts +0 -214
- package/src/utils/session-manager.ts +0 -168
- package/src/utils/session-title.ts +0 -87
- package/src/utils/simplified-errors.ts +0 -410
- package/src/utils/template-engine.ts +0 -94
- package/src/utils/test-audio.ts +0 -71
- package/src/utils/todo-context.ts +0 -46
- package/src/utils/token-counter.ts +0 -288
- /package/src/utils/{cli-output.ts → display/cli-output.ts} +0 -0
- /package/src/utils/{logger.ts → display/logger.ts} +0 -0
- /package/src/utils/{notifications.ts → display/notifications.ts} +0 -0
- /package/src/utils/{secret-utils.ts → security/secret-utils.ts} +0 -0
- /package/src/utils/{security.ts → security/security.ts} +0 -0
|
@@ -1,550 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Command System - 統一命令系統
|
|
3
|
-
* Feature-first, composable, functional command architecture
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { CommandOptions } from '../types/cli.types.js';
|
|
7
|
-
import { Result, err, ok } from './result.js';
|
|
8
|
-
import { withErrorHandling } from './error-handling.js';
|
|
9
|
-
import { logger } from '../utils/logger.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Command definition interface
|
|
13
|
-
*/
|
|
14
|
-
export interface Command {
|
|
15
|
-
name: string;
|
|
16
|
-
description: string;
|
|
17
|
-
handler: CommandHandler;
|
|
18
|
-
options?: CommandOption[];
|
|
19
|
-
middleware?: CommandMiddleware[];
|
|
20
|
-
examples?: string[];
|
|
21
|
-
aliases?: string[];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Command option definition
|
|
26
|
-
*/
|
|
27
|
-
export interface CommandOption {
|
|
28
|
-
name: string;
|
|
29
|
-
description: string;
|
|
30
|
-
type: 'string' | 'number' | 'boolean' | 'array';
|
|
31
|
-
required?: boolean;
|
|
32
|
-
default?: unknown;
|
|
33
|
-
choices?: unknown[];
|
|
34
|
-
validate?: (value: unknown) => boolean | string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Command middleware interface
|
|
39
|
-
*/
|
|
40
|
-
export interface CommandMiddleware {
|
|
41
|
-
name: string;
|
|
42
|
-
before?: (context: CommandContext) => Promise<void>;
|
|
43
|
-
after?: (context: CommandContext, result: CommandResult) => Promise<void>;
|
|
44
|
-
onError?: (context: CommandContext, error: Error) => Promise<void>;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Command context
|
|
49
|
-
*/
|
|
50
|
-
export interface CommandContext {
|
|
51
|
-
command: Command;
|
|
52
|
-
options: CommandOptions;
|
|
53
|
-
args: string[];
|
|
54
|
-
startTime: number;
|
|
55
|
-
metadata?: Record<string, unknown>;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Command result
|
|
60
|
-
*/
|
|
61
|
-
export type CommandResult = Result<unknown, Error>;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Command handler function
|
|
65
|
-
*/
|
|
66
|
-
export type CommandHandler = (context: CommandContext) => Promise<CommandResult>;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Command registry
|
|
70
|
-
*/
|
|
71
|
-
export class CommandRegistry {
|
|
72
|
-
private commands = new Map<string, Command>();
|
|
73
|
-
private aliases = new Map<string, string>();
|
|
74
|
-
private globalMiddleware: CommandMiddleware[] = [];
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Register a command
|
|
78
|
-
*/
|
|
79
|
-
register(command: Command): void {
|
|
80
|
-
// Validate command
|
|
81
|
-
if (!command.name || !command.description || !command.handler) {
|
|
82
|
-
throw new Error('Command must have name, description, and handler');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Check for conflicts
|
|
86
|
-
if (this.commands.has(command.name)) {
|
|
87
|
-
throw new Error(`Command already registered: ${command.name}`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Register command
|
|
91
|
-
this.commands.set(command.name, command);
|
|
92
|
-
|
|
93
|
-
// Register aliases
|
|
94
|
-
if (command.aliases) {
|
|
95
|
-
for (const alias of command.aliases) {
|
|
96
|
-
if (this.commands.has(alias) || this.aliases.has(alias)) {
|
|
97
|
-
throw new Error(`Alias already registered: ${alias}`);
|
|
98
|
-
}
|
|
99
|
-
this.aliases.set(alias, command.name);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
logger.debug('Command registered', {
|
|
104
|
-
name: command.name,
|
|
105
|
-
aliases: command.aliases,
|
|
106
|
-
options: command.options?.length || 0,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Unregister a command
|
|
112
|
-
*/
|
|
113
|
-
unregister(name: string): boolean {
|
|
114
|
-
const command = this.commands.get(name);
|
|
115
|
-
if (!command) return false;
|
|
116
|
-
|
|
117
|
-
// Remove command
|
|
118
|
-
this.commands.delete(name);
|
|
119
|
-
|
|
120
|
-
// Remove aliases
|
|
121
|
-
if (command.aliases) {
|
|
122
|
-
for (const alias of command.aliases) {
|
|
123
|
-
this.aliases.delete(alias);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
logger.debug('Command unregistered', { name });
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Get command by name or alias
|
|
133
|
-
*/
|
|
134
|
-
get(nameOrAlias: string): Command | null {
|
|
135
|
-
// Try direct name
|
|
136
|
-
const command = this.commands.get(nameOrAlias);
|
|
137
|
-
if (command) return command;
|
|
138
|
-
|
|
139
|
-
// Try alias
|
|
140
|
-
const commandName = this.aliases.get(nameOrAlias);
|
|
141
|
-
if (commandName) {
|
|
142
|
-
return this.commands.get(commandName) || null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Check if command exists
|
|
150
|
-
*/
|
|
151
|
-
has(nameOrAlias: string): boolean {
|
|
152
|
-
return this.commands.has(nameOrAlias) || this.aliases.has(nameOrAlias);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* List all commands
|
|
157
|
-
*/
|
|
158
|
-
list(): Command[] {
|
|
159
|
-
return Array.from(this.commands.values());
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Get command names
|
|
164
|
-
*/
|
|
165
|
-
names(): string[] {
|
|
166
|
-
return Array.from(this.commands.keys());
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Add global middleware
|
|
171
|
-
*/
|
|
172
|
-
addMiddleware(middleware: CommandMiddleware): void {
|
|
173
|
-
this.globalMiddleware.push(middleware);
|
|
174
|
-
logger.debug('Global middleware added', { name: middleware.name });
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Remove global middleware
|
|
179
|
-
*/
|
|
180
|
-
removeMiddleware(name: string): boolean {
|
|
181
|
-
const index = this.globalMiddleware.findIndex(m => m.name === name);
|
|
182
|
-
if (index > -1) {
|
|
183
|
-
this.globalMiddleware.splice(index, 1);
|
|
184
|
-
logger.debug('Global middleware removed', { name });
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Execute a command
|
|
192
|
-
*/
|
|
193
|
-
async execute(
|
|
194
|
-
nameOrAlias: string,
|
|
195
|
-
options: CommandOptions = {},
|
|
196
|
-
args: string[] = []
|
|
197
|
-
): Promise<CommandResult> {
|
|
198
|
-
const command = this.get(nameOrAlias);
|
|
199
|
-
if (!command) {
|
|
200
|
-
return err(new Error(`Command not found: ${nameOrAlias}`));
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const context: CommandContext = {
|
|
204
|
-
command,
|
|
205
|
-
options,
|
|
206
|
-
args,
|
|
207
|
-
startTime: Date.now(),
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
logger.info('Executing command', {
|
|
211
|
-
name: command.name,
|
|
212
|
-
args,
|
|
213
|
-
options,
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
try {
|
|
217
|
-
// Validate options
|
|
218
|
-
const validationResult = this.validateOptions(command, options);
|
|
219
|
-
if (!validationResult.success) {
|
|
220
|
-
return validationResult;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Apply global middleware (before)
|
|
224
|
-
for (const middleware of this.globalMiddleware) {
|
|
225
|
-
if (middleware.before) {
|
|
226
|
-
await middleware.before(context);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Apply command middleware (before)
|
|
231
|
-
if (command.middleware) {
|
|
232
|
-
for (const middleware of command.middleware) {
|
|
233
|
-
if (middleware.before) {
|
|
234
|
-
await middleware.before(context);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Execute command
|
|
240
|
-
const result = await command.handler(context);
|
|
241
|
-
|
|
242
|
-
// Apply command middleware (after)
|
|
243
|
-
if (command.middleware) {
|
|
244
|
-
for (const middleware of command.middleware) {
|
|
245
|
-
if (middleware.after) {
|
|
246
|
-
await middleware.after(context, result);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Apply global middleware (after)
|
|
252
|
-
for (const middleware of this.globalMiddleware) {
|
|
253
|
-
if (middleware.after) {
|
|
254
|
-
await middleware.after(context, result);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const duration = Date.now() - context.startTime;
|
|
259
|
-
logger.info('Command completed', {
|
|
260
|
-
name: command.name,
|
|
261
|
-
success: result.success,
|
|
262
|
-
duration,
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
return result;
|
|
266
|
-
|
|
267
|
-
} catch (error) {
|
|
268
|
-
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
269
|
-
|
|
270
|
-
// Apply command middleware (onError)
|
|
271
|
-
if (command.middleware) {
|
|
272
|
-
for (const middleware of command.middleware) {
|
|
273
|
-
if (middleware.onError) {
|
|
274
|
-
await middleware.onError(context, errorObj);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Apply global middleware (onError)
|
|
280
|
-
for (const middleware of this.globalMiddleware) {
|
|
281
|
-
if (middleware.onError) {
|
|
282
|
-
await middleware.onError(context, errorObj);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const duration = Date.now() - context.startTime;
|
|
287
|
-
logger.error('Command failed', {
|
|
288
|
-
name: command.name,
|
|
289
|
-
error: errorObj.message,
|
|
290
|
-
duration,
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
return err(errorObj);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Validate command options
|
|
299
|
-
*/
|
|
300
|
-
private validateOptions(command: Command, options: CommandOptions): CommandResult {
|
|
301
|
-
if (!command.options) return ok(undefined);
|
|
302
|
-
|
|
303
|
-
for (const option of command.options) {
|
|
304
|
-
const value = options[option.name];
|
|
305
|
-
|
|
306
|
-
// Check required options
|
|
307
|
-
if (option.required && (value === undefined || value === null)) {
|
|
308
|
-
return err(new Error(`Required option missing: ${option.name}`));
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Use default value
|
|
312
|
-
if (value === undefined && option.default !== undefined) {
|
|
313
|
-
options[option.name] = option.default;
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// Skip validation if value is not provided
|
|
318
|
-
if (value === undefined || value === null) {
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Type validation
|
|
323
|
-
if (option.type === 'number' && typeof value !== 'number') {
|
|
324
|
-
const num = Number(value);
|
|
325
|
-
if (isNaN(num)) {
|
|
326
|
-
return err(new Error(`Invalid number for option ${option.name}: ${value}`));
|
|
327
|
-
}
|
|
328
|
-
options[option.name] = num;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (option.type === 'boolean' && typeof value !== 'boolean') {
|
|
332
|
-
if (typeof value === 'string') {
|
|
333
|
-
options[option.name] = value.toLowerCase() === 'true';
|
|
334
|
-
} else {
|
|
335
|
-
options[option.name] = Boolean(value);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (option.type === 'array' && !Array.isArray(value)) {
|
|
340
|
-
if (typeof value === 'string') {
|
|
341
|
-
options[option.name] = value.split(',').map(s => s.trim());
|
|
342
|
-
} else {
|
|
343
|
-
return err(new Error(`Invalid array for option ${option.name}: ${value}`));
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Choice validation
|
|
348
|
-
if (option.choices && !option.choices.includes(options[option.name])) {
|
|
349
|
-
return err(new Error(
|
|
350
|
-
`Invalid choice for option ${option.name}: ${value}. Must be one of: ${option.choices.join(', ')}`
|
|
351
|
-
));
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Custom validation
|
|
355
|
-
if (option.validate) {
|
|
356
|
-
const validation = option.validate(options[option.name]);
|
|
357
|
-
if (validation !== true) {
|
|
358
|
-
return err(new Error(
|
|
359
|
-
typeof validation === 'string' ? validation : `Invalid value for option ${option.name}: ${value}`
|
|
360
|
-
));
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
return ok(undefined);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Command builder
|
|
371
|
-
*/
|
|
372
|
-
export class CommandBuilder {
|
|
373
|
-
private command: Partial<Command> = {};
|
|
374
|
-
|
|
375
|
-
name(name: string): CommandBuilder {
|
|
376
|
-
this.command.name = name;
|
|
377
|
-
return this;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
description(description: string): CommandBuilder {
|
|
381
|
-
this.command.description = description;
|
|
382
|
-
return this;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
handler(handler: CommandHandler): CommandBuilder {
|
|
386
|
-
this.command.handler = handler;
|
|
387
|
-
return this;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
option(option: CommandOption): CommandBuilder {
|
|
391
|
-
if (!this.command.options) {
|
|
392
|
-
this.command.options = [];
|
|
393
|
-
}
|
|
394
|
-
this.command.options.push(option);
|
|
395
|
-
return this;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
middleware(middleware: CommandMiddleware): CommandBuilder {
|
|
399
|
-
if (!this.command.middleware) {
|
|
400
|
-
this.command.middleware = [];
|
|
401
|
-
}
|
|
402
|
-
this.command.middleware.push(middleware);
|
|
403
|
-
return this;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
examples(examples: string[]): CommandBuilder {
|
|
407
|
-
this.command.examples = examples;
|
|
408
|
-
return this;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
aliases(aliases: string[]): CommandBuilder {
|
|
412
|
-
this.command.aliases = aliases;
|
|
413
|
-
return this;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
build(): Command {
|
|
417
|
-
if (!this.command.name || !this.command.description || !this.command.handler) {
|
|
418
|
-
throw new Error('Command must have name, description, and handler');
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
return this.command as Command;
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* Utility functions
|
|
427
|
-
*/
|
|
428
|
-
export const CommandUtils = {
|
|
429
|
-
/**
|
|
430
|
-
* Create a new command builder
|
|
431
|
-
*/
|
|
432
|
-
builder(): CommandBuilder {
|
|
433
|
-
return new CommandBuilder();
|
|
434
|
-
},
|
|
435
|
-
|
|
436
|
-
/**
|
|
437
|
-
* Create a simple command
|
|
438
|
-
*/
|
|
439
|
-
create(
|
|
440
|
-
name: string,
|
|
441
|
-
description: string,
|
|
442
|
-
handler: (options: CommandOptions) => Promise<unknown>
|
|
443
|
-
): Command {
|
|
444
|
-
return CommandUtils.builder()
|
|
445
|
-
.name(name)
|
|
446
|
-
.description(description)
|
|
447
|
-
.handler(async (context): Promise<CommandResult> => {
|
|
448
|
-
return withErrorHandling(() => handler(context.options));
|
|
449
|
-
})
|
|
450
|
-
.build();
|
|
451
|
-
},
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Create a command with options
|
|
455
|
-
*/
|
|
456
|
-
createWithOptions(
|
|
457
|
-
name: string,
|
|
458
|
-
description: string,
|
|
459
|
-
options: CommandOption[],
|
|
460
|
-
handler: (options: CommandOptions) => Promise<unknown>
|
|
461
|
-
): Command {
|
|
462
|
-
return CommandUtils.builder()
|
|
463
|
-
.name(name)
|
|
464
|
-
.description(description)
|
|
465
|
-
.options(...options)
|
|
466
|
-
.handler(async (context): Promise<CommandResult> => {
|
|
467
|
-
return withErrorHandling(() => handler(context.options));
|
|
468
|
-
})
|
|
469
|
-
.build();
|
|
470
|
-
},
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Create option definitions
|
|
474
|
-
*/
|
|
475
|
-
option: {
|
|
476
|
-
string: (name: string, description: string, required = false): CommandOption => ({
|
|
477
|
-
name,
|
|
478
|
-
description,
|
|
479
|
-
type: 'string',
|
|
480
|
-
required,
|
|
481
|
-
}),
|
|
482
|
-
|
|
483
|
-
number: (name: string, description: string, required = false): CommandOption => ({
|
|
484
|
-
name,
|
|
485
|
-
description,
|
|
486
|
-
type: 'number',
|
|
487
|
-
required,
|
|
488
|
-
}),
|
|
489
|
-
|
|
490
|
-
boolean: (name: string, description: string): CommandOption => ({
|
|
491
|
-
name,
|
|
492
|
-
description,
|
|
493
|
-
type: 'boolean',
|
|
494
|
-
}),
|
|
495
|
-
|
|
496
|
-
array: (name: string, description: string): CommandOption => ({
|
|
497
|
-
name,
|
|
498
|
-
description,
|
|
499
|
-
type: 'array',
|
|
500
|
-
}),
|
|
501
|
-
|
|
502
|
-
choice: (name: string, description: string, choices: unknown[], required = false): CommandOption => ({
|
|
503
|
-
name,
|
|
504
|
-
description,
|
|
505
|
-
type: 'string',
|
|
506
|
-
required,
|
|
507
|
-
choices,
|
|
508
|
-
}),
|
|
509
|
-
} as const,
|
|
510
|
-
|
|
511
|
-
/**
|
|
512
|
-
* Common middleware
|
|
513
|
-
*/
|
|
514
|
-
middleware: {
|
|
515
|
-
logging: (): CommandMiddleware => ({
|
|
516
|
-
name: 'logging',
|
|
517
|
-
before: async (context): Promise<void> => {
|
|
518
|
-
logger.debug('Command started', {
|
|
519
|
-
name: context.command.name,
|
|
520
|
-
options: context.options,
|
|
521
|
-
});
|
|
522
|
-
},
|
|
523
|
-
after: async (context, result): Promise<void> => {
|
|
524
|
-
logger.debug('Command completed', {
|
|
525
|
-
name: context.command.name,
|
|
526
|
-
success: result.success,
|
|
527
|
-
duration: Date.now() - context.startTime,
|
|
528
|
-
});
|
|
529
|
-
},
|
|
530
|
-
onError: async (context, error): Promise<void> => {
|
|
531
|
-
logger.error('Command failed', {
|
|
532
|
-
name: context.command.name,
|
|
533
|
-
error: error.message,
|
|
534
|
-
duration: Date.now() - context.startTime,
|
|
535
|
-
});
|
|
536
|
-
},
|
|
537
|
-
}),
|
|
538
|
-
|
|
539
|
-
timing: (): CommandMiddleware => ({
|
|
540
|
-
name: 'timing',
|
|
541
|
-
before: async (context): Promise<void> => {
|
|
542
|
-
context.metadata = { ...context.metadata, startTime: Date.now() };
|
|
543
|
-
},
|
|
544
|
-
after: async (context, result): Promise<void> => {
|
|
545
|
-
const duration = Date.now() - (context.metadata?.startTime || context.startTime);
|
|
546
|
-
logger.info(`Command "${context.command.name}" executed in ${duration}ms`);
|
|
547
|
-
},
|
|
548
|
-
}),
|
|
549
|
-
} as const,
|
|
550
|
-
} as const;
|