run method

  1. @override
Future<void> run()
override

Runs this command.

The return value is wrapped in a Future if necessary and returned by CommandRunner.runCommand.

Implementation

@override
Future<void> run() async {
  final args = argResults!;

  final providerArg = args['provider'] as String?;
  final provider = providerArg == null
      ? null
      : ai.AiProviderKind.tryParse(providerArg);
  if (providerArg != null && provider == null) {
    throw CliError('invalid --provider: $providerArg');
  }

  final modeArg = args['mode'] as String?;
  final mode = modeArg == null ? null : ai.AgentMode.tryParse(modeArg);
  if (modeArg != null && mode == null) {
    throw CliError('invalid --mode: $modeArg');
  }

  int? maxSteps;
  final maxStepsArg = args['max-steps'] as String?;
  if (maxStepsArg != null) {
    maxSteps = int.tryParse(maxStepsArg.trim());
    if (maxSteps == null || maxSteps <= 0) {
      throw CliError(
        'invalid --max-steps: $maxStepsArg (expected a positive integer)',
      );
    }
  }

  var key = args['key'] as String?;
  if (key == '-') {
    key = _readSecret('API key: ');
    if (key.isEmpty) throw CliError('no key entered');
  }

  // null = not provided; '' = clear back to the default; else the value.
  String? clearable(String name) {
    final raw = (args[name] as String?)?.trim();
    if (raw == null) return null;
    final v = raw.toLowerCase();
    return (raw.isEmpty || v == 'off' || v == 'none' || v == 'default')
        ? ''
        : raw;
  }

  final model = clearable('model');
  final plannerModel = clearable('planner-model');
  final executorModel = clearable('executor-model');
  final explainerModel = clearable('explainer-model');
  final baseUrl = clearable('base-url');
  final language = clearable('language');

  bool blank(String? s) => s == null || s.isEmpty;

  if (provider == null &&
      model == null &&
      plannerModel == null &&
      executorModel == null &&
      explainerModel == null &&
      blank(key) &&
      mode == null &&
      language == null &&
      baseUrl == null &&
      maxSteps == null) {
    throw CliError(
      'nothing to set — pass at least one of --provider/--model/'
      '--planner-model/--executor-model/--explainer-model/--key/--mode/'
      '--language/--base-url/--max-steps. Pass "default" to clear a value. '
      'See: omnyserver ai config --help',
    );
  }

  final path = omnyServerAiConfigPath(args['path'] as String?);
  ai.AiConfigIo.write(
    provider: provider,
    model: model,
    plannerModel: plannerModel,
    executorModel: executorModel,
    explainerModel: explainerModel,
    apiKey: blank(key) ? null : key,
    mode: mode,
    language: language,
    baseUrl: baseUrl,
    maxSteps: maxSteps,
    path: path,
  );

  void report(String label, String? value) {
    if (value == null) return;
    stdout.writeln(
      '  $label: ${value.isEmpty ? '(cleared — uses default)' : value}',
    );
  }

  stdout.writeln('Wrote $path');
  if (provider != null) stdout.writeln('  provider: ${provider.wireName}');
  report('model', model);
  report('plannerModel', plannerModel);
  report('executorModel', executorModel);
  report('explainerModel', explainerModel);
  if (!blank(key)) stdout.writeln('  key: ${_maskKey(key!)}');
  if (mode != null) stdout.writeln('  mode: ${mode.wireName}');
  report('language', language);
  report('baseUrl', baseUrl);
  if (maxSteps != null) stdout.writeln('  maxSteps: $maxSteps');
  stdout.writeln('Start the Hub with --shell to serve it to web clients.');
}