doRun method
Implementation
@override
Future<int> doRun() async {
printInfo('Checking custom commands configuration...');
printInfo('');
// Find config file
final configPath = _findConfigFile();
if (configPath == null) {
printInfo('Custom commands config file not found.');
printInfo('');
printInfo('Expected location: alex_custom_commands.yaml');
printInfo('Searched in current directory and parent directories (up to 10 levels)');
printInfo('');
printInfo('To create a config file, use:');
printInfo(' alex custom add');
return 0;
}
printInfo('Found config file: $configPath');
printInfo('');
// Try to load and parse directly to catch errors
try {
// Read and parse YAML directly
final file = File(configPath);
if (!file.existsSync()) {
printError('Config file not found: $configPath');
return 1;
}
final yamlString = file.readAsStringSync();
final yamlData = loadYaml(yamlString);
if (yamlData == null) {
printInfo('Config file is empty.');
printInfo('');
printInfo('To add a command, use:');
printInfo(' alex custom add');
return 0;
}
if (yamlData is! YamlMap) {
printError('Invalid config file format: expected YAML map, got ${yamlData.runtimeType}');
return 1;
}
final commandsList = yamlData['custom_commands'] as YamlList?;
if (commandsList == null || commandsList.isEmpty) {
printInfo('Config file exists but contains no commands.');
printInfo('');
printInfo('To add a command, use:');
printInfo(' alex custom add');
return 0;
}
// Parse each command to validate
final commands = <CustomCommandDefinition>[];
for (var i = 0; i < commandsList.length; i++) {
final cmdData = commandsList[i] as YamlMap;
final cmd = CustomCommandDefinition.fromYaml(cmdData);
commands.add(cmd);
}
// All commands parsed successfully
// Show summary
printInfo('✓ Configuration is valid!');
printInfo('');
printInfo('Found ${commands.length} custom command(s):');
printInfo('');
for (final cmd in commands) {
printInfo(' ${cmd.name}');
if (cmd.description.isNotEmpty) {
printInfo(' Description: ${cmd.description}');
}
if (cmd.aliases.isNotEmpty) {
printInfo(' Aliases: ${cmd.aliases.join(", ")}');
}
if (cmd.arguments.isNotEmpty) {
printInfo(' Arguments: ${cmd.arguments.length}');
for (final arg in cmd.arguments) {
final required = arg.required ? ' (required)' : '';
final defaultVal = arg.defaultValue != null ? ' [default: ${arg.defaultValue}]' : '';
printInfo(' --${arg.name}$required$defaultVal');
}
}
printInfo(' Actions: ${cmd.actions.length}');
for (var i = 0; i < cmd.actions.length; i++) {
final action = cmd.actions[i];
printInfo(' ${i + 1}. ${action.type.value}');
}
printInfo('');
}
printInfo('You can run these commands with:');
for (final cmd in commands) {
printInfo(' alex ${cmd.name}');
}
return 0;
} catch (e, stackTrace) {
printError('Failed to load custom commands config!');
printInfo('');
printError('Error: $e');
printInfo('');
// Try to extract line information from error message
final errorStr = e.toString();
// Try multiple patterns to extract line number
var lineMatch = RegExp(r'line (\d+):(\d+)').firstMatch(errorStr);
lineMatch ??= RegExp(r'line (\d+)').firstMatch(errorStr);
if (lineMatch != null) {
final lineNum = lineMatch.group(1);
final column = lineMatch.groupCount > 1 ? lineMatch.group(2) : null;
var locationStr = '$configPath:$lineNum';
if (column != null) {
locationStr += ':$column';
}
printInfo('Location: $locationStr');
printInfo('');
// Try to show the problematic line
try {
final file = File(configPath);
final lines = file.readAsLinesSync();
final lineIndex = int.parse(lineNum!) - 1;
if (lineIndex >= 0 && lineIndex < lines.length) {
printInfo('Problematic line:');
// Show context: 2 lines before, the error line, 2 lines after
final start = (lineIndex - 2).clamp(0, lines.length);
final end = (lineIndex + 3).clamp(0, lines.length);
for (var i = start; i < end; i++) {
final prefix = i == lineIndex ? '>>>' : ' ';
printInfo('$prefix ${i + 1}: ${lines[i]}');
}
printInfo('');
}
} catch (_) {
// Ignore errors while trying to show context
}
} else {
// If no line number found, try to extract command/action info
final commandMatch = RegExp('command "([^"]+)"').firstMatch(errorStr);
final actionMatch = RegExp(r'action (\d+)').firstMatch(errorStr);
if (commandMatch != null || actionMatch != null) {
var hint = 'Hint: ';
if (commandMatch != null) {
hint += 'Check command "${commandMatch.group(1)}"';
}
if (actionMatch != null) {
if (commandMatch != null) hint += ', ';
hint += 'action #${actionMatch.group(1)}';
}
printInfo(hint);
printInfo('');
}
}
printInfo('Stack trace:');
printInfo(stackTrace.toString());
printInfo('');
printInfo('Common issues:');
printInfo(' • YAML syntax errors (check indentation, quotes)');
printInfo(' • Missing required fields (name, actions)');
printInfo(' • Invalid action types');
printInfo(' • Unescaped special characters in strings');
printInfo(' • Type mismatches (e.g., number where string expected)');
printInfo('');
printInfo('Try editing the config file:');
printInfo(' alex custom edit');
return 1;
}
}